{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Initialization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Default initialization as usual." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import sys\n", "sys.path.append(\"wrappers\")\n", "from modelverse import *\n", "\n", "init()\n", "login(\"admin\", \"admin\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# New metamodel" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Define a new metamodel by instantiation SimpleClassDiagrams." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "model_add(\"formalisms/MyOwnFSA\", \"formalisms/SimpleClassDiagrams\", \"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now easily add an instance model." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "model_add(\"my_FSA\", \"formalisms/MyOwnFSA\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nonetheless, we cannot instantiate any element in that model, as the metamodel is empty." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "set()" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "types(\"my_FSA\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And indeed, instantiating a state yields an exception." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Type State not defined!\n" ] } ], "source": [ "try:\n", " instantiate(\"my_FSA\", \"State\")\n", "except UnknownElement:\n", " print(\"Type State not defined!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Creating classes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A first step is to define some classes that we would like to use, such as states and transitions.\n", "This is done as follows, similar to the usual model instantiation." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "model_add(\"formalisms/MyOwnFSA\", \"formalisms/SimpleClassDiagrams\", \"\"\"\n", " Class State {\n", " name = \"State\"\n", " }\n", "\n", " Association Transition (State, State) {\n", " name = \"Transition\"\n", " }\n", " \"\"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This allows us to instantiate elements of these types." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{('State', 'Class'),\n", " ('State.name', 'String'),\n", " ('Transition', 'Association'),\n", " ('Transition.name', 'String'),\n", " ('__1049623', 'Class_name'),\n", " ('__1049695', 'Class_name')}" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "types(\"my_FSA\")" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'__1054163'" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "instantiate(\"my_FSA\", \"State\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Inheritance" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another useful operation is to define inheritance between classes or associations.\n", "For example, we can add the notion of an initial state, being a special case of the normal state." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "model_add(\"formalisms/MyOwnFSA\", \"formalisms/SimpleClassDiagrams\", \"\"\"\n", " Class State {\n", " name = \"State\"\n", " }\n", "\n", " Class InitialState : State {\n", " name = \"InitialState\"\n", " }\n", "\n", " Association Transition (State, State) {\n", " name = \"Transition\"\n", " }\n", " \"\"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And indeed, this allows us to create an initial state, which is handled as both an instance of state and initial." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "All initial element IDs: {'__1063142'}\n", "All state element IDs: {'__1054163', '__1063142'}\n" ] } ], "source": [ "instantiate(\"my_FSA\", \"InitialState\")\n", "print(\"All initial element IDs: \" + str(all_instances(\"my_FSA\", \"InitialState\")))\n", "print(\"All state element IDs: \" + str(all_instances(\"my_FSA\", \"State\")))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Attributes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On these classes and transitions, we want to define some attributes which instances can use.\n", "To do that, however, we need to define attribute types.\n", "The Modelverse does not predefine any attribute types at the modelling level (only physically), thereby giving the user full control over the supported types." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "model_add(\"formalisms/MyOwnFSA\", \"formalisms/SimpleClassDiagrams\", \"\"\"\n", " include \"primitives.alh\"\n", " include \"modelling.alh\"\n", " include \"object_operations.alh\"\n", "\n", " SimpleAttribute String {\n", " name = \"String\"\n", " }\n", "\n", " ActionLanguage Action {}\n", "\n", " Class State {\n", " name = \"State\"\n", " name : String\n", " }\n", "\n", " Class InitialState : State {\n", " name = \"InitialState\"\n", " }\n", "\n", " Association Transition (State, State) {\n", " name = \"Transition\"\n", " trigger : String {}\n", " raise : String {}\n", " script : Action {}\n", " }\n", " \"\"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now attributes can be instantiated on these instances." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'name': 'FirstState'}\n" ] } ], "source": [ "new_state = instantiate(\"my_FSA\", \"State\")\n", "attr_assign(\"my_FSA\", new_state, \"name\", \"FirstState\")\n", "print(read_attrs(\"my_FSA\", new_state))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note, however, that our model now no longer conforms: there are still some states that do not have any value for the name attribute.\n", "Indeed, our metamodel has evolved, thereby invalidating the model." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Lower cardinality violation for outgoing edge of type State_name at NODE __1054163 (ID: 1054163)\n" ] } ], "source": [ "print(verify(\"my_FSA\", \"formalisms/MyOwnFSA\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we now assign a value for every state that does not have a name, the model conforms again." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "OK\n" ] } ], "source": [ "for counter, state in enumerate(all_instances(\"my_FSA\", \"State\")):\n", " attr_assign(\"my_FSA\", state, \"name\", \"State_\" + str(counter))\n", "print(verify(\"my_FSA\", \"formalisms/MyOwnFSA\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Attribute Constraints" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As there are no types predefined, all constraints must be specified by the language engineer directly.\n", "As such, it is now possible to assign whatever value to the attributes, as they are unconstrained." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "OK\n" ] } ], "source": [ "attr_assign(\"my_FSA\", new_state, \"name\", 123)\n", "print(verify(\"my_FSA\", \"formalisms/MyOwnFSA\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now start constraining our custom string type as being a direct mapping to the physical type string, as defined in the MvS.\n", "This is done by assigning a constraint function to the attribute." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "model_add(\"formalisms/MyOwnFSA\", \"formalisms/SimpleClassDiagrams\", \"\"\"\n", " include \"primitives.alh\"\n", " include \"modelling.alh\"\n", " include \"object_operations.alh\"\n", "\n", " SimpleAttribute String {\n", " name = \"String\"\n", " constraint = $\n", " String function constraint(model : Element, name : String):\n", " if (is_physical_string(model[\"model\"][name])):\n", " return \"OK\"!\n", " else:\n", " return \"String has non-string value\"!\n", " $\n", " }\n", "\n", " ActionLanguage Action {}\n", "\n", " Class State {\n", " name = \"State\"\n", " name : String\n", " }\n", "\n", " Class InitialState : State {\n", " name = \"InitialState\"\n", " }\n", "\n", " Association Transition (State, State) {\n", " name = \"Transition\"\n", " trigger : String {}\n", " raise : String {}\n", " script : Action {}\n", " }\n", " \"\"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This yields the expected result." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "String has non-string value\n" ] } ], "source": [ "attr_assign(\"my_FSA\", new_state, \"name\", 123)\n", "print(verify(\"my_FSA\", \"formalisms/MyOwnFSA\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Global Constraints" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similarly, global constraints can also be defined, which get access to the complete model.\n", "These are special elements, similar to classes.\n", "In this case, we check that there is at least one instance of the InitialState class." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "model_add(\"formalisms/MyOwnFSA\", \"formalisms/SimpleClassDiagrams\", \"\"\"\n", " include \"primitives.alh\"\n", " include \"modelling.alh\"\n", " include \"object_operations.alh\"\n", "\n", " SimpleAttribute String {\n", " name = \"String\"\n", " constraint = $\n", " String function constraint(model : Element, name : String):\n", " if (is_physical_string(model[\"model\"][name])):\n", " return \"OK\"!\n", " else:\n", " return \"String has non-string value\"!\n", " $\n", " }\n", "\n", " ActionLanguage Action {}\n", "\n", " Class State {\n", " name = \"State\"\n", " name : String\n", " }\n", "\n", " Class InitialState : State {\n", " name = \"InitialState\"\n", " }\n", "\n", " Association Transition (State, State) {\n", " name = \"Transition\"\n", " trigger : String {}\n", " raise : String {}\n", " script : Action {}\n", " }\n", "\n", " GlobalConstraint {\n", " constraint = $\n", " String function constraint(model : Element):\n", " Integer initials\n", " initials = set_len(allInstances(model, \"InitialState\"))\n", " if (initials == 0):\n", " return \"No initial state found\"!\n", " elif (initials > 1):\n", " return \"Too many initial states defined\"!\n", " else:\n", " return \"OK\"!\n", " $\n", " }\n", " \"\"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Local Constraint Helpers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Most constraints are related to the multiplicities of associations and classes.\n", "For example, we want to make sure that there is exactly one instance of a specific class (e.g., InitialState).\n", "Similarly, for an association we might want to define that there is at least one such.\n", "The Modelverse provides various such attributes that can be set.\n", "For example, to constrain the number of instances, use the *lower_cardinality* and *upper_cardinality* attributes.\n", "For associations, there are additionally the *source_lower_cardinality*, *source_upper_cardinality*, *target_lower_cardinality*, and *target_upper_cardinality* attributes." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "model_add(\"formalisms/MyOwnFSA\", \"formalisms/SimpleClassDiagrams\", \"\"\"\n", " include \"primitives.alh\"\n", " include \"modelling.alh\"\n", " include \"object_operations.alh\"\n", "\n", " SimpleAttribute String {\n", " name = \"String\"\n", " constraint = $\n", " String function constraint(model : Element, name : String):\n", " if (is_physical_string(model[\"model\"][name])):\n", " return \"OK\"!\n", " else:\n", " return \"String has non-string value\"!\n", " $\n", " }\n", "\n", " ActionLanguage Action {}\n", "\n", " Class State {\n", " name = \"State\"\n", " name : String\n", " }\n", "\n", " Class InitialState : State {\n", " name = \"InitialState\"\n", " lower_cardinality = 1\n", " upper_cardinality = 1\n", " }\n", "\n", " Association Transition (State, State) {\n", " name = \"Transition\"\n", " trigger : String {}\n", " raise : String {}\n", " script : Action {}\n", " }\n", " \"\"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Optional Attributes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Often, not all of the attributes are mandatory, and they can therefore be left empty.\n", "During conformance checking, these attributes are then not enforced.\n", "When reading out their value, however, the language engineer must take care that the value might be empty." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "model_add(\"formalisms/MyOwnFSA\", \"formalisms/SimpleClassDiagrams\", \"\"\"\n", " include \"primitives.alh\"\n", " include \"modelling.alh\"\n", " include \"object_operations.alh\"\n", "\n", " SimpleAttribute String {\n", " name = \"String\"\n", " constraint = $\n", " String function constraint(model : Element, name : String):\n", " if (is_physical_string(model[\"model\"][name])):\n", " return \"OK\"!\n", " else:\n", " return \"String has non-string value\"!\n", " $\n", " }\n", "\n", " ActionLanguage Action {}\n", "\n", " Class State {\n", " name = \"State\"\n", " name : String\n", " }\n", "\n", " Class InitialState : State {\n", " name = \"InitialState\"\n", " lower_cardinality = 1\n", " upper_cardinality = 1\n", " }\n", "\n", " Association Transition (State, State) {\n", " name = \"Transition\"\n", " trigger? : String {}\n", " raise? : String {}\n", " script? : Action {}\n", " }\n", " \"\"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Incremental Construction" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, the metamodel can be created incrementally." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "mm = \"formalisms/MyOwnFSA2\"\n", "\n", "model_add(mm, \"formalisms/SimpleClassDiagrams\")\n", "\n", "str_attr = instantiate(mm, \"SimpleAttribute\")\n", "attr_assign(mm, str_attr, \"name\", \"String\")\n", "attr_assign_code(mm, str_attr, \"constraint\", \"\"\"\n", " include \"primitives.alh\"\n", " \n", " String function constraint(model : Element, name : String):\n", " if (is_physical_string(model[\"model\"][name])):\n", " return \"OK\"!\n", " else:\n", " return \"String has non-string value\"!\n", " \"\"\")\n", "al_attr = instantiate(mm, \"ActionLanguage\")\n", "\n", "state = instantiate(mm, \"Class\")\n", "attr_assign(mm, state, \"name\", \"State\")\n", "define_attribute(mm, state, \"name\", str_attr)\n", "\n", "initial = instantiate(mm, \"Class\")\n", "attr_assign(mm, initial, \"name\", \"InitialState\")\n", "instantiate(mm, \"Inheritance\", edge=(initial, state))\n", "attr_assign(mm, initial, \"lower_cardinality\", 1)\n", "attr_assign(mm, initial, \"upper_cardinality\", 1)\n", "\n", "transition = instantiate(mm, \"Association\", edge=(state, state))\n", "attr_assign(mm, transition, \"name\", \"Transition\")\n", "define_attribute(mm, transition, \"trigger\", str_attr)\n", "attribute_optional(mm, transition, \"trigger\", True)\n", "define_attribute(mm, transition, \"raise\", str_attr)\n", "attribute_optional(mm, transition, \"raise\", True)\n", "define_attribute(mm, transition, \"script\", al_attr)\n", "attribute_optional(mm, transition, \"script\", True)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.5" } }, "nbformat": 4, "nbformat_minor": 2 }