From ae97a52c1e4adb680d4aca553a742279f76528c9 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Thu, 16 Nov 2023 21:58:42 +0100 Subject: Remove unused Morph and Obj, use equations --- Makefile | 2 +- src/act4e_solutions/semicategory_representation.py | 70 +++++++++++++--------- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index 084e1f5..300e14b 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ build: docker build -f Dockerfile --build-arg DOCKER_REGISTRY=${DOCKER_REGISTRY} -t $(tag) . docker-check: build - docker run -it --rm -v $(PWD)/out-results:/ACT4E/out-results $(tag) \ + docker run -it --rm $(tag) \ act4e-test --collections act4e_checks --module act4e_solutions diff --git a/src/act4e_solutions/semicategory_representation.py b/src/act4e_solutions/semicategory_representation.py index d6977bc..9012c4f 100644 --- a/src/act4e_solutions/semicategory_representation.py +++ b/src/act4e_solutions/semicategory_representation.py @@ -6,7 +6,7 @@ from act4e_interfaces import EnumerableSet from .sets_representation import MyFiniteSet from dataclasses import dataclass -from functools import partial +from functools import reduce from itertools import product @@ -18,22 +18,11 @@ ROD = I.RichObject[OD] RMD = I.RichMorphism[MD] -@dataclass(frozen=True) -class Morph(I.RichMorphism[MD]): - source: str - target: str - - -@dataclass(frozen=True) -class Obj(I.RichObject[OD]): - identity: Optional[Morph] - - class MySemiCategory(Generic[OD, MD], I.SemiCategory[ROD, RMD]): - _objects: Dict[str, Obj] - _morphisms: Dict[int, Dict[Tuple[str, str], List[Morph]]] + _objects: Dict[str, ROD] + _morphisms: Dict[int, Dict[Tuple[str, str], List[RMD]]] _composition: Callable[[OD, OD, OD, MD], MD] - _equations: Dict[List[str], str] + _equations: Dict[str, List[str]] def __init__( self, @@ -45,20 +34,20 @@ class MySemiCategory(Generic[OD, MD], I.SemiCategory[ROD, RMD]): self._composition = composition self._equations = equations - def add_object(self, ob: Obj): + def add_object(self, ob: ROD): self._objects[ob.label] = ob - def add_morphism(self, mor: Morph): - if not (mor.source, mor.target) in self._morphisms[0].keys(): - self._morphisms[0][(mor.source, mor.target)] = [] - self._morphisms[0][(mor.source, mor.target)].append(mor) + def add_morphism(self, source: str, target: str, mor: RMD): + if not (source, target) in self._morphisms[0].keys(): + self._morphisms[0][source, target] = [] + self._morphisms[0][(source, target)].append(mor) def objects(self, uptolevel: Optional[int] = None) -> EnumerableSet[ROD]: return MyFiniteSet(self._objects.values()) def hom(self, ob1: ROD, ob2: ROD, uptolevel: Optional[int] = None) -> EnumerableSet[RMD]: def all_morphisms(source, target, lvl): - """ return all morphisms up to level lvl """ + """ return all morphisms up to level lvl: """ # Base case, for level zero return given morphisms if lvl <= 0: return self._morphisms[0].get((source, target), []) @@ -75,12 +64,33 @@ class MySemiCategory(Generic[OD, MD], I.SemiCategory[ROD, RMD]): # Build all possible compositions not_id = lambda m: not m.label.startswith("id_") for f, g in product(filter(not_id, fs), filter(not_id, gs)): + # Compose the morphisms source_ob = self._objects[source] target_ob = self._objects[target] h = self.compose(source_ob, interm_ob, target_ob, f, g) + # Create entry in cache if not present if (source, target) not in self._morphisms[lvl]: self._morphisms[lvl][source, target] = [] + + # If the composition is in an equation have to replace it + if h.label in self._equations.keys(): + # Find the morphisms that compose the right hand side + rhs_morphisms = [] + for (s, d), mors in self._morphisms[0].items(): + for mor, f in product(mors, self._equations[h.label]): + if mor.label == f: + rhs_morphisms.append((s, d, mor)) + + # Build the RHS rich morphism object + compose = lambda m1, m2: self.compose(m1[0], m1[1], m2[0], m1[2], m2[2]) + _, _, rhs = reduce(compose, rhs_morphisms[1:], rhs_morphisms[0]) + + # Save this one instead of h + self._morphisms[lvl][source, target].append(rhs) + continue + + # Save the new morphism self._morphisms[lvl][source, target].append(h) # Compute the union @@ -95,7 +105,7 @@ class MySemiCategory(Generic[OD, MD], I.SemiCategory[ROD, RMD]): def compose(self, ob1: ROD, ob2: ROD, ob3: ROD, m1: RMD, m2: RMD) -> RMD: m3 = self._composition(ob1.obdata, ob2.obdata, ob3.obdata, m1.mordata, m2.mordata) - return Morph(";".join((m1.label, m2.label)), m3, ob1.label, ob2.label) + return I.RichMorphism(";".join((m1.label, m2.label)), m3) def identity(self, ob: ROD) -> RMD: if not self._objects[ob.label]: @@ -116,19 +126,23 @@ class SolSemiCategoryRepresentation(I.SemiCategoryRepresentation): if not all(k in data.keys() for k in ["objects", "morphisms", "equations"]): raise I.InvalidFormat() - sc = MySemiCategory(compose, data["equations"]) + equations = {} + for eq_name, eq in data["equations"].items(): + lhs, rhs = eq.split("=") + equations[lhs] = rhs.split(";") + + sc = MySemiCategory(compose, equations) # Get the objects for obname, ob in data["objects"].items(): if not "obdata" in ob.keys(): raise I.InvalidFormat() - identity = None if "identity" in ob.keys() and ob["identity"]: - identity = Morph(f"id_{obname}", ob["identity"]["mordata"], obname, obname) - sc.add_morphism(identity) + identity = I.RichMorphism(f"id_{obname}", ob["identity"]["mordata"]) + sc.add_morphism(obname, obname, identity) - sc.add_object(Obj(obname, ob["obdata"], identity)) + sc.add_object(I.RichObject(obname, ob["obdata"])) # Get the morphisms for morname, mor in data["morphisms"].items(): @@ -136,6 +150,6 @@ class SolSemiCategoryRepresentation(I.SemiCategoryRepresentation): raise I.InvalidFormat() src, tar = mor["source"], mor["target"] - sc.add_morphism(Morph(morname, mor["mordata"], mor["source"], mor["target"])) + sc.add_morphism(mor["source"], mor["target"], I.RichMorphism(morname, mor["mordata"])) return sc -- cgit v1.2.1