{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "sys.path.append(\"../wrappers/\")\n",
    "from modelverse import *\n",
    "init()\n",
    "login(None, None)\n",
    "\n",
    "from IPython.display import SVG, display\n",
    "\n",
    "def view(model_name):\n",
    "    svg = SVG()\n",
    "    svg.data = show(model_name)\n",
    "    display(svg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "model_add(\"~/formalisms/simple_mm\", \"formalisms/SimpleClassDiagrams\", \"\"\"\n",
    "    include \"primitives.alh\"\n",
    "\n",
    "    SimpleAttribute integer {\n",
    "        constraint = $\n",
    "            String function constraint(value : Element):\n",
    "                if is_physical_int(value):\n",
    "                    return \"OK\"!\n",
    "                else:\n",
    "                    return \"Expected integer value instead of '\" + cast_string(value) + \"'\"!\n",
    "            $\n",
    "    }\n",
    "    SimpleAttribute string {\n",
    "        constraint = $\n",
    "            String function constraint(value : Element):\n",
    "                if is_physical_string(value):\n",
    "                    return \"OK\"!\n",
    "                else:\n",
    "                    return \"Expected string value instead of '\" + cast_string(value) + \"'\"!\n",
    "            $\n",
    "    }\n",
    "\n",
    "    Class A {\n",
    "        d : integer\n",
    "        name = \"A\"\n",
    "    }\n",
    "    Class B {\n",
    "        d : string\n",
    "        name = \"B\"\n",
    "    }\n",
    "    Class C {\n",
    "        name = \"C\"\n",
    "    }\n",
    "\n",
    "    Inheritance (C, A) {}\n",
    "    Inheritance (C, B) {}\n",
    "    \"\"\")\n",
    "\n",
    "model_add(\"~/models/model_string\", \"~/formalisms/simple_mm\", \"\"\"\n",
    "    C {\n",
    "        d = \"a\"\n",
    "    }\n",
    "    \"\"\")\n",
    "\n",
    "model_add(\"~/models/model_integer\", \"~/formalisms/simple_mm\", \"\"\"\n",
    "    C {\n",
    "        d = 1\n",
    "    }\n",
    "    \"\"\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "transformation_add_AL({\"model\": \"formalisms/Bottom\", \"metamodel\": \"formalisms/SimpleClassDiagrams\", \"type_mapping\": \"formalisms/TypeMapping\"}, {}, \"~/models/conformance_AToMPM\", \"\"\"\n",
    "    include \"primitives.alh\"\n",
    "    include \"object_operations.alh\"\n",
    "    include \"modelling.alh\"\n",
    "    include \"library.alh\"\n",
    "\n",
    "    Boolean function main(model : Element):\n",
    "        // Contains three types of models: model, metamodel, and type_mapping.\n",
    "        // Each with the obvious meanings.\n",
    "\n",
    "        // Note that this is only a placeholder that serves as a proof of concept.\n",
    "        // Thus only the check for multiple inheritance is being done, which checks for attributes.\n",
    "        // A full example is given in the Modelverse's internal conformance relation.\n",
    "\n",
    "        // Find all instances of classes\n",
    "        // First, find the class types\n",
    "        Element classes\n",
    "        classes = allInstances(model, \"metamodel/Class\")\n",
    "\n",
    "        Element type_mapping\n",
    "        Element instances\n",
    "        String instance\n",
    "        type_mapping = model[\"model\"][set_pop(allInstances(model, \"type_mapping/Root\"))]\n",
    "\n",
    "        Element new_type_mapping\n",
    "        Element keys\n",
    "        String key\n",
    "        new_type_mapping = dict_create()\n",
    "        keys = dict_keys(type_mapping)\n",
    "        while (set_len(keys) > 0):\n",
    "            key = set_pop(keys)\n",
    "            dict_add(new_type_mapping, \"model/\" + key, \"metamodel/\" + cast_string(type_mapping[key]))\n",
    "\n",
    "        type_mapping = new_type_mapping\n",
    "\n",
    "        // Check if each attribute is there, and satisfies the constraints\n",
    "        instances = dict_keys(type_mapping)\n",
    "        while (set_len(instances) > 0):\n",
    "            instance = set_pop(instances)\n",
    "            if (read_type(model, type_mapping[instance]) == \"metamodel/Class\"):\n",
    "                // Got an instance of a Class\n",
    "                String type\n",
    "                Element inherits_from\n",
    "                type = cast_string(type_mapping[instance])\n",
    "\n",
    "                Element outgoing_links\n",
    "                String outgoing_link\n",
    "                Element attrs\n",
    "\n",
    "                outgoing_links = allOutgoingAssociationInstances(model, instance, \"\")\n",
    "                attrs = dict_create()\n",
    "                while (set_len(outgoing_links) > 0):\n",
    "                    outgoing_link = set_pop(outgoing_links)\n",
    "                    String name\n",
    "                    if (dict_in(type_mapping, outgoing_link)):\n",
    "                        name = read_attribute(model, type_mapping[outgoing_link], \"name\")\n",
    "                        dict_add(attrs, name, model[\"model\"][readAssociationDestination(model, outgoing_link)])\n",
    "\n",
    "                // Fetch a list of attributes that should be defined\n",
    "                // TODO\n",
    "                inherits_from = allAssociationDestinations(model, type, \"metamodel/Inheritance\")\n",
    "\n",
    "                String superclass\n",
    "                Element defining_attributes\n",
    "                Element last_found\n",
    "\n",
    "                last_found = dict_create()\n",
    "                while (set_len(inherits_from) > 0):\n",
    "                    superclass = set_pop(inherits_from)\n",
    "                    defining_attributes = getInstantiatableAttributes(model, superclass, \"metamodel/AttributeLink\")\n",
    "                    dict_update(last_found, defining_attributes)\n",
    "\n",
    "                Element keys\n",
    "                String attr\n",
    "                Element constraint\n",
    "                String result\n",
    "                keys = dict_keys(attrs)\n",
    "                while (set_len(keys) > 0):\n",
    "                    attr = set_pop(keys)\n",
    "                    constraint = get_func_AL_model(import_node(read_attribute(model, last_found[attr], \"constraint\")))\n",
    "                    result = constraint(attrs[attr])\n",
    "\n",
    "                    if (result != \"OK\"):\n",
    "                        log(\"Conformance not OK: \" + result)\n",
    "                        return False!\n",
    "\n",
    "        log(\"Conformance OK\")\n",
    "        return True!\n",
    "    \"\"\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "transformation_add_AL({\"model\": \"formalisms/Bottom\", \"metamodel\": \"formalisms/SimpleClassDiagrams\", \"type_mapping\": \"formalisms/TypeMapping\"}, {}, \"~/models/conformance_MetaDepth\", \"\"\"\n",
    "    include \"primitives.alh\"\n",
    "    include \"object_operations.alh\"\n",
    "    include \"modelling.alh\"\n",
    "    include \"library.alh\"\n",
    "\n",
    "    Boolean function main(model : Element):\n",
    "        // Contains three types of models: model, metamodel, and type_mapping.\n",
    "        // Each with the obvious meanings.\n",
    "\n",
    "        // Note that this is only a placeholder that serves as a proof of concept.\n",
    "        // Thus only the check for multiple inheritance is being done, which checks for attributes.\n",
    "        // A full example is given in the Modelverse's internal conformance relation.\n",
    "\n",
    "        // Find all instances of classes\n",
    "        // First, find the class types\n",
    "        Element classes\n",
    "        classes = allInstances(model, \"metamodel/Class\")\n",
    "\n",
    "        Element type_mapping\n",
    "        Element instances\n",
    "        String instance\n",
    "        type_mapping = model[\"model\"][set_pop(allInstances(model, \"type_mapping/Root\"))]\n",
    "\n",
    "        Element new_type_mapping\n",
    "        Element keys\n",
    "        String key\n",
    "        new_type_mapping = dict_create()\n",
    "        keys = dict_keys(type_mapping)\n",
    "        while (set_len(keys) > 0):\n",
    "            key = set_pop(keys)\n",
    "            dict_add(new_type_mapping, \"model/\" + key, \"metamodel/\" + cast_string(type_mapping[key]))\n",
    "\n",
    "        type_mapping = new_type_mapping\n",
    "\n",
    "        // Check if each attribute is there, and satisfies the constraints\n",
    "        instances = dict_keys(type_mapping)\n",
    "        while (set_len(instances) > 0):\n",
    "            instance = set_pop(instances)\n",
    "            if (read_type(model, type_mapping[instance]) == \"metamodel/Class\"):\n",
    "                // Got an instance of a Class\n",
    "                String type\n",
    "                Element inherits_from\n",
    "                type = type_mapping[instance]\n",
    "\n",
    "                Element outgoing_links\n",
    "                String outgoing_link\n",
    "                Element attrs\n",
    "\n",
    "                outgoing_links = allOutgoingAssociationInstances(model, instance, \"\")\n",
    "                attrs = dict_create()\n",
    "                while (set_len(outgoing_links) > 0):\n",
    "                    outgoing_link = set_pop(outgoing_links)\n",
    "                    String name\n",
    "                    if (dict_in(type_mapping, outgoing_link)):\n",
    "                        name = read_attribute(model, type_mapping[outgoing_link], \"name\")\n",
    "                        dict_add(attrs, name, model[\"model\"][readAssociationDestination(model, outgoing_link)])\n",
    "\n",
    "                // Fetch a list of attributes that should be defined\n",
    "                inherits_from = allAssociationDestinations(model, type, \"metamodel/Inheritance\")\n",
    "\n",
    "                String superclass\n",
    "                Element defining_attributes\n",
    "                Element last_found\n",
    "\n",
    "                Element inherits_mapping\n",
    "                inherits_mapping = dict_create()\n",
    "\n",
    "                String key\n",
    "                while (set_len(inherits_from) > 0):\n",
    "                    key = set_pop(inherits_from)\n",
    "                    dict_add(inherits_mapping, read_attribute(model, key, \"name\"), key)\n",
    "\n",
    "                Element sorted_inherits\n",
    "                sorted_inherits = list_sort(set_to_list(dict_keys(inherits_mapping)))\n",
    "\n",
    "                inherits_from = list_create()\n",
    "                while (list_len(sorted_inherits) > 0):\n",
    "                    list_append(inherits_from, inherits_mapping[list_pop(sorted_inherits, 0)])\n",
    "\n",
    "                last_found = dict_create()\n",
    "                while (list_len(inherits_from) > 0):\n",
    "                    superclass = list_pop_final(inherits_from)\n",
    "                    defining_attributes = getInstantiatableAttributes(model, superclass, \"metamodel/AttributeLink\")\n",
    "                    dict_update(last_found, defining_attributes)\n",
    "\n",
    "                Element keys\n",
    "                String attr\n",
    "                Element constraint\n",
    "                String result\n",
    "                keys = dict_keys(attrs)\n",
    "                while (set_len(keys) > 0):\n",
    "                    attr = set_pop(keys)\n",
    "                    constraint = get_func_AL_model(import_node(read_attribute(model, last_found[attr], \"constraint\")))\n",
    "                    result = constraint(attrs[attr])\n",
    "\n",
    "                    if (result != \"OK\"):\n",
    "                        log(\"Conformance not OK: \" + result)\n",
    "                        return False!\n",
    "\n",
    "        log(\"Conformance OK\")\n",
    "        return True!\n",
    "    \"\"\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Checking conformance of model with Integer in AToMPM semantics: False\n",
      "Checking conformance of model with String in AToMPM semantics: True\n",
      "Checking conformance of model with Integer in MetaDepth semantics: True\n",
      "Checking conformance of model with String in MetaDepth semantics: False\n"
     ]
    }
   ],
   "source": [
    "print(\"Checking conformance of model with Integer in AToMPM semantics: \" + str(transformation_execute_AL(\"~/models/conformance_AToMPM\", {\"model\": \"~/models/model_integer\", \"metamodel\": \"~/formalisms/simple_mm\", \"type_mapping\": model_types(\"~/models/model_integer\").pop()[1]}, {})))\n",
    "print(\"Checking conformance of model with String in AToMPM semantics: \" + str(transformation_execute_AL(\"~/models/conformance_AToMPM\", {\"model\": \"~/models/model_string\", \"metamodel\": \"~/formalisms/simple_mm\", \"type_mapping\": model_types(\"~/models/model_string\").pop()[1]}, {})))\n",
    "print(\"Checking conformance of model with Integer in MetaDepth semantics: \" + str(transformation_execute_AL(\"~/models/conformance_MetaDepth\", {\"model\": \"~/models/model_integer\", \"metamodel\": \"~/formalisms/simple_mm\", \"type_mapping\": model_types(\"~/models/model_integer\").pop()[1]}, {})))\n",
    "print(\"Checking conformance of model with String in MetaDepth semantics: \" + str(transformation_execute_AL(\"~/models/conformance_MetaDepth\", {\"model\": \"~/models/model_string\", \"metamodel\": \"~/formalisms/simple_mm\", \"type_mapping\": model_types(\"~/models/model_string\").pop()[1]}, {})))"
   ]
  }
 ],
 "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
}
