{
 "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",
       " ('__1049604', 'Class_name'),\n",
       " ('__1049676', '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": [
       "'__1054144'"
      ]
     },
     "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: {'__1063123'}\n",
      "All state element IDs: {'__1054144', '__1063123'}\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 __1054144 (ID: 1054144)\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)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Semantics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "While we have created the syntax of the new language, it should still be possible to define the semantics.\n",
    "The Modelverse supports three main types of activity, each with their own ideal problem domain."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Manual"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The first type of activity is also the easiest to define, as it is a manual activity.\n",
    "Many types of activity, or modifications of a model, have to be done manually as they augment information.\n",
    "For example, refinement is a typical operation that requires a modeller to manually add information to the model.\n",
    "\n",
    "For our own defined FSAs, assume that we want to add a *revise* activity, in which the modeller is prompted to modify the model.\n",
    "While this does not give much information to the Modelverse, it is required, for example, to integrate manual activities in a process model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "transformation_add_MANUAL({\"FSA\": \"formalisms/MyOwnFSA\"}, {\"FSA\": \"formalisms/MyOwnFSA\"}, \"formalisms/MyOwnFSA_activities/revise\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can see it in action.\n",
    "But as was mentioned, it will take manual operations, in our case through the use of a callback function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Before:\n",
      "[]\n",
      "After:\n",
      "[{'__id': '__1278420', '__type': 'State', 'name': 'new_state'}]\n"
     ]
    }
   ],
   "source": [
    "def callback(model):\n",
    "    state = instantiate(model, \"FSA/State\")\n",
    "    attr_assign(model, state, \"name\", \"new_state\")\n",
    "    \n",
    "model_add(\"models/my_FSA\", \"formalisms/MyOwnFSA\")\n",
    "\n",
    "print(\"Before:\")\n",
    "print(element_list_nice(\"models/my_FSA\"))\n",
    "\n",
    "transformation_execute_MANUAL(\"formalisms/MyOwnFSA_activities/revise\", {\"FSA\": \"models/my_FSA\"}, {\"FSA\": \"models/my_FSA\"}, callback)\n",
    "\n",
    "print(\"After:\")\n",
    "print(element_list_nice(\"models/my_FSA\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Action Language"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Another typical execution scenario is for procedural operations to execute.\n",
    "In the simplest case, this merely calls some action language code with the selected model as a parameter.\n",
    "Note that this parameter will be a single model, consisting of the merged model and metamodel.\n",
    "\n",
    "For our own defined FSAs, assume that we want to add a simple simulation algorithm.\n",
    "Note the \"return True\" at the end, signifying that the operation was terminated OK and that changes can be propagated."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "transformation_add_AL({\"FSA\": \"formalisms/MyOwnFSA\"}, {}, \"formalisms/MyOwnFSA_activities/simulate\", \"\"\"\n",
    "include \"primitives.alh\"\n",
    "include \"modelling.alh\"\n",
    "include \"object_operations.alh\"\n",
    "include \"conformance_scd.alh\"\n",
    "include \"io.alh\"\n",
    "include \"metamodels.alh\"\n",
    "include \"mini_modify.alh\"\n",
    "include \"library.alh\"\n",
    "\n",
    "Boolean function main(model : Element):\n",
    "    String input_value\n",
    "    Float start_time\n",
    "    String current_state\n",
    "    String old_state\n",
    "    Element transitions\n",
    "    String transition\n",
    "\n",
    "    start_time = time()\n",
    "\n",
    "    Element all_states\n",
    "    String element_name\n",
    "    all_states = allInstances(model, \"FSA/State\")\n",
    "    while (set_len(all_states) > 0):\n",
    "        element_name = set_pop(all_states)\n",
    "        if (read_type(model, element_name) == \"FSA/InitialState\"):\n",
    "            current_state = element_name\n",
    "            old_state = element_name\n",
    "            break!\n",
    "\n",
    "    while (time() - start_time < 10.0):\n",
    "        if (has_input()):\n",
    "            input_value = list_read(string_split(input(), \"\\\\n\"), 0)\n",
    "            log(\"Received input value: \" + cast_string(input_value))\n",
    "            if (input_value == \"__EXIT__\"):\n",
    "                break!\n",
    "\n",
    "            transitions = allOutgoingAssociationInstances(model, current_state, \"FSA/Transition\")\n",
    "            while (set_len(transitions) > 0):\n",
    "                transition = set_pop(transitions)\n",
    "                log(\"Compare against \" + cast_string(read_attribute(model, transition, \"trigger\")))\n",
    "                if (cast_string(read_attribute(model, transition, \"trigger\")) == input_value):\n",
    "                    if (element_neq(read_attribute(model, transition, \"raise\"), read_root())):\n",
    "                        log(cast_value(time() - start_time) + \" output \" + cast_string(read_attribute(model, transition, \"raise\")))\n",
    "                        output(cast_value(time() - start_time) + \" output \" + cast_string(read_attribute(model, transition, \"raise\")))\n",
    "                    if (element_neq(read_attribute(model, transition, \"script\"), read_root())):\n",
    "                        Element func\n",
    "                        func = get_func_AL_model(import_node(read_attribute(model, transition, \"script\")))\n",
    "                        func()\n",
    "                    current_state = readAssociationDestination(model, transition)\n",
    "                    break!\n",
    "\n",
    "        log(cast_value(time() - start_time) + \" \" + cast_string(read_attribute(model, current_state, \"name\")))\n",
    "        output(cast_value(time() - start_time) + \" \" + cast_string(read_attribute(model, current_state, \"name\")))\n",
    "        sleep(0.2)\n",
    "    return True!\n",
    "    \"\"\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can see it in action.\n",
    "For now, we just rely on the end time of the simulation (and no inputs happen), but otherwise we would have to couple it to an SCCD model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model_add(\"models/my_FSA\", \"formalisms/MyOwnFSA\", \"\"\"\n",
    "    InitialState init{\n",
    "        name = \"initial\"\n",
    "    }\n",
    "    State s1{\n",
    "        name = \"S1\"\n",
    "    }\n",
    "    State s2{\n",
    "        name = \"S2\"\n",
    "    }\n",
    "    Transition (init, s1) {\n",
    "        trigger = \"B\"\n",
    "        raise = \"C\"\n",
    "    }\n",
    "    Transition (s1, s2) {\n",
    "        trigger = \"A\"\n",
    "        raise = \"D\"\n",
    "    }\n",
    "    \"\"\")\n",
    "transformation_execute_AL(\"formalisms/MyOwnFSA_activities/simulate\", {\"FSA\": \"models/my_FSA\"}, {})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Model Transformation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, it is possible to define a model transformation.\n",
    "This requires RAMification and such, but this is all done transparently by the Modelverse.\n",
    "Defining a model transformation is therefore identical to defining an Action Language activity, except that now we pass a model of transformations and rules, instead of passing an action language fragment.\n",
    "\n",
    "For our defined FSAs, assume that we want to add a simple optimization transformation, removing all states that have no incoming transition."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "transformation_add_MT({\"FSA\": \"formalisms/MyOwnFSA\"}, {\"FSA\": \"formalisms/MyOwnFSA\"}, \"formalisms/MyOwnFSA_activities/optimize\", \"\"\"\n",
    "include \"primitives.alh\"\n",
    "include \"modelling.alh\"\n",
    "include \"object_operations.alh\"\n",
    "\n",
    "Composite schedule {\n",
    "    {Contains} Success success {}\n",
    "    {Contains} ForAll optimize {\n",
    "        NAC { \n",
    "            Pre_FSA/State nac_s_1 {\n",
    "                label = \"0\"\n",
    "            }\n",
    "            Pre_FSA/State nac_s_2 {\n",
    "                label = \"1\"\n",
    "            }\n",
    "            Pre_FSA/Transition nac_s_3 (nac_s_2, nac_s_1) {\n",
    "                label = \"2\"\n",
    "            }\n",
    "        }\n",
    "        LHS {\n",
    "            Pre_FSA/State pre_s_1 {\n",
    "                label = \"0\"\n",
    "                constraint = $\n",
    "                    Boolean function not_initial(model : Element, name : String):\n",
    "                        if (read_type(model, name) == \"FSA/InitialState\"):\n",
    "                            return False!\n",
    "                        else:\n",
    "                            return True!\n",
    "                $\n",
    "            }\n",
    "        }\n",
    "        RHS {\n",
    "        }\n",
    "    }    \n",
    "}\n",
    "\n",
    "Initial (schedule, optimize) {}\n",
    "OnSuccess (optimize, optimize) {}\n",
    "OnFailure (optimize, success) {}\n",
    "    \"\"\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can see it in action."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Before:\n",
      "{'a', 'c', 'b'}\n",
      "After:\n",
      "{'a', 'b'}\n"
     ]
    }
   ],
   "source": [
    "model_add(\"models/my_FSA\", \"formalisms/MyOwnFSA\", \"\"\"\n",
    "    InitialState a {\n",
    "        name = \"A\"\n",
    "    }\n",
    "    State b {\n",
    "        name = \"B\"\n",
    "    }\n",
    "    State c {\n",
    "        name = \"C\"\n",
    "    }\n",
    "    Transition (a, b) {}\n",
    "\"\"\")\n",
    "\n",
    "print(\"Before:\")\n",
    "print(all_instances(\"models/my_FSA\", \"State\"))\n",
    "\n",
    "transformation_execute_MT(\"formalisms/MyOwnFSA_activities/optimize\", {\"FSA\": \"models/my_FSA\"}, {\"FSA\": \"models/my_FSA\"})\n",
    "\n",
    "print(\"After:\")\n",
    "print(all_instances(\"models/my_FSA\", \"State\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Traceability Links"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It is often useful to have multiple metamodels that integrate with one another.\n",
    "For example, when defining denotational semantics, we might want to create traceability links between both formalisms.\n",
    "As in the Modelverse everything must be explicitly modelled, these links should also follow the usual modelling conventions.\n",
    "That is, the links must have a type defined.\n",
    "For that purpose, the Modelverse create a *merged* metamodel on which the activities actually occur.\n",
    "It is possible to define a callback in each of the *transformation_add_* operations, which are then able to alter this merged metamodel.\n",
    "Such alterations can, for example, include adding a traceability link between elements from different origining metamodels.\n",
    "For more details, refer to the documentation."
   ]
  }
 ],
 "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
}
