Browse Source

Updated new_MM notebook

Yentl Van Tendeloo 3 years ago
parent
commit
e60f863cd8
1 changed files with 424 additions and 119 deletions
  1. 424 119
      New_MM.ipynb

+ 424 - 119
New_MM.ipynb

@@ -4,7 +4,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "# Create a new metamodel"
+    "# Initialization"
    ]
   },
   {
@@ -32,7 +32,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "## New metamodel"
+    "# New metamodel"
    ]
   },
   {
@@ -55,8 +55,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Add the different attributes to be used, and define their name.\n",
-    "Action language attributes can also be used, which goes outside of the simple attributes."
+    "We can now easily add an instance model."
    ]
   },
   {
@@ -65,46 +64,92 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "model_add(\"formalisms/MyOwnFSA\", \"formalisms/SimpleClassDiagrams\", \"\"\"\n",
-    "    include \"primitives.alh\"\n",
-    "\n",
-    "    SimpleAttribute String {\n",
-    "        name = \"String\"\n",
-    "    }\n",
-    "\n",
-    "    ActionLanguage Action {}\n",
-    "    \"\"\")"
+    "model_add(\"my_FSA\", \"formalisms/MyOwnFSA\")"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Attributes are defined manually by the language engineer, so the constraints must also be made explicit, by mapping it to physical primitives."
+    "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",
-    "    include \"primitives.alh\"\n",
-    "    include \"modelling.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",
+    "    Class State {\n",
+    "        name = \"State\"\n",
     "    }\n",
     "\n",
-    "    ActionLanguage Action {}\n",
+    "    Association Transition (State, State) {\n",
+    "        name = \"Transition\"\n",
+    "    }\n",
     "    \"\"\")"
    ]
   },
@@ -112,45 +157,86 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Add the different classes and associations of the metamodel."
+    "This allows us to instantiate elements of these types."
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "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",
-    "    include \"primitives.alh\"\n",
-    "    include \"modelling.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",
+    "    }\n",
     "\n",
-    "        constraint = $\n",
-    "            String function constraint(model : Element, name : String):\n",
-    "                if (string_len(read_attribute(model, name, \"name\")) > 3):\n",
-    "                    return \"OK\"!\n",
-    "                else:\n",
-    "                    return \"Name is too short\"!\n",
-    "            $\n",
+    "    Class InitialState : State {\n",
+    "        name = \"InitialState\"\n",
     "    }\n",
     "\n",
     "    Association Transition (State, State) {\n",
+    "        name = \"Transition\"\n",
     "    }\n",
     "    \"\"\")"
    ]
@@ -159,28 +245,58 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Define attributes in the state and transitions, using the previously defined attribute types."
+    "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": 6,
+   "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",
-    "        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",
@@ -188,20 +304,17 @@
     "    Class State {\n",
     "        name = \"State\"\n",
     "        name : String\n",
+    "    }\n",
     "\n",
-    "        constraint = $\n",
-    "            String function constraint(model : Element, name : String):\n",
-    "                if (string_len(read_attribute(model, name, \"name\")) > 3):\n",
-    "                    return \"OK\"!\n",
-    "                else:\n",
-    "                    return \"Name is too short\"!\n",
-    "            $\n",
+    "    Class InitialState : State {\n",
+    "        name = \"InitialState\"\n",
     "    }\n",
     "\n",
     "    Association Transition (State, State) {\n",
-    "        trigger? : String {}\n",
-    "        raise? : String {}\n",
-    "        script? : Action {}\n",
+    "        name = \"Transition\"\n",
+    "        trigger : String {}\n",
+    "        raise : String {}\n",
+    "        script : Action {}\n",
     "    }\n",
     "    \"\"\")"
    ]
@@ -210,18 +323,130 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Still missing the initial state, which we can define using inheritance."
+    "Now attributes can be instantiated on these instances."
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "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",
@@ -239,23 +464,17 @@
     "    Class State {\n",
     "        name = \"State\"\n",
     "        name : String\n",
-    "        \n",
-    "        constraint = $\n",
-    "            String function constraint(model : Element, name : String):\n",
-    "                if (string_len(read_attribute(model, name, \"name\")) > 3):\n",
-    "                    return \"OK\"!\n",
-    "                else:\n",
-    "                    return \"Name is too short\"!\n",
-    "            $\n",
     "    }\n",
     "\n",
     "    Class InitialState : State {\n",
+    "        name = \"InitialState\"\n",
     "    }\n",
     "\n",
     "    Association Transition (State, State) {\n",
-    "        trigger? : String {}\n",
-    "        raise? : String {}\n",
-    "        script? : Action {}\n",
+    "        name = \"Transition\"\n",
+    "        trigger : String {}\n",
+    "        raise : String {}\n",
+    "        script : Action {}\n",
     "    }\n",
     "    \"\"\")"
    ]
@@ -264,12 +483,46 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Require that there is exactly one initial state, by using a global constraint."
+    "This yields the expected result."
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "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": [
@@ -294,23 +547,17 @@
     "    Class State {\n",
     "        name = \"State\"\n",
     "        name : String\n",
-    "\n",
-    "        constraint = $\n",
-    "            String function constraint(model : Element, name : String):\n",
-    "                if (string_len(read_attribute(model, name, \"name\")) > 3):\n",
-    "                    return \"OK\"!\n",
-    "                else:\n",
-    "                    return \"Name is too short\"!\n",
-    "            $\n",
     "    }\n",
     "\n",
     "    Class InitialState : State {\n",
+    "        name = \"InitialState\"\n",
     "    }\n",
     "\n",
     "    Association Transition (State, State) {\n",
-    "        trigger? : String {}\n",
-    "        raise? : String {}\n",
-    "        script? : Action {}\n",
+    "        name = \"Transition\"\n",
+    "        trigger : String {}\n",
+    "        raise : String {}\n",
+    "        script : Action {}\n",
     "    }\n",
     "\n",
     "    GlobalConstraint {\n",
@@ -333,12 +580,24 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "More efficient implementation using predefined constructs (lower_cardinality and upper_cardinality)."
+    "# 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": 9,
+   "execution_count": 19,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -363,22 +622,76 @@
     "    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 (string_len(read_attribute(model, name, \"name\")) > 3):\n",
+    "                if (is_physical_string(model[\"model\"][name])):\n",
     "                    return \"OK\"!\n",
     "                else:\n",
-    "                    return \"Name is too short\"!\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",
@@ -386,6 +699,13 @@
     "    \"\"\")"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Incremental Construction"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -395,7 +715,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
+   "execution_count": 21,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -419,23 +739,15 @@
     "state = instantiate(mm, \"Class\")\n",
     "attr_assign(mm, state, \"name\", \"State\")\n",
     "define_attribute(mm, state, \"name\", str_attr)\n",
-    "attr_assign_code(mm, state, \"constraint\", \"\"\"\n",
-    "    include \"primitives.alh\"\n",
-    "    include \"modelling.alh\"\n",
-    "    \n",
-    "    String function constraint(model : Element, name : String):\n",
-    "        if (string_len(read_attribute(model, name, \"name\")) > 3):\n",
-    "            return \"OK\"!\n",
-    "        else:\n",
-    "            return \"Name is too short\"!\n",
-    "    \"\"\")\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",
@@ -443,13 +755,6 @@
     "define_attribute(mm, transition, \"script\", al_attr)\n",
     "attribute_optional(mm, transition, \"script\", True)"
    ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
   }
  ],
  "metadata": {