Source code for pm4py.objects.petri_net.exporter.variants.pnml

'''
    PM4Py – A Process Mining Library for Python
Copyright (C) 2024 Process Intelligence Solutions UG (haftungsbeschränkt)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see this software project's root or
visit <https://www.gnu.org/licenses/>.

Website: https://processintelligence.solutions
Contact: info@processintelligence.solutions
'''
import uuid

from lxml import etree

from pm4py.objects.petri_net.obj import Marking
from pm4py.objects.petri_net.obj import PetriNet, ResetNet, InhibitorNet
from pm4py.objects.petri_net import properties as petri_properties
from pm4py.util import constants, exec_utils
from enum import Enum


[docs] class Parameters(Enum): ENCODING = "encoding"
[docs] def export_petri_tree( petrinet, marking, final_marking=None, export_prom5=False, parameters=None ): """ Export a Petrinet to a XML tree Parameters ---------- petrinet: :class:`pm4py.entities.petri.petrinet.PetriNet` Petri net marking: :class:`pm4py.entities.petri.petrinet.Marking` Marking final_marking: :class:`pm4py.entities.petri.petrinet.Marking` Final marking (optional) export_prom5 Enables exporting PNML files in a format that is ProM5-friendly parameters Other parameters of the algorithm Returns ---------- tree XML tree """ if parameters is None: parameters = {} if final_marking is None: final_marking = Marking() root = etree.Element("pnml") net = etree.SubElement(root, "net") net.set("id", petrinet.name) netname = etree.SubElement(net, "name") netnametext = etree.SubElement(netname, "text") netnametext.text = petrinet.name net.set("type", "http://www.pnml.org/version-2009/grammar/pnmlcoremodel") if export_prom5 is True: page = net else: page = etree.SubElement(net, "page") page.set("id", "n0") places_map = {} for place in petrinet.places: places_map[place] = place.name pl = etree.SubElement(page, "place") pl.set("id", place.name) pl_name = etree.SubElement(pl, "name") pl_name_text = etree.SubElement(pl_name, "text") pl_name_text.text = ( place.properties[constants.PLACE_NAME_TAG] if constants.PLACE_NAME_TAG in place.properties else place.name ) if place in marking: pl_initial_marking = etree.SubElement(pl, "initialMarking") pl_initial_marking_text = etree.SubElement( pl_initial_marking, "text" ) pl_initial_marking_text.text = str(marking[place]) if constants.LAYOUT_INFORMATION_PETRI in place.properties: graphics = etree.SubElement(pl, "graphics") position = etree.SubElement(graphics, "position") position.set( "x", str( place.properties[constants.LAYOUT_INFORMATION_PETRI][0][0] ), ) position.set( "y", str( place.properties[constants.LAYOUT_INFORMATION_PETRI][0][1] ), ) dimension = etree.SubElement(graphics, "dimension") dimension.set( "x", str( place.properties[constants.LAYOUT_INFORMATION_PETRI][1][0] ), ) dimension.set( "y", str( place.properties[constants.LAYOUT_INFORMATION_PETRI][1][1] ), ) transitions_map = {} for transition in petrinet.transitions: transitions_map[transition] = transition.name trans = etree.SubElement(page, "transition") trans.set("id", transition.name) trans_name = etree.SubElement(trans, "name") trans_text = etree.SubElement(trans_name, "text") if constants.LAYOUT_INFORMATION_PETRI in transition.properties: graphics = etree.SubElement(trans, "graphics") position = etree.SubElement(graphics, "position") position.set( "x", str( transition.properties[constants.LAYOUT_INFORMATION_PETRI][ 0 ][0] ), ) position.set( "y", str( transition.properties[constants.LAYOUT_INFORMATION_PETRI][ 0 ][1] ), ) dimension = etree.SubElement(graphics, "dimension") dimension.set( "x", str( transition.properties[constants.LAYOUT_INFORMATION_PETRI][ 1 ][0] ), ) dimension.set( "y", str( transition.properties[constants.LAYOUT_INFORMATION_PETRI][ 1 ][1] ), ) if constants.STOCHASTIC_DISTRIBUTION in transition.properties: random_variable = transition.properties[ constants.STOCHASTIC_DISTRIBUTION ] stochastic_information = etree.SubElement(trans, "toolspecific") stochastic_information.set("tool", "StochasticPetriNet") stochastic_information.set("version", "0.2") distribution_type = etree.SubElement( stochastic_information, "property" ) distribution_type.set("key", "distributionType") distribution_type.text = random_variable.get_distribution_type() if not random_variable.get_distribution_type() == "IMMEDIATE": distribution_parameters = etree.SubElement( stochastic_information, "property" ) distribution_parameters.set("key", "distributionParameters") distribution_parameters.text = ( random_variable.get_distribution_parameters() ) distribution_priority = etree.SubElement( stochastic_information, "property" ) distribution_priority.set("key", "priority") distribution_priority.text = str(random_variable.get_priority()) distribution_invisible = etree.SubElement( stochastic_information, "property" ) distribution_invisible.set("key", "invisible") distribution_invisible.text = str( True if transition.label is None else False ).lower() distribution_weight = etree.SubElement( stochastic_information, "property" ) distribution_weight.set("key", "weight") distribution_weight.text = str(random_variable.get_weight()) if transition.label is not None: trans_text.text = transition.label else: trans_text.text = transition.name tool_specific = etree.SubElement(trans, "toolspecific") tool_specific.set("tool", "ProM") tool_specific.set("version", "6.4") tool_specific.set("activity", "$invisible$") tool_specific.set("localNodeID", str(uuid.uuid4())) if export_prom5 is True: if transition.label is not None: prom5_specific = etree.SubElement(trans, "toolspecific") prom5_specific.set("tool", "ProM") prom5_specific.set("version", "5.2") log_event_prom5 = etree.SubElement(prom5_specific, "logevent") event_name = transition.label.split("+")[0] event_transition = ( transition.label.split("+")[1] if len(transition.label.split("+")) > 1 else "complete" ) log_event_prom5_name = etree.SubElement( log_event_prom5, "name" ) log_event_prom5_name.text = event_name log_event_prom5_type = etree.SubElement( log_event_prom5, "type" ) log_event_prom5_type.text = event_transition # specific for data Petri nets if petri_properties.TRANS_GUARD in transition.properties: trans.set( petri_properties.TRANS_GUARD, transition.properties[petri_properties.TRANS_GUARD], ) if petri_properties.READ_VARIABLE in transition.properties: read_variables = transition.properties[ petri_properties.READ_VARIABLE ] for rv in read_variables: rv_el = etree.SubElement(trans, petri_properties.READ_VARIABLE) rv_el.text = rv if petri_properties.WRITE_VARIABLE in transition.properties: write_variables = transition.properties[ petri_properties.WRITE_VARIABLE ] for wv in write_variables: wv_el = etree.SubElement( trans, petri_properties.WRITE_VARIABLE ) wv_el.text = wv for arc in petrinet.arcs: arc_el = etree.SubElement(page, "arc") arc_el.set("id", str(hash(arc))) if type(arc.source) is PetriNet.Place: arc_el.set("source", str(places_map[arc.source])) arc_el.set("target", str(transitions_map[arc.target])) else: arc_el.set("source", str(transitions_map[arc.source])) arc_el.set("target", str(places_map[arc.target])) if arc.weight > 1: inscription = etree.SubElement(arc_el, "inscription") arc_weight = etree.SubElement(inscription, "text") arc_weight.text = str(arc.weight) if isinstance(arc, ResetNet.ResetArc): element = etree.SubElement(arc_el, petri_properties.ARCTYPE) element_text = etree.SubElement(element, "text") element_text.text = petri_properties.RESET_ARC elif isinstance(arc, InhibitorNet.InhibitorArc): element = etree.SubElement(arc_el, petri_properties.ARCTYPE) element_text = etree.SubElement(element, "text") element_text.text = petri_properties.INHIBITOR_ARC for prop_key in arc.properties: if prop_key != petri_properties.ARCTYPE: element = etree.SubElement(arc_el, prop_key) element_text = etree.SubElement(element, "text") element_text.text = str(arc.properties[prop_key]) if len(final_marking) > 0: finalmarkings = etree.SubElement(net, "finalmarkings") marking = etree.SubElement(finalmarkings, "marking") for place in final_marking: placem = etree.SubElement(marking, "place") placem.set("idref", place.name) placem_text = etree.SubElement(placem, "text") placem_text.text = str(final_marking[place]) # specific for data Petri nets if petri_properties.VARIABLES in petrinet.properties: variables = etree.SubElement(net, "variables") for prop in petrinet.properties[petri_properties.VARIABLES]: variable = etree.SubElement(variables, "variable") variable.set("type", prop["type"]) variable_name = etree.SubElement(variable, "name") variable_name.text = prop["name"] tree = etree.ElementTree(root) return tree
[docs] def export_petri_as_string( petrinet, marking, final_marking=None, export_prom5=False, parameters=None ): """ Parameters ---------- petrinet: :class:`pm4py.entities.petri.petrinet.PetriNet` Petri net marking: :class:`pm4py.entities.petri.petrinet.Marking` Marking final_marking: :class:`pm4py.entities.petri.petrinet.Marking` Final marking (optional) export_prom5 Enables exporting PNML files in a format that is ProM5-friendly Returns ---------- string Petri net as string """ if parameters is None: parameters = {} encoding = exec_utils.get_param_value( Parameters.ENCODING, parameters, constants.DEFAULT_ENCODING ) # gets the XML tree tree = export_petri_tree( petrinet, marking, final_marking=final_marking, export_prom5=export_prom5, ) # removing default decoding (return binary string as in other parts of the # application) return etree.tostring(tree, xml_declaration=True, encoding=encoding)
[docs] def export_net( petrinet, marking, output_filename, final_marking=None, export_prom5=False, parameters=None, ): """ Export a Petrinet to a PNML file Parameters ---------- petrinet: :class:`pm4py.entities.petri.petrinet.PetriNet` Petri net marking: :class:`pm4py.entities.petri.petrinet.Marking` Marking final_marking: :class:`pm4py.entities.petri.petrinet.Marking` Final marking (optional) output_filename: Absolute output file name for saving the pnml file export_prom5 Enables exporting PNML files in a format that is ProM5-friendly """ if parameters is None: parameters = {} encoding = exec_utils.get_param_value( Parameters.ENCODING, parameters, constants.DEFAULT_ENCODING ) # gets the XML tree tree = export_petri_tree( petrinet, marking, final_marking=final_marking, export_prom5=export_prom5, ) # write the tree to a file F = open(output_filename, "wb") tree.write(F, pretty_print=True, xml_declaration=True, encoding=encoding) F.close()