123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- // Pseudo-code
- // TODO: add link to the ports of the boundary
- // TODO: update MM to reflect the new changes to the structure (everything is an Activity with a Next link, and everything has a duration)
- // init_place = new_place()
- // branches = [(init_place, [(0, topmost_model)]]
- // while branches:
- // prev, options = branches.pop()
- // nr = find_min_time(options)
- // time, cur = options.pop(nr)
- //
- // if type(cur) == "Event":
- // // Just add the current node and augment the duration for the next one
- // prev_model = new_element(cur)
- // if (cur.next != None):
- // options.append((time + cur.next.duration, cur.next))
- // branches.append((prev_model, options))
- // else:
- // // recurse upwards until we can follow a link
- // elem = containee(cur)
- // while elem.next_activity == None and containee(elem) != None:
- // elem = containee(elem)
- // if containee(elem) == None:
- // // finished this branch
- // continue!
- // else:
- // cur = elem.next_activity
- // options.append((time + elem.duration, cur.next))
- // branches.append((prev_model, options))
- // elif type(cur) == "Sequence":
- // options.append((time + first.duration, cur.first))
- // branches.append((prev_model, options))
- // elif type(cur) == "Parallel":
- // // Add all starts of the parallel as potential next one
- // // But keep the previous source, as we only expanded
- // for next in cur.start_nodes:
- // options.append((time + next.duration, next))
- // branches.append((prev, options))
- // elif type(cur) == "Alternative":
- // // Expand into new branches, but keep the options as is (add the individual options though)
- // for next in cur.start_nodes:
- // options.append((time + next.duration, next))
- // // Don't rewrite the source, as we effectively want to branch out from this node
- // branches.append(prev, options)
- include "primitives.alh"
- include "modelling.alh"
- include "object_operations.alh"
- Element function env_to_EPN(params : Element, output_mms : Element):
- Element result
- Element out_model
- Element in_model
- String init_place
- String current_activity
- Element branches
- Element options
- Element branch
- String previous_place
- Integer i
- Integer cnt
- Integer min_time
- Integer index_min_time
- Element option
- Integer current_time
- String new_transition
- String new_model
- Element containers
- Element new_options
- Element inner_elements
- Element entry
- String type
- String prev_model
- String element
- result = create_node()
- out_model = instantiate_model(output_mms["Encapsulated_PetriNet"])
- in_model = params["environment"]
- // Create the initial place
- init_place = instantiate_node(out_model, "Place", "")
- instantiate_attribute(out_model, init_place, "tokens", 1)
- // Set current element to the TopActivity, which will be expanded
- current_activity = set_pop(allInstances(in_model, "TopActivity"))
- // Initialize the data structure with the current element and initial place
- branches = create_node()
- options = create_node()
- list_append(options, create_tuple(0, current_activity))
- set_add(branches, create_tuple(init_place, options))
- // Keep going as long as there are branches to resolve
- while (read_nr_out(branches) > 0):
- // Still a branch, so pick one at random
- branch = set_pop(branches)
- previous_place = branch[0]
- options = branch[1]
- // Find the index of the option with the lowest time (first element of tuple)
- i = 0
- cnt = list_len(options)
- min_time = 9999999
- index_min_time = -1
- while (i < cnt):
- entry = list_read(options, i)
- if (integer_lt(entry[0], min_time)):
- min_time = entry[0]
- index_min_time = i
- i = i + 1
- // Pop the minimal option
- option = list_pop(options, index_min_time)
- current_time = option[0]
- current_activity = option[1]
- // Figure out the type
- type = read_type(in_model, current_activity)
- // Now branch based on the type
- if (type == "Event"):
- // Process an event: update the PN and go to the next activity
- new_transition = instantiate_node(out_model, "Transition", "")
- new_model = instantiate_node(out_model, "Place", "")
- instantiate_link(out_model, "P2T", "", prev_model, new_transition)
- instantiate_link(out_model, "T2P", "", new_transition, new_model)
- // Check if there is a Next to this Event, meaning another event
- if (read_nr_out(allOutgoingAssociationInstances(in_model, current_activity, "Next")) > 0):
- // We have a Next, so just push that next event on the options
- current_activity = set_pop(allAssociationDestinations(in_model, current_activity, "Next"))
- list_append(options, create_tuple(integer_addition(current_time, read_attribute(in_model, current_activity, "duration")), current_activity))
- set_add(branches, create_tuple(new_model, options))
- else:
- // No Next in this node, so we recurse up until one of these elements does have a next (or we reach the top)
- while (read_nr_out(allOutgoingAssociationInstances(in_model, current_activity, "Next")) == 0):
- // Recurse up
- containers = allAssociationOrigins(in_model, current_activity, "Contains")
- if (read_nr_out(containers) == 1):
- current_activity = set_pop(containers)
- elif (read_nr_out(containers) == 0):
- // No more containers, so at top element
- break!
- if (read_nr_out(containers) == 0):
- // Nothing left to do, so clear up this branch, but continue with the others
- continue!
- else:
- // Found a node with a Next link: we follow it
- current_activity = set_pop(allAssociationDestinations(in_model, current_activity, "Next"))
- list_append(options, create_tuple(integer_addition(current_time, read_attribute(in_model, current_activity, "duration")), current_activity))
- set_add(branches, create_tuple(new_model, options))
- elif (type == "Sequence"):
- // Process a sequence: just move the current option to the enclosing activity
- inner_elements = allAssociationDestinations(in_model, current_activity, "Contains")
- while (read_nr_out(inner_elements) > 0):
- element = set_pop(inner_elements)
- if (read_nr_out(allIncomingAssociationInstances(in_model, element, "Next")) == 0):
- current_activity = element
- break!
- // current_activity now contains the inner element to execute
- list_append(options, create_tuple(integer_addition(current_time, read_attribute(in_model, current_activity, "duration")), current_activity))
- // keep the current branch alive, as everything is updated by reference
- set_add(branches, branch)
- elif (type == "Parallel"):
- // Process a parallel: create new options for each containing element
- inner_elements = allAssociationDestinations(in_model, current_activity, "Contains")
- while (read_nr_out(inner_elements) > 0):
- current_activity = set_pop(inner_elements)
- // current_activity now contains the inner element to execute in parallel (an option)
- list_append(options, create_tuple(integer_addition(current_time, read_attribute(in_model, current_activity, "duration")), current_activity))
- // keep the current branch alive, as everything is updated by reference
- set_add(branches, branch)
- elif (type == "Alternative"):
- inner_elements = allAssociationDestinations(in_model, current_activity, "Contains")
- while (read_nr_out(inner_elements) > 0):
- current_activity = set_pop(inner_elements)
- // current_activity now contains the inner element to execute in alternative branches (a branch)
- new_options = set_copy(options)
- list_append(options, create_tuple(integer_addition(current_time, read_attribute(in_model, current_activity, "duration")), current_activity))
- set_add(branches, create_tuple(previous_place, new_options))
- dict_add(result, "Encapsulated_PetriNet", out_model)
- return result!
|