cd.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. from services.bottom.V0 import Bottom
  2. from uuid import UUID
  3. class CDAPI:
  4. def __init__(self, state, m: UUID):
  5. self.state = state
  6. self.bottom = Bottom(state)
  7. self.m = m
  8. self.mm = UUID(state.read_value(state.read_dict(state.read_root(), "SCD")))
  9. # pre-compute some things
  10. # element -> name
  11. self.type_model_names = {
  12. self.bottom.read_outgoing_elements(self.m, e)[0]
  13. : e for e in self.bottom.read_keys(self.m)
  14. }
  15. inh_type, = self.bottom.read_outgoing_elements(self.mm, "Inheritance")
  16. inh_links = []
  17. for tm_element, tm_name in self.type_model_names.items():
  18. types = self.bottom.read_outgoing_elements(tm_element, "Morphism")
  19. if inh_type in types:
  20. inh_links.append(tm_element)
  21. # for each inheritance link we add the parent and child to the sub types map
  22. # name -> name
  23. self.direct_sub_types = { type_name: set() for type_name in self.bottom.read_keys(self.m) } # empty initially
  24. self.direct_super_types = { type_name: set() for type_name in self.bottom.read_keys(self.m) } # empty initially
  25. for link in inh_links:
  26. tm_source = self.bottom.read_edge_source(link)
  27. tm_target = self.bottom.read_edge_target(link)
  28. parent_name = self.type_model_names[tm_target]
  29. child_name = self.type_model_names[tm_source]
  30. self.direct_sub_types[parent_name].add(child_name)
  31. self.direct_super_types[child_name].add(parent_name)
  32. def get_transitive_sub_types(type_name: str):
  33. # includes the type itself - reason: if we want to get all the instances of some type and its subtypes, we don't have to consider the type itself as an extra case
  34. return [type_name, *(sub_type for child_name in self.direct_sub_types.get(type_name, set()) for sub_type in get_transitive_sub_types(child_name) )]
  35. def get_transitive_super_types(type_name: str):
  36. # includes the type itself - reason: if we want to check if something is an instance of a type, we check if its type or one of its super types is equal to the type we're looking for, without having to consider the instance's type itself as an extra case
  37. return [type_name, *(super_type for parent_name in self.direct_super_types.get(type_name, set()) for super_type in get_transitive_super_types(parent_name))]
  38. self.transitive_sub_types = { type_name: set(get_transitive_sub_types(type_name)) for type_name in self.direct_sub_types }
  39. self.transitive_super_types = { type_name: set(get_transitive_super_types(type_name)) for type_name in self.direct_super_types }
  40. def get_type(type_name: str):
  41. return self.bottom.read_outgoing_elements(self.m, type_name)[0]
  42. def is_direct_subtype(super_type_name: str, sub_type_name: str):
  43. return sub_type_name in self.direct_sub_types[super_type]
  44. def is_direct_supertype(sub_type_name: str, super_type_name: str):
  45. return super_type_name in self.direct_super_types[sub_type_name]
  46. def is_subtype(super_type_name: str, sub_type_name: str):
  47. return sub_type_name in self.transitive_sub_types[super_type]
  48. def is_supertype(sub_type_name: str, super_type_name: str):
  49. return super_type_name in self.transitive_super_types[sub_type_name]
  50. # # The edge connecting an object to the value of a slot must be named `{object_name}_{attr_name}`
  51. # def get_attr_link_name(self, class_name, attr_name):
  52. # assoc_name = f"{class_name}_{attr_name}"
  53. # type_edges = self.bottom.read_outgoing_elements(self.m, assoc_name)
  54. # if len(type_edges) == 1:
  55. # return assoc_name
  56. # else:
  57. # # look for attribute in the super-types
  58. # conf = Conformance(self.bottom.state, self.model, self.type_model)
  59. # conf.precompute_sub_types() # only need to know about subtypes
  60. # super_types = [s for s in conf.sub_types if class_name in conf.sub_types[s]]
  61. # for s in super_types:
  62. # assoc_name = f"{s}_{attr_name}"
  63. # if len(self.bottom.read_outgoing_elements(self.type_model, assoc_name)) == 1:
  64. # return assoc_name
  65. # Attributes are inherited, so when we instantiate an attribute of a class, the AttributeLink may contain the name of the superclass
  66. def find_attribute_type(self, class_name: str, attr_name: str):
  67. assoc_name = f"{class_name}_{attr_name}"
  68. type_edges = self.bottom.read_outgoing_elements(self.m, assoc_name)
  69. if len(type_edges) == 1:
  70. return type_edges[0]
  71. else:
  72. for supertype in self.direct_super_types[class_name]:
  73. result = self.find_attribute_type(supertype, attr_name)
  74. if result != None:
  75. return result