fpom / snakes

SNAKES is the Net Algebra Kit for Editors and Simulators
https://snakes.ibisc.univ-evry.fr
Other
89 stars 29 forks source link

KeyError when using `remove_place` methods with Clusters plugin #28

Closed maxhoerstr closed 1 year ago

maxhoerstr commented 1 year ago

Hello,

i'm currently working with the Clusters plugin for snakes and now the remove_place method always gives me a KeyError.

In the following example program i create a simple Cluster where all of my nodes exists in. If i call the remove_node method directly (the line that is commented out), it removes the Node from the cluster without an error. However, if i call the remove_place method instead, I get the KeyError "2" message. As far as i understood, the remove_place method is patched when using the Clusters plugin, so the place will be removed from the cluster too. I could not figure out why the node can not be found. Is there maybe something wrong with the creation of the Cluster? The same error occours, when leaving the nodes of the cluster empty and creating a subcluster instead.

Thanks in advance!

import snakes.plugins

snakes.plugins.load(["labels", "gv", "clusters"], "snakes.nets", "nets")
from nets import PetriNet, Place, Transition, Value, Cluster

def main():
    net = PetriNet("petri_net")
    net.add_place(Place("1", []))
    net.add_place(Place("2", []))
    net.add_place(Place("3", []))
    net.add_transition(Transition("4"))
    net.add_transition(Transition("5"))

    net.clusters = Cluster(["1", "2", "3", "4", "5"])

    net.add_input("1", "4", Value(1))
    net.add_input("2", "5", Value(1))
    net.add_input("3", "4", Value(1))
    net.add_input("3", "5", Value(1))

    # net.clusters.remove_node("2")
    net.remove_place("2")

if __name__ == "__main__":
    main()
fpom commented 1 year ago

This plugin is not intended to be used this way: by doing net.clusters = ... you replace the cluster that has been created along with net and it becomes inconsistent with the net itself. What do you want to achieve, and for what purpose do you need clusters?

Plugin cluster is mainly for internal use by plugin gv, when nets are composed through control-flow operators. If you don't use control-flow, you may be able to use clusters by yourself without interference. But to do so, you need to add an option cluster=... to net.add_place() where ... is a path to a (sub)cluster represented as a list of ints, eg [1, 2] means cluster #2 within cluster #1.

maxhoerstr commented 1 year ago

I want to cluster certain components in the petri net that belong to each other, so they are drawn "together" when using gv. More specifically, there should be subgraphs created in the dot file (which is already the case when i use them like shown above) . So everything is working as intentend except for the removal.

How is the intented way to use clusters for my use case? Is it sufficient to add cluster=... ? I tried it and it seemed like that I also have to remove the node from the cluster (like in the line that is commented out) to print the net without error.

maxhoerstr commented 1 year ago

I tried to debug the code a little bit and I observed that the remove_node method in the Cluster class is called twice when calling remove_place from the Petri Net. So the given node is removed correctly the first time, while the second call results in a KeyError.

fpom commented 1 year ago

Sorry for the delay. It turns out there was a bug indeed: plugin cluster loaded twice, first because gv depends on it and then because you loaded it explicitly. This should be fixed now; I've released a bug-fix version.

maxhoerstr commented 1 year ago

Thank you very much for the fix, it is working now!