|
@@ -1,5 +1,5 @@
|
|
|
import wrappers.modelverse as mv
|
|
|
-from commons import get_all_attributes_of_type
|
|
|
+import commons
|
|
|
|
|
|
|
|
|
class Edge(object):
|
|
@@ -20,16 +20,94 @@ class Edge(object):
|
|
|
return "{}->{}".format(self.src, self.dest)
|
|
|
|
|
|
|
|
|
-def _count_occurences(node_type, model):
|
|
|
- """ returns the number of occurences of a node with type node_type in a model """
|
|
|
- ctr = 0
|
|
|
- all_nodes = mv.all_instances(model, "Node")
|
|
|
- for node in all_nodes:
|
|
|
- typ = mv.read_attrs(model, node)["typeID"]
|
|
|
- if typ == node_type:
|
|
|
- ctr += 1
|
|
|
- return ctr
|
|
|
-
|
|
|
+class Verifier(object):
|
|
|
+ def __init__(self, instance_model):
|
|
|
+ self._instance_model = instance_model
|
|
|
+ self._example_models = None
|
|
|
+ self._available_types = None
|
|
|
+
|
|
|
+ def set_instance_model(self, model):
|
|
|
+ self._instance_model = model
|
|
|
+
|
|
|
+ def get_instance_model(self):
|
|
|
+ return self._instance_model
|
|
|
+
|
|
|
+ def init(self):
|
|
|
+ """
|
|
|
+ Inits the verifier. Loads required data from the modelverse
|
|
|
+ to avoid reloading it for every step.
|
|
|
+ """
|
|
|
+ self._example_models = commons.all_example_models()
|
|
|
+ self._available_types = commons.get_available_types()
|
|
|
+
|
|
|
+ def verify_node_typing(self):
|
|
|
+ """
|
|
|
+ Checks if every node in instance model is typed by a node in any example model.
|
|
|
+ Should actually not be neccessary since instance modeling only allows types from
|
|
|
+ example models.
|
|
|
+ """
|
|
|
+ # First, get a list of all types found in all example models.
|
|
|
+ all_types = []
|
|
|
+ for exm in self._example_models:
|
|
|
+ all_nodes = mv.all_instances(exm, "Node")
|
|
|
+ for node in all_nodes:
|
|
|
+ typ = mv.read_attrs(exm, node)["typeID"]
|
|
|
+ if not typ in all_types:
|
|
|
+ all_types.append(typ)
|
|
|
+ # print("Verify: types found in example models: {}".format(all_types))
|
|
|
+
|
|
|
+ # Check for every node in instance model if it has a valid type
|
|
|
+ all_nodes = mv.all_instances(self._instance_model, "Node")
|
|
|
+ for node in all_nodes:
|
|
|
+ node_typ = commons.get_node_type(self._instance_model, node)
|
|
|
+ if node_typ not in all_types:
|
|
|
+ return {"OK": False, "error": "Type {} from instance model not in example models".format(node_typ)}
|
|
|
+
|
|
|
+ return {"OK":True, "error":None}
|
|
|
+
|
|
|
+ def verify_node_multiplicity(self):
|
|
|
+ """
|
|
|
+ A node is mandatory in the instance model if it occurs in every example model.
|
|
|
+ More specifically, if a node type appears occ = [n0, n1, ... n_i] times in example model i,
|
|
|
+ it needs to occur min(occ) in the instance model.
|
|
|
+ """
|
|
|
+ total_occurences = {k: [] for k in self._available_types}
|
|
|
+ for node, occ_list in total_occurences.iteritems():
|
|
|
+ for exm in self._example_models:
|
|
|
+ num_occ = commons.count_occurences(node, exm)
|
|
|
+ occ_list.append(num_occ)
|
|
|
+
|
|
|
+ elem_cardinality = {k: min(v) for k, v in total_occurences.iteritems()}
|
|
|
+ for el, min_occ in elem_cardinality.iteritems():
|
|
|
+ if not commons.count_occurences(el, self._instance_model) >= min_occ:
|
|
|
+ return {"OK": False, "error": "Node with type {} needs to occur at least {} times".format(el, min_occ)}
|
|
|
+
|
|
|
+ return {"OK": True, "error": None}
|
|
|
+
|
|
|
+ def verify_attributes(self):
|
|
|
+ """
|
|
|
+ 1. For every attribute key of a typed node in the instance model, there must be a corresponding
|
|
|
+ attribute key in some example model.
|
|
|
+ 2. An attribute for a type is mandatory if it occurs in every example model.
|
|
|
+ """
|
|
|
+
|
|
|
+ # TODO: implement
|
|
|
+
|
|
|
+ return {"OK": True, "error": None}
|
|
|
+
|
|
|
+ def verify_associations(self):
|
|
|
+ """
|
|
|
+ 1. If an association between two types is present in all example models, it is mandatory and must
|
|
|
+ therefore be present in the instance model (if it contains the same two types).
|
|
|
+ 2. For every association in the instance model, the types of the source and target must correspond
|
|
|
+ to the types of an association in some example model. This check should not be necessary since this
|
|
|
+ is already enforced while instance modeling (see im_scene.py, draw_edge() which checks this when trying
|
|
|
+ to connect two nodes).
|
|
|
+ """
|
|
|
+
|
|
|
+ # TODO: implement
|
|
|
+
|
|
|
+ return {"OK": True, "error": None}
|
|
|
|
|
|
def verify(instance_model_path):
|
|
|
"""
|
|
@@ -40,14 +118,13 @@ def verify(instance_model_path):
|
|
|
3. Attribute validity
|
|
|
4. Associations
|
|
|
"""
|
|
|
- example_models = mv.model_list("models/example")
|
|
|
- example_models_full = ["models/example/"+exm for exm in example_models]
|
|
|
+ example_models = commons.all_example_models()
|
|
|
|
|
|
# 1. Check if all nodes in instance model are typed by a node in the example models
|
|
|
# For that, first get all available types from example models
|
|
|
print("Verify: checking node typing ...")
|
|
|
all_types = []
|
|
|
- for exm in example_models_full:
|
|
|
+ for exm in example_models:
|
|
|
all_nodes = mv.all_instances(exm, "Node")
|
|
|
for node in all_nodes:
|
|
|
typ = mv.read_attrs(exm, node)["typeID"]
|
|
@@ -67,7 +144,7 @@ def verify(instance_model_path):
|
|
|
print("Verify: checking node multiplicity ...")
|
|
|
total_occurences = {k:[] for k in all_types}
|
|
|
for node, occ_list in total_occurences.iteritems():
|
|
|
- for exm in example_models_full:
|
|
|
+ for exm in example_models:
|
|
|
num_occ = _count_occurences(node, exm)
|
|
|
occ_list.append(num_occ)
|
|
|
|
|
@@ -76,24 +153,22 @@ def verify(instance_model_path):
|
|
|
if not _count_occurences(el, instance_model_path) >= min_occ:
|
|
|
return {"OK":False, "error":"Node with type {} needs to occur at least {} times".format(el, min_occ)}
|
|
|
|
|
|
- return {"OK":True, "error":None}
|
|
|
-
|
|
|
# 3. Check attribute types: Is every attribute in instance model present in some example model?
|
|
|
print("Verify: checking attributes ...")
|
|
|
all_nodes = mv.all_instances(instance_model_path, "Node")
|
|
|
for node in all_nodes:
|
|
|
- node_typ = mv.read_attrs(instance_model_path, node)["type"]
|
|
|
- attrs = get_all_attributes_of_type(instance_model_path, node_typ)
|
|
|
+ node_typ = mv.read_attrs(instance_model_path, node)["typeID"]
|
|
|
+ attrs = commons.get_all_attributes_of_type(instance_model_path, node_typ)
|
|
|
if len(attrs) == 0:
|
|
|
continue
|
|
|
#print("Attributes of node {} of type {} are: {}".format(node, node_typ, attrs))
|
|
|
# check example models for such an attribute key
|
|
|
for im_attribute in attrs:
|
|
|
found = False
|
|
|
- for exm in example_models_full:
|
|
|
+ for exm in example_models:
|
|
|
if found:
|
|
|
break
|
|
|
- exm_attrs = get_all_attributes_of_type(exm, node_typ)
|
|
|
+ exm_attrs = commons.get_all_attributes_of_type(exm, node_typ)
|
|
|
for exm_attr in exm_attrs:
|
|
|
if exm_attr.key == im_attribute.key:
|
|
|
#print("Found attribute {} in model {}".format(im_attribute, exm))
|
|
@@ -109,17 +184,17 @@ def verify(instance_model_path):
|
|
|
# Check multiplicity: an association needs to occur n>0 times if it occurs n>0 times in every example model
|
|
|
# Check assocation type validity as well
|
|
|
print("Verify: checking associations ...")
|
|
|
- all_edges = {k:[] for k in example_models_full}
|
|
|
- for exm in example_models_full:
|
|
|
+ all_edges = {k:[] for k in example_models}
|
|
|
+ for exm in example_models:
|
|
|
all_nodes = mv.all_instances(exm, "Node")
|
|
|
for node in all_nodes:
|
|
|
- node_typ = mv.read_attrs(exm, node)["type"]
|
|
|
+ node_typ = mv.read_attrs(exm, node)["typeID"]
|
|
|
out_associations = mv.read_outgoing(exm, node, "Edge")
|
|
|
for assoc in out_associations:
|
|
|
if assoc.startswith("__"):
|
|
|
continue
|
|
|
target = mv.read_association_destination(exm, assoc)[0]
|
|
|
- target_typ = mv.read_attrs(exm, target)["type"]
|
|
|
+ target_typ = mv.read_attrs(exm, target)["typeID"]
|
|
|
all_edges[exm].append(Edge(node_typ, target_typ))
|
|
|
|
|
|
unique_edges = []
|
|
@@ -136,7 +211,8 @@ def verify(instance_model_path):
|
|
|
for k, v in edge_ctr.iteritems():
|
|
|
edge_ctr[k] = min(v)
|
|
|
|
|
|
- #print(edge_ctr) # {Edge("AP", "Tablet"): 0, Edge("Router", "PC"): 1, ...}
|
|
|
+ print(edge_ctr) # {Edge("AP", "Tablet"): 0, Edge("Router", "PC"): 1, ...}
|
|
|
+ return {"OK": True, "error": None}
|
|
|
|
|
|
# check if mandatory edges are present in instance model
|
|
|
# first, get all edges in instance model
|
|
@@ -147,8 +223,8 @@ def verify(instance_model_path):
|
|
|
continue
|
|
|
edge_src = mv.read_association_source(instance_model_path, edge)[0]
|
|
|
edge_dest = mv.read_association_destination(instance_model_path, edge)[0]
|
|
|
- edge_src_typ = mv.read_attrs(instance_model_path, edge_src)["type"]
|
|
|
- edge_dest_typ = mv.read_attrs(instance_model_path, edge_dest)["type"]
|
|
|
+ edge_src_typ = mv.read_attrs(instance_model_path, edge_src)["typeID"]
|
|
|
+ edge_dest_typ = mv.read_attrs(instance_model_path, edge_dest)["typeID"]
|
|
|
im_edges.append(Edge(edge_src_typ, edge_dest_typ))
|
|
|
|
|
|
# Check if all edges in instance models are valid (connecting types correspond to example models)
|