def get_map_exponential_from_aggstatistics(agg_statistics, parameters=None): """ Get transition stochastic distribution map (exponential variable forced) given the log and the Petri net Parameters ----------- agg_statistics Aggregated statistics calculated on the DFG graph and the Petri net parameters Parameters of the algorithm Returns ----------- stochastic_map Map that to each transition associates a random variable """ stochastic_map = {} if parameters is None: parameters = {} del parameters for el in agg_statistics: if type(el) is PetriNet.Transition: rand = RandomVariable() rand.random_variable = Exponential() rand.random_variable.scale = agg_statistics[el]["performance"] stochastic_map[el] = rand return stochastic_map
def test_constant0_variable_2(self): # to avoid static method warnings in tests, # that by construction of the unittest package have to be expressed in such way self.dummy_variable = "dummy_value" const = Constant0() values = [0.0000001, 0.0000001, 0.0000002] loglikeli = const.calculate_loglikelihood(values) if abs(loglikeli) < 10000000: raise Exception("problem in managing constant variables") rand = RandomVariable() rand.calculate_parameters(values) if not rand.get_distribution_type() == "IMMEDIATE": raise Exception("Expected a constant!") loglikeli = rand.calculate_loglikelihood(values) if abs(loglikeli) < 10000000: raise Exception("problem in managing constant variables (2)")
def test_exponential_variable(self): # to avoid static method warnings in tests, # that by construction of the unittest package have to be expressed in such way self.dummy_variable = "dummy_value" loc = 0 scale = 5 tol = 0.2 exp = Exponential(loc=loc, scale=scale) values = exp.get_values(no_values=400) rand = RandomVariable() rand.calculate_parameters(values) if not rand.get_distribution_type() == "EXPONENTIAL": raise Exception("Expected an exponential!") loc_r = rand.random_variable.loc scale_r = rand.random_variable.scale diff_value_loc = abs(loc - loc_r) / (max(abs(loc), abs(loc_r)) + 0.000001) diff_value_scale = abs(scale - scale_r) / (max(abs(scale), abs(scale_r)) + 0.000001) if diff_value_loc > tol or diff_value_scale > tol: raise Exception("parameters found outside tolerance")
def test_normal_variable(self): # to avoid static method warnings in tests, # that by construction of the unittest package have to be expressed in such way self.dummy_variable = "dummy_value" mu = 53 sigma = 4 tol = 0.15 norm = Normal(mu=mu, sigma=sigma) values = norm.get_values(no_values=400) rand = RandomVariable() rand.calculate_parameters(values) if not rand.get_distribution_type() == "NORMAL": raise Exception("Excepted a normal!") mu_r = rand.random_variable.mu sigma_r = rand.random_variable.sigma diff_value_mu = abs(mu - mu_r) / (max(abs(mu), abs(mu_r))) diff_value_sigma = abs(sigma - sigma_r) / (max(abs(sigma), abs(sigma_r))) if diff_value_mu > tol or diff_value_sigma > tol: raise Exception("parameters found outside tolerance")
def test_uniform_variable(self): # to avoid static method warnings in tests, # that by construction of the unittest package have to be expressed in such way self.dummy_variable = "dummy_value" loc = 53 scale = 32 tol = 0.15 unif = Uniform(loc=loc, scale=scale) values = unif.get_values(no_values=400) rand = RandomVariable() rand.calculate_parameters(values) if not rand.get_distribution_type() == "UNIFORM": raise Exception("Expected an uniform!") loc_r = rand.random_variable.loc scale_r = rand.random_variable.scale diff_value_loc = abs(loc - loc_r) / (max(abs(loc), abs(loc_r))) diff_value_scale = abs(scale - scale_r) / (max(abs(scale), abs(scale_r))) if diff_value_loc > tol or diff_value_scale > tol: raise Exception("parameters found outside tolerance")
def import_net(input_file_path, return_stochastic_information=False, parameters=None): """ Import a Petri net from a PNML file Parameters ---------- input_file_path Input file path return_stochastic_information Enables return of stochastic information if found in the PNML parameters Other parameters of the algorithm """ if parameters is None: parameters = {} tree = etree.parse(input_file_path) root = tree.getroot() net = petri.petrinet.PetriNet('imported_' + str(time.time())) marking = petri.petrinet.Marking() fmarking = petri.petrinet.Marking() nett = None page = None finalmarkings = None stochastic_information = {} for child in root: nett = child places_dict = {} trans_dict = {} if nett is not None: for child in nett: if "page" in child.tag: page = child if "finalmarkings" in child.tag: finalmarkings = child if page is None: page = nett if page is not None: for child in page: if "place" in child.tag: place_id = child.get("id") place_name = place_id number = 0 for child2 in child: if "name" in child2.tag: for child3 in child2: if child3.text: place_name = child3.text if "initialMarking" in child2.tag: for child3 in child2: if child3.tag == "text": number = int(child3.text) places_dict[place_id] = petri.petrinet.PetriNet.Place(place_id) net.places.add(places_dict[place_id]) if number > 0: marking[places_dict[place_id]] = number del place_name if page is not None: for child in page: if "transition" in child.tag: trans_name = child.get("id") trans_label = trans_name trans_visible = True random_variable = None for child2 in child: if child2.tag == "name": for child3 in child2: if child3.text: if trans_label == trans_name: trans_label = child3.text if "toolspecific" in child2.tag: tool = child2.get("tool") if "ProM" in tool: activity = child2.get("activity") if "invisible" in activity: trans_visible = False elif "StochasticPetriNet" in tool: distribution_type = None distribution_parameters = None priority = None weight = None for child3 in child2: key = child3.get("key") value = child3.text if key == "distributionType": distribution_type = value elif key == "distributionParameters": distribution_parameters = value elif key == "priority": priority = int(value) elif key == "weight": weight = float(value) if return_stochastic_information: random_variable = RandomVariable() random_variable.read_from_string( distribution_type, distribution_parameters) random_variable.set_priority(priority) random_variable.set_weight(weight) if not trans_visible: trans_label = None #if "INVISIBLE" in trans_label: # trans_label = None trans_dict[trans_name] = petri.petrinet.PetriNet.Transition( trans_name, trans_label) net.transitions.add(trans_dict[trans_name]) if random_variable is not None: stochastic_information[ trans_dict[trans_name]] = random_variable if page is not None: for child in page: if "arc" in child.tag: arc_source = child.get("source") arc_target = child.get("target") arc_weight = 1 for arc_child in child: if "inscription" in arc_child.tag: for text_arcweight in arc_child: if "text" in text_arcweight.tag: arc_weight = int(text_arcweight.text) if arc_source in places_dict and arc_target in trans_dict: petri.utils.add_arc_from_to(places_dict[arc_source], trans_dict[arc_target], net, weight=arc_weight) elif arc_target in places_dict and arc_source in trans_dict: petri.utils.add_arc_from_to(trans_dict[arc_source], places_dict[arc_target], net, weight=arc_weight) if finalmarkings is not None: for child in finalmarkings: for child2 in child: place_id = child2.get("idref") for child3 in child2: if "text" in child3.tag: number = int(child3.text) if number > 0: fmarking[places_dict[place_id]] = number # generate the final marking in the case has not been found if len(fmarking) == 0: fmarking = final_marking.discover_final_marking(net) if return_stochastic_information and len( list(stochastic_information.keys())) > 0: return net, marking, fmarking, stochastic_information return net, marking, fmarking
def get_map_from_log_and_net(log, net, initial_marking, final_marking, force_distribution=None, parameters=None): """ Get transition stochastic distribution map given the log and the Petri net Parameters ----------- log Event log net Petri net initial_marking Initial marking of the Petri net final_marking Final marking of the Petri net force_distribution If provided, distribution to force usage (e.g. EXPONENTIAL) parameters Parameters of the algorithm, including: PARAM_ACTIVITY_KEY -> activity name PARAM_TIMESTAMP_KEY -> timestamp key Returns ----------- stochastic_map Map that to each transition associates a random variable """ stochastic_map = {} if parameters is None: parameters = {} activity_key = parameters[ PARAM_ACTIVITY_KEY] if PARAM_ACTIVITY_KEY in parameters else log_lib.util.xes.DEFAULT_NAME_KEY timestamp_key = parameters[ PARAM_TIMESTAMP_KEY] if PARAM_TIMESTAMP_KEY in parameters else "time:timestamp" parameters_variants = {PARAM_ACTIVITY_KEY: activity_key} variants_idx = variants_module.get_variants_from_log_trace_idx( log, parameters=parameters_variants) variants = variants_module.convert_variants_trace_idx_to_trace_obj( log, variants_idx) parameters_tr = {PARAM_ACTIVITY_KEY: activity_key, "variants": variants} # do the replay aligned_traces = token_replay.apply(log, net, initial_marking, final_marking, parameters=parameters_tr) element_statistics = performance_map.single_element_statistics( log, net, initial_marking, aligned_traces, variants_idx, activity_key=activity_key, timestamp_key=timestamp_key) for el in element_statistics: if type( el ) is PetriNet.Transition and "performance" in element_statistics[el]: values = element_statistics[el]["performance"] rand = RandomVariable() rand.calculate_parameters(values, force_distribution=force_distribution) no_of_times_enabled = element_statistics[el]['no_of_times_enabled'] no_of_times_activated = element_statistics[el][ 'no_of_times_activated'] if no_of_times_enabled > 0: rand.set_weight( float(no_of_times_activated) / float(no_of_times_enabled)) else: rand.set_weight(0.0) stochastic_map[el] = rand return stochastic_map
def import_net(input_file_path, parameters=None): """ Import a Petri net from a PNML file Parameters ---------- input_file_path Input file path parameters Other parameters of the algorithm """ if parameters is None: parameters = {} parser = etree.XMLParser(remove_comments=True) tree = objectify.parse(input_file_path, parser=parser) root = tree.getroot() net = PetriNet('imported_' + str(time.time())) marking = Marking() fmarking = Marking() nett = None page = None finalmarkings = None stochastic_information = {} for child in root: nett = child places_dict = {} trans_dict = {} if nett is not None: for child in nett: if "page" in child.tag: page = child if "finalmarkings" in child.tag: finalmarkings = child if page is None: page = nett if page is not None: for child in page: if "place" in child.tag: position_X = None position_Y = None dimension_X = None dimension_Y = None place_id = child.get("id") place_name = place_id number = 0 for child2 in child: if child2.tag.endswith('name'): for child3 in child2: if child3.text: place_name = child3.text if child2.tag.endswith('initialMarking'): for child3 in child2: if child3.tag.endswith("text"): number = int(child3.text) if child2.tag.endswith('graphics'): for child3 in child2: if child3.tag.endswith('position'): position_X = float(child3.get("x")) position_Y = float(child3.get("y")) elif child3.tag.endswith("dimension"): dimension_X = float(child3.get("x")) dimension_Y = float(child3.get("y")) places_dict[place_id] = PetriNet.Place(place_id) places_dict[place_id].properties[ constants.PLACE_NAME_TAG] = place_name net.places.add(places_dict[place_id]) if position_X is not None and position_Y is not None and dimension_X is not None and dimension_Y is not None: places_dict[place_id].properties[ constants.LAYOUT_INFORMATION_PETRI] = ((position_X, position_Y), (dimension_X, dimension_Y)) if number > 0: marking[places_dict[place_id]] = number del place_name if page is not None: for child in page: if child.tag.endswith("transition"): position_X = None position_Y = None dimension_X = None dimension_Y = None trans_name = child.get("id") trans_label = trans_name trans_visible = True random_variable = None for child2 in child: if child2.tag.endswith("name"): for child3 in child2: if child3.text: if trans_label == trans_name: trans_label = child3.text if child2.tag.endswith("graphics"): for child3 in child2: if child3.tag.endswith("position"): position_X = float(child3.get("x")) position_Y = float(child3.get("y")) elif child3.tag.endswith("dimension"): dimension_X = float(child3.get("x")) dimension_Y = float(child3.get("y")) if child2.tag.endswith("toolspecific"): tool = child2.get("tool") if "ProM" in tool: activity = child2.get("activity") if "invisible" in activity: trans_visible = False elif "StochasticPetriNet" in tool: distribution_type = None distribution_parameters = None priority = None weight = None for child3 in child2: key = child3.get("key") value = child3.text if key == "distributionType": distribution_type = value elif key == "distributionParameters": distribution_parameters = value elif key == "priority": priority = int(value) elif key == "weight": weight = float(value) random_variable = RandomVariable() random_variable.read_from_string( distribution_type, distribution_parameters) random_variable.set_priority(priority) random_variable.set_weight(weight) if not trans_visible: trans_label = None #if "INVISIBLE" in trans_label: # trans_label = None trans_dict[trans_name] = PetriNet.Transition( trans_name, trans_label) net.transitions.add(trans_dict[trans_name]) if random_variable is not None: trans_dict[trans_name].properties[ constants.STOCHASTIC_DISTRIBUTION] = random_variable if position_X is not None and position_Y is not None and dimension_X is not None and dimension_Y is not None: trans_dict[trans_name].properties[ constants.LAYOUT_INFORMATION_PETRI] = ((position_X, position_Y), (dimension_X, dimension_Y)) if page is not None: for child in page: if child.tag.endswith("arc"): arc_source = child.get("source") arc_target = child.get("target") arc_weight = 1 for arc_child in child: if arc_child.tag.endswith("inscription"): for text_arcweight in arc_child: if text_arcweight.tag.endswith("text"): arc_weight = int(text_arcweight.text) if arc_source in places_dict and arc_target in trans_dict: add_arc_from_to(places_dict[arc_source], trans_dict[arc_target], net, weight=arc_weight) elif arc_target in places_dict and arc_source in trans_dict: add_arc_from_to(trans_dict[arc_source], places_dict[arc_target], net, weight=arc_weight) if finalmarkings is not None: for child in finalmarkings: for child2 in child: place_id = child2.get("idref") for child3 in child2: if child3.tag.endswith("text"): number = int(child3.text) if number > 0: fmarking[places_dict[place_id]] = number # generate the final marking in the case has not been found if len(fmarking) == 0: fmarking = final_marking.discover_final_marking(net) return net, marking, fmarking
def get_map_from_log_and_net(log, net, initial_marking, final_marking, force_distribution=None, parameters=None): """ Get transition stochastic distribution map given the log and the Petri net Parameters ----------- log Event log net Petri net initial_marking Initial marking of the Petri net final_marking Final marking of the Petri net force_distribution If provided, distribution to force usage (e.g. EXPONENTIAL) parameters Parameters of the algorithm, including: Parameters.ACTIVITY_KEY -> activity name Parameters.TIMESTAMP_KEY -> timestamp key Returns ----------- stochastic_map Map that to each transition associates a random variable """ stochastic_map = {} if parameters is None: parameters = {} token_replay_variant = exec_utils.get_param_value( Parameters.TOKEN_REPLAY_VARIANT, parameters, executor.Variants.TOKEN_REPLAY) activity_key = exec_utils.get_param_value(Parameters.ACTIVITY_KEY, parameters, xes_constants.DEFAULT_NAME_KEY) timestamp_key = exec_utils.get_param_value( Parameters.TIMESTAMP_KEY, parameters, xes_constants.DEFAULT_TIMESTAMP_KEY) parameters_variants = { constants.PARAMETER_CONSTANT_ACTIVITY_KEY: activity_key } variants_idx = variants_module.get_variants_from_log_trace_idx( log, parameters=parameters_variants) variants = variants_module.convert_variants_trace_idx_to_trace_obj( log, variants_idx) parameters_tr = { token_replay.Parameters.ACTIVITY_KEY: activity_key, token_replay.Parameters.VARIANTS: variants } # do the replay aligned_traces = executor.apply(log, net, initial_marking, final_marking, variant=token_replay_variant, parameters=parameters_tr) element_statistics = performance_map.single_element_statistics( log, net, initial_marking, aligned_traces, variants_idx, activity_key=activity_key, timestamp_key=timestamp_key, parameters={"business_hours": True}) for el in element_statistics: if type( el ) is PetriNet.Transition and "performance" in element_statistics[el]: values = element_statistics[el]["performance"] rand = RandomVariable() rand.calculate_parameters(values, force_distribution=force_distribution) no_of_times_enabled = element_statistics[el]['no_of_times_enabled'] no_of_times_activated = element_statistics[el][ 'no_of_times_activated'] if no_of_times_enabled > 0: rand.set_weight( float(no_of_times_activated) / float(no_of_times_enabled)) else: rand.set_weight(0.0) stochastic_map[el] = rand return stochastic_map
#there are 6 possible traces simulated_log = simulator.apply(net, im, variant=simulator.Variants.EXTENSIVE, parameters={simulator.Variants.EXTENSIVE.value.Parameters.MAX_TRACE_LENGTH: 5}) #saving possible traces in a dictionary possible_traces = {} possible_traces[0] = ['a', 'b', 'e'] possible_traces[1] = ['a', 'b', 'd', 'e'] possible_traces[2] = ['a', 'd', 'b', 'e'] possible_traces[3] = ['a', 'c', 'e'] possible_traces[4] = ['a', 'c', 'd', 'e'] possible_traces[5] = ['a', 'd', 'c', 'e'] #creating stochastic map assigning probabilities to transitions smap = {} for t in transitions: rand = RandomVariable() #we do not use the uniform distribution, but we need some kind of distribution to initialize #the random_variable of the RandomVariable() object, so that we can call set_weight and get_weight later rand.random_variable = Uniform() smap[t] = rand if t.label == "b": rand.set_weight(0.9) elif t.label == "c": rand.set_weight(0.1) elif t.label == "d": rand.set_weight(0.2) elif t.label == None: rand.set_weight(0.8) else: rand.set_weight(1)
def import_net_from_xml_object(root, parameters=None): """ Import a Petri net from an etree XML object Parameters ---------- root Root object of the XML parameters Other parameters of the algorithm """ if parameters is None: parameters = {} net = PetriNet('imported_' + str(time.time())) marking = Marking() fmarking = Marking() nett = None page = None finalmarkings = None variables = None stochastic_information = {} for child in root: nett = child places_dict = {} trans_dict = {} if nett is not None: for child in nett: if "page" in child.tag: page = child if "finalmarkings" in child.tag: finalmarkings = child if "variables" in child.tag: variables = child if page is None: page = nett if page is not None: for child in page: if "place" in child.tag: position_X = None position_Y = None dimension_X = None dimension_Y = None place_id = child.get("id") place_name = place_id number = 0 for child2 in child: if child2.tag.endswith('name'): for child3 in child2: if child3.text: place_name = child3.text if child2.tag.endswith('initialMarking'): for child3 in child2: if child3.tag.endswith("text"): number = int(child3.text) if child2.tag.endswith('graphics'): for child3 in child2: if child3.tag.endswith('position'): position_X = float(child3.get("x")) position_Y = float(child3.get("y")) elif child3.tag.endswith("dimension"): dimension_X = float(child3.get("x")) dimension_Y = float(child3.get("y")) places_dict[place_id] = PetriNet.Place(place_id) places_dict[place_id].properties[ constants.PLACE_NAME_TAG] = place_name net.places.add(places_dict[place_id]) if position_X is not None and position_Y is not None and dimension_X is not None and dimension_Y is not None: places_dict[place_id].properties[ constants.LAYOUT_INFORMATION_PETRI] = ((position_X, position_Y), (dimension_X, dimension_Y)) if number > 0: marking[places_dict[place_id]] = number del place_name if page is not None: for child in page: if child.tag.endswith("transition"): position_X = None position_Y = None dimension_X = None dimension_Y = None trans_id = child.get("id") trans_name = trans_id trans_visible = True trans_properties = {} trans_guard = child.get("guard") if trans_guard is not None: trans_properties[ petri_properties.TRANS_GUARD] = trans_guard random_variable = None for child2 in child: if child2.tag.endswith("name"): for child3 in child2: if child3.text: if trans_name == trans_id: trans_name = child3.text elif child2.tag.endswith("graphics"): for child3 in child2: if child3.tag.endswith("position"): position_X = float(child3.get("x")) position_Y = float(child3.get("y")) elif child3.tag.endswith("dimension"): dimension_X = float(child3.get("x")) dimension_Y = float(child3.get("y")) elif child2.tag.endswith("toolspecific"): tool = child2.get("tool") if "ProM" in tool: activity = child2.get("activity") if "invisible" in activity: trans_visible = False elif "StochasticPetriNet" in tool: distribution_type = None distribution_parameters = None priority = None weight = None for child3 in child2: key = child3.get("key") value = child3.text if key == "distributionType": distribution_type = value elif key == "distributionParameters": distribution_parameters = value elif key == "priority": priority = int(value) elif key == "weight": weight = float(value) random_variable = RandomVariable() random_variable.read_from_string( distribution_type, distribution_parameters) random_variable.set_priority(priority) random_variable.set_weight(weight) elif child2.tag.endswith(petri_properties.WRITE_VARIABLE): # property for data Petri nets if petri_properties.WRITE_VARIABLE not in trans_properties: trans_properties[ petri_properties.WRITE_VARIABLE] = [] trans_properties[ petri_properties.WRITE_VARIABLE].append( child2.text) elif child2.tag.endswith(petri_properties.READ_VARIABLE): # property for data Petri nets if petri_properties.READ_VARIABLE not in trans_properties: trans_properties[ petri_properties.READ_VARIABLE] = [] trans_properties[ petri_properties.READ_VARIABLE].append(child2.text) # 15/02/2021: the name associated in the PNML to invisible transitions was lost. # at least save that as property. if trans_visible: trans_label = trans_name else: trans_label = None trans_dict[trans_id] = PetriNet.Transition( trans_id, trans_label) trans_dict[trans_id].properties[ constants.TRANS_NAME_TAG] = trans_name for prop in trans_properties: trans_dict[trans_id].properties[prop] = trans_properties[ prop] net.transitions.add(trans_dict[trans_id]) if random_variable is not None: trans_dict[trans_id].properties[ constants.STOCHASTIC_DISTRIBUTION] = random_variable if position_X is not None and position_Y is not None and dimension_X is not None and dimension_Y is not None: trans_dict[trans_id].properties[ constants.LAYOUT_INFORMATION_PETRI] = ((position_X, position_Y), (dimension_X, dimension_Y)) if page is not None: for child in page: if child.tag.endswith("arc"): arc_source = child.get("source") arc_target = child.get("target") arc_weight = 1 arc_type = None arc_properties = {} for arc_child in child: if arc_child.tag.endswith("inscription"): for text_element in arc_child: if text_element.tag.endswith("text"): arc_weight = int(text_element.text) elif arc_child.tag.endswith(petri_properties.ARCTYPE): for text_element in arc_child: if text_element.tag.endswith("text"): arc_type = text_element.text if arc_source in places_dict and arc_target in trans_dict: a = add_arc_from_to(places_dict[arc_source], trans_dict[arc_target], net, weight=arc_weight, type=arc_type) for prop in arc_properties: a.properties[prop] = arc_properties[prop] elif arc_target in places_dict and arc_source in trans_dict: a = add_arc_from_to(trans_dict[arc_source], places_dict[arc_target], net, weight=arc_weight, type=arc_type) for prop in arc_properties: a.properties[prop] = arc_properties[prop] if finalmarkings is not None: for child in finalmarkings: for child2 in child: place_id = child2.get("idref") for child3 in child2: if child3.tag.endswith("text"): number = int(child3.text) if number > 0: fmarking[places_dict[place_id]] = number if variables is not None: net.properties[petri_properties.VARIABLES] = [] for child in variables: variable_type = child.get("type") variable_name = "" for child2 in child: if child2.tag.endswith("name"): variable_name = child2.text net.properties[petri_properties.VARIABLES].append({ "type": variable_type, "name": variable_name }) # generate the final marking in the case has not been found if len(fmarking) == 0: fmarking = final_marking.discover_final_marking(net) return net, marking, fmarking