cd.py 4.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  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. # The transitive sub-/super-types of every type includes the type itself.
  39. # This is because, often we want to know if an instance's type is 'compatible' (substitutible) with a specified type.
  40. self.transitive_sub_types = { type_name: set(get_transitive_sub_types(type_name)) for type_name in self.direct_sub_types }
  41. self.transitive_super_types = { type_name: set(get_transitive_super_types(type_name)) for type_name in self.direct_super_types }
  42. def get(self, type_name: str):
  43. return self.bottom.read_outgoing_elements(self.m, type_name)[0]
  44. def is_direct_subtype(self, super_type_name: str, sub_type_name: str):
  45. return sub_type_name in self.direct_sub_types[super_type_name]
  46. def is_direct_supertype(self, sub_type_name: str, super_type_name: str):
  47. return super_type_name in self.direct_super_types[sub_type_name]
  48. # Note: according to this function, every class is a subtype of itself
  49. def is_subtype(self, super_type_name: str, sub_type_name: str):
  50. return sub_type_name in self.transitive_sub_types[super_type_name]
  51. # Note: according to this function, every class is a supertype of itself
  52. def is_supertype(self, sub_type_name: str, super_type_name: str):
  53. return super_type_name in self.transitive_super_types[sub_type_name]
  54. # # The edge connecting an object to the value of a slot must be named `{object_name}_{attr_name}`
  55. def get_attr_link_name(self, class_name, attr_name):
  56. attr_type_link = self.find_attribute_type(class_name, attr_name)
  57. if attr_type_link != None:
  58. return self.type_model_names[attr_type_link]
  59. # Attributes are inherited, so when we instantiate an attribute of a class, the AttributeLink may contain the name of the superclass
  60. def find_attribute_type(self, class_name: str, attr_name: str):
  61. assoc_name = f"{class_name}_{attr_name}"
  62. type_edges = self.bottom.read_outgoing_elements(self.m, assoc_name)
  63. if len(type_edges) == 1:
  64. return type_edges[0]
  65. else:
  66. for supertype in self.direct_super_types[class_name]:
  67. result = self.find_attribute_type(supertype, attr_name)
  68. if result != None:
  69. return result
  70. def get_type(self, type_name: str):
  71. return next(k for k, v in self.type_model_names.items() if v == type_name)