123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- Modelling
- =========
- Modelling is the core activity in the Modelverse.
- A model is based on a meta-model, or a language, which, for the sake of this tutorial, assume to exist.
- Throughout this tutorial, we will focus on how to instantiate a simple Petri Net model.
- We assume that our language has a notion of *Place*, *Transition*, *P2T* arc, and *T2P* arc.
- The *Place* has a *name* and *tokens*, the *Transition* has a *name*.
- Both the *P2T* and *T2P*"arcs have a *weight*.
- This information is stored in the metamodel, which we will define later on.
- For now, assume that the metamodel is stored in the Modelverse using the name *PetriNets*.
- Creating a model
- ----------------
- Creating a new instance of PetriNets is simple, and can be done using the *model_add* operation of the wrapper::
- >>> model_add("models/my_pn", "formalisms/PetriNets")
- The first parameter of the operation indicates the name that we would like to give to our newly created model.
- This name is available to all users, and is therefore a unique identifier.
- The second parameter is the metamodel that we want to use to conform to.
- The value needs to be a name that is available in the Modelverse, and readable to the current user.
- To get a list of currently available models, users can query the Modelverse with the *model_list* operation::
- >>> model_list("")
- ["formalisms/", "models/", "administration/", "users/", "type mappings/"]
- This list contains the various entries in the specified location.
- Note that this operation does not specify anything about the permissions of the supplied entries.
- Entries that end with a forward slash (/) are folders, and can subsequently be listed::
- >>> model_list("formalisms")
- ["Bottom", "SimpleClassDiagrams", "Tracability", ...]
- >>> model_list("users/admin")
- []
- Depending on permissions, not all folders can be listed::
-
- >>> model_list("administration")
- PermissionDenied("administration")
- Modifying a model
- -----------------
- Now that we have created our model, we can start modifying it.
- To do so, we have access to several operations offered by the Modelverse.
- We categorize them by their effects on the Modelverse: create, read, or delete.
- Create and delete operations are only allowed when the user has write permission to the model, which users have by default on their own models.
- Create
- ^^^^^^
- 1. *instantiate* creates a new instance in the model, for example a new PetriNet place::
- >>> instantiate("models/my_pn", "Place")
- __12345
- The operation requires the model on which we are working, and the type of the element you want to instantiate.
- When successful, the operation returns the identifier that can be used in future operations.
- This identifier has no value within the model, and should only be used as a handle to that specific model element.
- When instantiating an edge, the optional *edge* parameter must be passed with the identifiers to connect::
-
- >>> instantiate("models/my_pn", "Place")
- p1
- >>> instantiate("models/my_pn", "Transition")
- t1
- >>> instantiate("models/my_pn", "P2T", edge=("p1", "t1"))
- p2t1
- 2. *attr_assign* assigns attributes of a specific model element.
- For example, it specifies the name and number of tokens of our PetriNet place::
-
- >>> instantiate("models/my_pn", "Place")
- p1
- >>> attr_assign("models/my_pn", "p1", "name", "place 1")
- >>> attr_assign("models/my_pn", "p1", "tokens", 2)
- The value of the attribute can be any simple primitive: string, integer, float, or boolean.
- When the attribute already exists, its value is overwritten.
- If it doesn't exist, it is created.
- Read
- ^^^^
- 1. *read* reads out basic information about a queried element, such as its type and the source and target (if it is an edge)::
- >>> instantiate("models/my_pn", "Place")
- p1
- >>> read("models/my_pn", "p1")
- ("Place, None)
- >>> instantiate("models/my_pn", "Transition")
- t1
- >>> instantiate("models/my_pn", "P2T", edge=("p1", "t1"))
- p2t1
- >>> read("models/my_pn", "p2t1")
- ("P2T", ("p1", "t1"))
- 2. *read_attrs* reads out the attributes of a specific element, in a dictionary form.
- This operation can be used to read out, for example, the number of tokens of a specific place::
- >>> instantiate("models/my_pn", "Place")
- p1
- >>> attr_assign("models/my_pn", "p1", "name", "place 1")
- >>> attr_assign("models/my_pn", "p1", "tokens", 2)
- >>> read_attrs("models/my_pn", "p1")
- {"name": "place 1", "tokens": 2}
-
- 3. *types* reads out the list of types that can be instantiated in this model.
- All calls to instantiate should act upon one of these types.
- For PetriNets, this returns the concepts of the domain::
- >>> types("models/my_pn")
- ["Place", "Transition", "P2T", "T2P", ...]
- 4. *element_list_nice* reads out a simple JSON-like representation of the model.
- This includes all information about the model and can be used to fetch the complete model in one go.
- For example, to read out a simple PetriNet::
- >>> element_list_nice("models/my_pn")
- [{"id": "p1", "type": "Place", "name": "place 1", "tokens": 1},
- {"id": "p2", "type": "Place", "name": "place 2", "tokens": 2},
- {"id": "t1", "type": "Transition"},
- {"id": "p2t", "type": "P2T", "__source": "p1", "__target": "t1", "weight": 1},
- {"id": "t2p", "type": "T2P", "__source": "t1", "__target": "p2", "weight": 2},
- ]
- 5. *read_outgoing* reads the outgoing associations of a certain type, for a specific element.
- This takes into account inheritance relation.
- For example, to read out all outgoing P2T links of a place::
- >>> read_outgoing("models/my_pn", "p1", "P2T")
- ["p2t"]
- It is possible to get all outgoing associations as well, by leaving the type empty (the empty string).
- 6. *read_incoming* similarly reads out all incoming associations of a certain type, for a specific element.
- For example, to read out all incoming T2P links of a place::
- >>> read_incoming("models/my_pn", "p2", "T2P")
- ["t2p"]
- Again, the type can be set to the empty string to return all incoming associations.
- 7. *read_association_source* reads out the source of a specific association, and can be used in conjunction with *read_outgoing* and *read_incoming*.
- For example, to read out which is the source of an arc::
- >>> read_association_source("models/my_pn", "p2t")
- p1
- 8. *read_association_destination* similarly reads out the destination of a specific association.
- For example, to read out the target of an arc::
- >>> read_association_destination("models/my_pn", "p2t")
- t1
- 9. *connections_between* reads out the set of all association types that can be created between two elements in the model.
- This also takes into account inheritance information.
- For example, to find out which association types can connect a place and transition::
- >>> connections_between("models/my_pn", "p1", "t1")
- ["P2T"]
- If no associations are allowed, the list is empty.
- 10. *all_instances* read out the set of all instances of a specific type in the model.
- For example, to find all Places in our PetriNet model::
- >>> all_instances("models/my_pn", "Place")
- ["p1", "p2"]
- Delete
- ^^^^^^
- 1. *delete_element* deletes the element from the model and the type mapping.
- Note that currently, attribute values are not automatically removed from the model, and they will remain dangling.
- Therefore, to prevent strange errors, it is safest to first delete all attributes of an element before deleting it.
- Associations, however, are removed.
- For example, to remove place p1::
- >>> element_list_nice("models/my_pn")
- [{"id": "p1", "type": "Place", "name": "place 1", "tokens": 1},
- {"id": "p2", "type": "Place", "name": "place 2", "tokens": 2},
- {"id": "t1", "type": "Transition"},
- {"id": "p2t", "type": "P2T", "__source": "p1", "__target": "t1", "weight": 1},
- {"id": "t2p", "type": "T2P", "__source": "t1", "__target": "p2", "weight": 2},
- ]
- >>> delete_element("models/my_pn", "p1")
- >>> element_list_nice("models/my_pn")
- [{"id": "p2", "type": "Place", "name": "place 2", "tokens": 2},
- {"id": "t1", "type": "Transition"},
- {"id": "t2p", "type": "T2P", "__source": "t1", "__target": "p2", "weight": 2},
- ]
- 2. *attr_delete* deletes an attribute from a model element.
- The attribute is removed, basically rendering it undefined.
- Nonetheless, if the attribute is optional, a subsequent *attr_assign* call is required to make sure that the model conforms.
- Note that *attr_assign* automatically updates the attribute, so *attr_delete* is only necessary for optional attributes that must be unset.
|