Bläddra i källkod

Added examples of the various operations

Yentl Van Tendeloo 8 år sedan
förälder
incheckning
8e630ca5cf
1 ändrade filer med 160 tillägg och 2 borttagningar
  1. 160 2
      doc/operations.rst

+ 160 - 2
doc/operations.rst

@@ -1,5 +1,3 @@
-.. TODO include examples!!
-
 Operations
 ==========
 
@@ -23,6 +21,47 @@ For example, computing the reachability graph of a PetriNets instance can certai
 On the other hand, procedural algorithms are relatively easy (when implemented naively).
 
 The functions on model transformations are exposed using the *transformation_add_MT* and *transformation_execute_MT* operations.
+Examples as shown in the previous section::
+
+    >>> def callback():
+    ...     instantiate(None, "Association", edge=("PetriNets/Transition", "ReachabilityGraph/Transition"), ID="PN2RG_Transition")
+    >>> transformation_add_MT({"PetriNets": "formalisms/PetriNets"}, {"ReachabilityGraph": "formalisms/ReachabilityGraph"}, "models/pn_analyse", open("models/pn_analyse.mvc", "r").read(), callback)
+
+A situation in which model transformations are effective, is when the transformation is to map a Domain Specific Language (DSL) to a General Purpose Language (GPL).
+For example, when defining a mapping between a RPGame DSL and the PetriNets formalism, to facilitate formal analysis::
+
+    >>> def callback():
+    ...     instantiate(None, "Association", edge=("RPGame/Tile", "PetriNets/Place"), ID="Tracability_link")
+    >>> rule = \
+    ...     """
+    ...     Composite composite {
+    ...         {Contains} ForAll create_places_for_tiles {
+    ...             LHS {
+    ...                 Pre_RPGame/Tile pre_t1 {
+    ...                     label = "tile"
+    ...                 }
+    ...             }
+    ...             RHS {
+    ...                 Post_RPGame/Tile post_t1 {
+    ...                     label = "tile"
+    ...                 }
+    ...                 Post_PetriNets/Place post_p1 {
+    ...                     label = "place"
+    ...                 }
+    ...                 Post_Tracability_link (post_t1, post_p1) {
+    ...                     label = "tracability"
+    ...                 }
+    ...             }
+    ...         }
+    ...         ...
+    ...     }
+    ...     Initial (composite, create_places_for_tiles) {}
+    ...     OnSuccess (create_places_for_tiles, ...) {}
+    ...     OnFailure (create_places_for_tiles, ...) {}
+    ...     ...
+    ...     """
+    >>> transformation_add_MT({"RPGame": "formalisms/RPGame"}, {"PetriNets": "formalisms/PetriNets"}, "models/rpg_to_pn", rule, callback)
+    >>> transformation_execute_MT("models/rpg_to_pn", {"RPGame": "models/my_rpg"}, {"PetriNets": "models/exported_rpg"})
 
 Action Language
 ---------------
@@ -40,6 +79,26 @@ This function should take a single argument, being the merged model.
 From this model, the merged metamodel can easily be accessed.
 As with model transformations, the names of model entities are prefixed with their tags.
 
+For example, when defining the PetriNets analysis in action language, which is a much better match than model transformations::
+
+    >>> def callback():
+    ...     instantiate(None, "Association", edge=("PetriNets/Transition", "ReachabilityGraph/Transition"), ID="PN2RG_Transition")
+    >>> code = \
+    ...     """
+    ...     include "primitives.alh"
+    ...     Element function explore_state(model : Element, state : Element):
+    ...         ...
+    ...     
+    ...     Element function main(model : Element):
+    ...         String initial
+    ...         initial = instantiate_node(model, "ReachabilityGraph/Initial")
+    ...         instantiate_attribute(model, initial, "name", "state_0")
+    ...         ...
+    ...         return model!
+    ...     """
+    >>> transformation_add_AL({"PetriNets": "formalisms/PetriNets"}, {"ReachabilityGraph": "formalisms/ReachabilityGraph"}, "models/pn_analyse", code, callback)
+    >>> transformation-execute_AL("models/pn_analyse", {"PetriNets": "models/my_pn"}, {"ReachabilityGraph": "models/generated_reachability"})
+
 Manual Operations
 -----------------
 
@@ -53,6 +112,14 @@ The functions on action language are exposed using the *transformation_add_MANUA
 Their signature is identical to that of model transformations, except that now there is no model to provide with the *transformation_add_MANUAL*.
 As with model transformations, the names of model entities are prefixed with their tags.
 
+For example, when defining an operation to refine or revise a model in a DSL with respect to the requirements, such as the RPGame language from before::
+
+    >>> def callback():
+    ...     instantiate(None, "Association", edge=("Requirements/Actor", "RPGame/Player"))
+    >>> transformation_add_MANUAL({"RPGame": "formalisms/RPGame", "Requirements": "formalisms/Requirements"}, {"RPGame": "formalisms/RPGame"}, "revise_rpg", callback)
+
+Its execution, however, differs significantly from before, as we will see next.
+
 Execution callbacks
 ^^^^^^^^^^^^^^^^^^^
 
@@ -65,6 +132,29 @@ Therefore, the callback function can do much more than just these calls: all exp
 Based on this, the callback can define whatever structure is desired, possibly even going as far as starting up a dialog box or using a graphical interface.
 As before, the first parameter of the operations (*model_name*) should be set to *None*.
 
+For example, to specify the operations that have to be done in a manual operation, all in Python syntax::
+
+    >>> def callback():
+    ...     tiles = [instantiate(None, "RPGame/Tile") for _ in range(100)]
+    ...     left_links = [instantiate(None, "RPGame/left", edge=(tiles[i], tiles[i+1])) for i in range(len(tiles) - 1)]
+    ...     ...
+    >>> transformation_execute_MANUAL("revise_rpg", {"RPGame": "models/my_rpg", "Requirements": "models/rpg_requirements"}, {"RPGame": "models/my_rpg"}, callback)
+
+Alternatively, the operations might only be known at runtime, thereby requiring user interaction.
+Note that, in this case, the code in the callback is effectively the user interface offered to the user in this specific context.
+As such, the code can be completely tailored to the domain and problem at hand (e.g., a *create random level* operation).
+
+    >>> def callback():
+    ...     while True:
+    ...         print("Please perform operation on RPGame!)"
+    ...         inp = raw_input()
+    ...         if inp == "new tile":
+    ...             instantiate(None, "RPGame/Tile")
+    ...         elif inp == "create random level":
+    ...             ...
+    ...         ...
+    >>> transformation_execute_MANUAL("revise_rpg", {"RPGame": "models/my_rpg", "Requirements": "models/rpg_requirements"}, {"RPGame": "models/my_rpg"}, callback)
+
 Manual operations are not the only operations which might require user input.
 Model transformations and action language can just as well query the users for input.
 This is done the same way: by defining a callback function.
@@ -86,6 +176,74 @@ Apart from control flow, an FTG+PM also specifies data flow: which models are us
 Indeed, we could define the sequence of activities to execute, but we still need information on what are the input models of the various activities.
 For example, the same activity might execute multiple times, but each time on different input models and generating different output models.
 
+A simple process model is shown, which executes the operations stored in *models/A* and *models/B* in parallel.
+Both operations use some data, where *models/A* modifies one of its data inputs in-place, and *models/B* generates new data::
+
+    Start start {}
+    Finish finish {}
+
+    Fork fork1 {}
+
+    Exec activity_A {
+        name = "models/A"
+    }
+
+    Exec activity_B {
+        name = "models/B"
+    }
+
+    Join join1{}
+
+    Data data_a1 {
+        name = "models/data_a1"
+        type = "formalisms/Bottom"
+    }
+
+    Data data_a2 {
+        name = "models/data_a2"
+        type = "formalisms/Bottom"
+    }
+
+    Data data_b1 {
+        name = "models/data_b1"
+        type = "formalisms/SimpleClassDiagrams"
+    }
+
+    Data data_b2 {
+        name = "models/data_b2"
+        type = "formalisms/Bottom"
+    }
+
+    Next (start, fork1) {}
+    Next (fork1, activity_A) {}
+    Next (fork1, activity_B) {}
+    Next (activity_A, join1) {}
+    Next (activity_B, join1) {}
+    Next (join1, finish) {}
+
+    Consumes (activity_A, data_a1) {
+        name = "First"
+    }
+    Consumes (activity_A, data_a2) {
+        name = "Second"
+    }
+    Produces (activity_A, data_a2) {
+        name = "Second"
+    }
+
+    Consumes (activity_B, data_b1) {
+        name = "input"
+    }
+    Produces (activity_B, data_b2) {
+        name = "output"
+    }
+
+This simple Process Model is equivalent to the following statements in the code.
+Note that we do not know the type of the activity in the operations, and therefore put an asterisk (\*) there::
+
+    >>> execute_transformation_*("models/A", {"First": "my_models/data_a1", "Second": "my_models/data_a2"}, {"Second": "my_models/data_a2"})
+    >>> execute_transformation_*("models/B", {"input": "my_models/data_b1"}, {"output": "my_models/data_b2"})
+
 When enacting, the FTG+PM is executed by starting at the initial node.
 The first element it points to is executed, thereby branching, deciding, or executing an activity.
 Due to the branching, it is possible for multiple activities to be scheduled concurrently.