Nominal and structural typing seem to be fully working

This commit is contained in:
Andrei Bondarenko 2021-08-24 23:56:25 +02:00
parent f7430cceff
commit 695ec6132a
3 changed files with 77 additions and 25 deletions

View file

@ -31,10 +31,10 @@ def bootstrap_pn(state: State, model_name: str) -> UUID:
# Create class attributes
service.create_attribute_link("P", "Integer", "t", 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
service.create_attribute_link("P2T", "Integer", "w", False)
service.create_attribute_link("T2P", "Integer", "w", False)
service.create_attribute_link("P2T", "Integer", "weight", False)
service.create_attribute_link("T2P", "Integer", "weight", False)
# Create test constraint
service.add_constraint("P", "True")
return model_uuid

View file

@ -388,35 +388,85 @@ class Conformance:
def match_structures(self):
ref_element, = self.bottom.read_outgoing_elements(self.scd_model, "ModelRef")
# match nodes
# matching
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
for type_name, structure in self.structures.items():
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
if is_edge == type_is_edge:
matched = []
matched = 0
for name, optional, attr_type in structure:
try:
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
# linguistically conforms to the specified type
# if its an internlly defined attribute, this will be checked by constraints later
morphisms = self.bottom.read_outgoing_elements(tm_element, "Morphism")
# if its an internally defined attribute, this will be checked by constraints
morphisms = self.bottom.read_outgoing_elements(attr_tm, "Morphism")
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:
# attr not found or failed parsing UUID
if optional:
continue
else:
break
if len(matched) == len(structure):
self.candidates[m_name].add(type_name)
if matched == len(structure):
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):
pass
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
if __name__ == '__main__':
@ -426,6 +476,7 @@ if __name__ == '__main__':
scd = bootstrap_scd(s)
from bootstrap.pn import bootstrap_pn
ltm_pn = bootstrap_pn(s, "PN")
ltm_pn_lola = bootstrap_pn(s, "PNlola")
from services.pn import PN
my_pn = s.create_node()
PNserv = PN(ltm_pn, my_pn, s)
@ -435,10 +486,11 @@ if __name__ == '__main__':
PNserv.create_p2t("p1", "t1", 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.precompute_structures()
cf.match_structures()
cf.build_morphisms()
print(cf.check_nominal())
# cf.precompute_structures()
# cf.match_structures()

View file

@ -52,11 +52,11 @@ class PN:
name_model = self.bottom.create_node()
String(name_model, self.bottom.state).create(name)
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)
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_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_link, ltm_pn_link, "Morphism")
@ -73,11 +73,11 @@ class PN:
weight_model = self.bottom.create_node()
Integer(weight_model, self.bottom.state).create(weight)
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)
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_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_link, scd_link, "Morphism")
@ -94,11 +94,11 @@ class PN:
weight_model = self.bottom.create_node()
Integer(weight_model, self.bottom.state).create(weight)
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)
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_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_link, scd_link, "Morphism")