Nominal and structural typing seem to be fully working
This commit is contained in:
parent
f7430cceff
commit
695ec6132a
3 changed files with 77 additions and 25 deletions
|
|
@ -31,10 +31,10 @@ def bootstrap_pn(state: State, model_name: str) -> UUID:
|
||||||
# Create class attributes
|
# Create class attributes
|
||||||
service.create_attribute_link("P", "Integer", "t", False)
|
service.create_attribute_link("P", "Integer", "t", False)
|
||||||
service.create_attribute_link("P", "String", "n", False)
|
service.create_attribute_link("P", "String", "n", False)
|
||||||
service.create_attribute_link("T", "String", "n", False)
|
service.create_attribute_link("T", "String", "name", False)
|
||||||
# Create association attributes
|
# Create association attributes
|
||||||
service.create_attribute_link("P2T", "Integer", "w", False)
|
service.create_attribute_link("P2T", "Integer", "weight", False)
|
||||||
service.create_attribute_link("T2P", "Integer", "w", False)
|
service.create_attribute_link("T2P", "Integer", "weight", False)
|
||||||
# Create test constraint
|
# Create test constraint
|
||||||
service.add_constraint("P", "True")
|
service.add_constraint("P", "True")
|
||||||
return model_uuid
|
return model_uuid
|
||||||
|
|
|
||||||
|
|
@ -388,34 +388,84 @@ class Conformance:
|
||||||
|
|
||||||
def match_structures(self):
|
def match_structures(self):
|
||||||
ref_element, = self.bottom.read_outgoing_elements(self.scd_model, "ModelRef")
|
ref_element, = self.bottom.read_outgoing_elements(self.scd_model, "ModelRef")
|
||||||
# match nodes
|
# matching
|
||||||
for m_element, m_name in self.model_names.items():
|
for m_element, m_name in self.model_names.items():
|
||||||
self.candidates[m_name] = set()
|
|
||||||
is_edge = self.bottom.read_edge_source(m_element) is not None
|
is_edge = self.bottom.read_edge_source(m_element) is not None
|
||||||
for type_name, structure in self.structures.items():
|
for type_name, structure in self.structures.items():
|
||||||
tm_element, = self.bottom.read_outgoing_elements(self.type_model, type_name)
|
tm_element, = self.bottom.read_outgoing_elements(self.type_model, type_name)
|
||||||
type_is_edge = self.bottom.read_edge_source(tm_element) is not None
|
type_is_edge = self.bottom.read_edge_source(tm_element) is not None
|
||||||
if is_edge == type_is_edge:
|
if is_edge == type_is_edge:
|
||||||
matched = []
|
matched = 0
|
||||||
for name, optional, attr_type in structure:
|
for name, optional, attr_type in structure:
|
||||||
try:
|
try:
|
||||||
attr, = self.bottom.read_outgoing_elements(self.model, f"{m_name}.{name}")
|
attr, = self.bottom.read_outgoing_elements(self.model, f"{m_name}.{name}")
|
||||||
|
attr_tm, = self.bottom.read_outgoing_elements(self.type_model, attr_type)
|
||||||
# if attribute is a modelref, we need to check whether it
|
# if attribute is a modelref, we need to check whether it
|
||||||
# linguistically conforms to the specified type
|
# linguistically conforms to the specified type
|
||||||
# if its an internlly defined attribute, this will be checked by constraints later
|
# if its an internally defined attribute, this will be checked by constraints
|
||||||
morphisms = self.bottom.read_outgoing_elements(tm_element, "Morphism")
|
morphisms = self.bottom.read_outgoing_elements(attr_tm, "Morphism")
|
||||||
if ref_element in morphisms:
|
if ref_element in morphisms:
|
||||||
pass
|
# check conformance of reference model
|
||||||
|
type_model_uuid = UUID(self.bottom.read_value(attr_tm))
|
||||||
|
model_uuid = UUID(self.bottom.read_value(attr))
|
||||||
|
attr_conforms = Conformance(self.state, self.scd_model, model_uuid, type_model_uuid)\
|
||||||
|
.check_nominal()
|
||||||
|
else:
|
||||||
|
# eval constraints
|
||||||
|
code = self.read_attribute(attr_tm, "constraint")
|
||||||
|
if code is not None:
|
||||||
|
attr_conforms = self.evaluate_constraint(code, element=attr)
|
||||||
|
matched += 1
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
# attr not found or failed parsing UUID
|
||||||
if optional:
|
if optional:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
if len(matched) == len(structure):
|
if matched == len(structure):
|
||||||
self.candidates[m_name].add(type_name)
|
self.candidates.setdefault(m_name, set()).add(type_name)
|
||||||
|
# filter out candidates for links based on source and target types
|
||||||
|
for m_element, m_name in self.model_names.items():
|
||||||
|
is_edge = self.bottom.read_edge_source(m_element) is not None
|
||||||
|
if is_edge and m_name in self.candidates:
|
||||||
|
m_source = self.bottom.read_edge_source(m_element)
|
||||||
|
m_target = self.bottom.read_edge_target(m_element)
|
||||||
|
source_candidates = self.candidates[self.model_names[m_source]]
|
||||||
|
target_candidates = self.candidates[self.model_names[m_target]]
|
||||||
|
remove = set()
|
||||||
|
for candidate_name in self.candidates[m_name]:
|
||||||
|
candidate_element, = self.bottom.read_outgoing_elements(self.type_model, candidate_name)
|
||||||
|
candidate_source = self.type_model_names[self.bottom.read_edge_source(candidate_element)]
|
||||||
|
if candidate_source not in source_candidates:
|
||||||
|
remove.add(candidate_name)
|
||||||
|
candidate_target = self.type_model_names[self.bottom.read_edge_target(candidate_element)]
|
||||||
|
if candidate_target not in target_candidates:
|
||||||
|
remove.add(candidate_name)
|
||||||
|
self.candidates[m_name] = self.candidates[m_name].difference(remove)
|
||||||
|
|
||||||
def build_morphisms(self):
|
def build_morphisms(self):
|
||||||
|
if not all([len(c) == 1 for c in self.candidates.values()]):
|
||||||
|
print("Ambiguous structural matches found, unable to build unique morphism.")
|
||||||
|
return False
|
||||||
|
mapping = {k: v.pop() for k, v in self.candidates.items()}
|
||||||
|
for m_name, tm_name in mapping.items():
|
||||||
|
# morphism to class/assoc
|
||||||
|
m_element, = self.bottom.read_outgoing_elements(self.model, m_name)
|
||||||
|
tm_element, = self.bottom.read_outgoing_elements(self.type_model, tm_name)
|
||||||
|
self.bottom.create_edge(m_element, tm_element, "Morphism")
|
||||||
|
# morphism for attributes and attribute links
|
||||||
|
structure = self.structures[tm_name]
|
||||||
|
for attr_name, _, attr_type in structure:
|
||||||
|
try:
|
||||||
|
# attribute node
|
||||||
|
attr_element, = self.bottom.read_outgoing_elements(self.model, f"{m_name}.{attr_name}")
|
||||||
|
attr_type_element, = self.bottom.read_outgoing_elements(self.type_model, attr_type)
|
||||||
|
self.bottom.create_edge(attr_element, attr_type_element, "Morphism")
|
||||||
|
# attribute link
|
||||||
|
attr_link_element, = self.bottom.read_outgoing_elements(self.model, f"{m_name}.{attr_name}_link")
|
||||||
|
attr_link_type_element, = self.bottom.read_outgoing_elements(self.type_model, f"{tm_name}_{attr_name}")
|
||||||
|
self.bottom.create_edge(attr_link_element, attr_link_type_element, "Morphism")
|
||||||
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -426,6 +476,7 @@ if __name__ == '__main__':
|
||||||
scd = bootstrap_scd(s)
|
scd = bootstrap_scd(s)
|
||||||
from bootstrap.pn import bootstrap_pn
|
from bootstrap.pn import bootstrap_pn
|
||||||
ltm_pn = bootstrap_pn(s, "PN")
|
ltm_pn = bootstrap_pn(s, "PN")
|
||||||
|
ltm_pn_lola = bootstrap_pn(s, "PNlola")
|
||||||
from services.pn import PN
|
from services.pn import PN
|
||||||
my_pn = s.create_node()
|
my_pn = s.create_node()
|
||||||
PNserv = PN(ltm_pn, my_pn, s)
|
PNserv = PN(ltm_pn, my_pn, s)
|
||||||
|
|
@ -435,10 +486,11 @@ if __name__ == '__main__':
|
||||||
PNserv.create_p2t("p1", "t1", 1)
|
PNserv.create_p2t("p1", "t1", 1)
|
||||||
PNserv.create_t2p("t1", "p2", 1)
|
PNserv.create_t2p("t1", "p2", 1)
|
||||||
|
|
||||||
cf = Conformance(s, scd, my_pn, ltm_pn)
|
cf = Conformance(s, scd, my_pn, ltm_pn_lola)
|
||||||
# cf = Conformance(s, scd, ltm_pn, scd)
|
# cf = Conformance(s, scd, ltm_pn, scd)
|
||||||
|
cf.precompute_structures()
|
||||||
|
cf.match_structures()
|
||||||
|
cf.build_morphisms()
|
||||||
print(cf.check_nominal())
|
print(cf.check_nominal())
|
||||||
# cf.precompute_structures()
|
|
||||||
# cf.match_structures()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,11 +52,11 @@ class PN:
|
||||||
name_model = self.bottom.create_node()
|
name_model = self.bottom.create_node()
|
||||||
String(name_model, self.bottom.state).create(name)
|
String(name_model, self.bottom.state).create(name)
|
||||||
name_node = self.bottom.create_node(str(name_model))
|
name_node = self.bottom.create_node(str(name_model))
|
||||||
self.bottom.create_edge(self.model, name_node, f"{name}.n")
|
self.bottom.create_edge(self.model, name_node, f"{name}.name")
|
||||||
name_link = self.bottom.create_edge(transition_node, name_node)
|
name_link = self.bottom.create_edge(transition_node, name_node)
|
||||||
self.bottom.create_edge(self.model, name_link, f"{name}.n_link")
|
self.bottom.create_edge(self.model, name_link, f"{name}.name_link")
|
||||||
ltm_pn_node, = self.bottom.read_outgoing_elements(self.ltm_pn, "String")
|
ltm_pn_node, = self.bottom.read_outgoing_elements(self.ltm_pn, "String")
|
||||||
ltm_pn_link, = self.bottom.read_outgoing_elements(self.ltm_pn, "T_n")
|
ltm_pn_link, = self.bottom.read_outgoing_elements(self.ltm_pn, "T_name")
|
||||||
self.bottom.create_edge(name_node, ltm_pn_node, "Morphism")
|
self.bottom.create_edge(name_node, ltm_pn_node, "Morphism")
|
||||||
self.bottom.create_edge(name_link, ltm_pn_link, "Morphism")
|
self.bottom.create_edge(name_link, ltm_pn_link, "Morphism")
|
||||||
|
|
||||||
|
|
@ -73,11 +73,11 @@ class PN:
|
||||||
weight_model = self.bottom.create_node()
|
weight_model = self.bottom.create_node()
|
||||||
Integer(weight_model, self.bottom.state).create(weight)
|
Integer(weight_model, self.bottom.state).create(weight)
|
||||||
weight_node = self.bottom.create_node(str(weight_model))
|
weight_node = self.bottom.create_node(str(weight_model))
|
||||||
self.bottom.create_edge(self.model, weight_node, f"{place}_to_{transition}.w")
|
self.bottom.create_edge(self.model, weight_node, f"{place}_to_{transition}.weight")
|
||||||
weight_link = self.bottom.create_edge(edge, weight_node)
|
weight_link = self.bottom.create_edge(edge, weight_node)
|
||||||
self.bottom.create_edge(self.model, weight_link, f"{place}_to_{transition}.w_link")
|
self.bottom.create_edge(self.model, weight_link, f"{place}_to_{transition}.weight_link")
|
||||||
scd_node, = self.bottom.read_outgoing_elements(self.ltm_pn, "Integer")
|
scd_node, = self.bottom.read_outgoing_elements(self.ltm_pn, "Integer")
|
||||||
scd_link, = self.bottom.read_outgoing_elements(self.ltm_pn, "P2T_w")
|
scd_link, = self.bottom.read_outgoing_elements(self.ltm_pn, "P2T_weight")
|
||||||
self.bottom.create_edge(weight_node, scd_node, "Morphism")
|
self.bottom.create_edge(weight_node, scd_node, "Morphism")
|
||||||
self.bottom.create_edge(weight_link, scd_link, "Morphism")
|
self.bottom.create_edge(weight_link, scd_link, "Morphism")
|
||||||
|
|
||||||
|
|
@ -94,11 +94,11 @@ class PN:
|
||||||
weight_model = self.bottom.create_node()
|
weight_model = self.bottom.create_node()
|
||||||
Integer(weight_model, self.bottom.state).create(weight)
|
Integer(weight_model, self.bottom.state).create(weight)
|
||||||
weight_node = self.bottom.create_node(str(weight_model))
|
weight_node = self.bottom.create_node(str(weight_model))
|
||||||
self.bottom.create_edge(self.model, weight_node, f"{transition}_to_{place}.w")
|
self.bottom.create_edge(self.model, weight_node, f"{transition}_to_{place}.weight")
|
||||||
weight_link = self.bottom.create_edge(edge, weight_node)
|
weight_link = self.bottom.create_edge(edge, weight_node)
|
||||||
self.bottom.create_edge(self.model, weight_link, f"{transition}_to_{place}.w_link")
|
self.bottom.create_edge(self.model, weight_link, f"{transition}_to_{place}.weight_link")
|
||||||
scd_node, = self.bottom.read_outgoing_elements(self.ltm_pn, "Integer")
|
scd_node, = self.bottom.read_outgoing_elements(self.ltm_pn, "Integer")
|
||||||
scd_link, = self.bottom.read_outgoing_elements(self.ltm_pn, "T2P_w")
|
scd_link, = self.bottom.read_outgoing_elements(self.ltm_pn, "T2P_weight")
|
||||||
self.bottom.create_edge(weight_node, scd_node, "Morphism")
|
self.bottom.create_edge(weight_node, scd_node, "Morphism")
|
||||||
self.bottom.create_edge(weight_link, scd_link, "Morphism")
|
self.bottom.create_edge(weight_link, scd_link, "Morphism")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue