From 47dea1ad2905652588eb5d187b26d945ff0ac965 Mon Sep 17 00:00:00 2001
From: cha <charles.paperman@univ-lille.fr>
Date: Sat, 1 Jun 2024 15:34:41 +0200
Subject: [PATCH] Improvement into class method

---
 data/classes/algebras/commutative.typed.yaml |  2 +-
 pysemigroup/algebra/__init__.py              |  8 +-
 pysemigroup/algebra/algebra_base.py          | 94 ++++++++++++++------
 pysemigroup/algebra/associativity.py         | 92 ++++++++-----------
 pysemigroup/algebra/morphism.py              | 44 +++++----
 pysemigroup/algebra/with_identity.py         | 57 ++----------
 pysemigroup/datamodel/files.py               | 44 +++------
 7 files changed, 156 insertions(+), 185 deletions(-)

diff --git a/data/classes/algebras/commutative.typed.yaml b/data/classes/algebras/commutative.typed.yaml
index 4f669b5..5810cb9 100644
--- a/data/classes/algebras/commutative.typed.yaml
+++ b/data/classes/algebras/commutative.typed.yaml
@@ -22,4 +22,4 @@ algo:
                 def cond(G):
                     return G.is_J_trivial()
             algo: ...
-        # Be default, uses the first appliable equation 
\ No newline at end of file
+        # Be default, uses the first appliable equation 
diff --git a/pysemigroup/algebra/__init__.py b/pysemigroup/algebra/__init__.py
index cc6bf5c..d336978 100644
--- a/pysemigroup/algebra/__init__.py
+++ b/pysemigroup/algebra/__init__.py
@@ -1,7 +1,7 @@
 from typing import Type, TypeVar
 
 from pysemigroup.algebra import associativity, inversible, with_identity
-from pysemigroup.algebra.algebra_base import FreeAlgebraBase, FiniteAlgebraBase
+from pysemigroup.algebra.algebra_base import FiniteAlgebraBase, FreeAlgebraBase
 
 __all__ = ["associativity", "with_identity", "inversible"]
 
@@ -11,6 +11,6 @@ for A in (FreeAlgebraBase, FiniteAlgebraBase):
         local_scope[cls.__name__] = cls
         __all__.append(cls.__name__)
 
-FiniteAlgebra : TypeVar = Type[FiniteAlgebraBase]
-FreeAlgebra : TypeVar = Type[FreeAlgebraBase]
-Algebra : TypeVar = FiniteAlgebra | FreeAlgebra
+FiniteAlgebra: TypeVar = Type[FiniteAlgebraBase]
+FreeAlgebra: TypeVar = Type[FreeAlgebraBase]
+Algebra: TypeVar = FiniteAlgebra | FreeAlgebra
diff --git a/pysemigroup/algebra/algebra_base.py b/pysemigroup/algebra/algebra_base.py
index 460ea07..cae832d 100644
--- a/pysemigroup/algebra/algebra_base.py
+++ b/pysemigroup/algebra/algebra_base.py
@@ -2,6 +2,7 @@ from abc import ABC, abstractmethod, abstractproperty
 from collections.abc import Collection, Iterable
 from dataclasses import dataclass
 from itertools import product
+from operator import mul
 from typing import (
     Callable,
     Generic,
@@ -13,6 +14,7 @@ from typing import (
     TypeAlias,
     TypeVar,
     cast,
+    ClassVar
 )
 
 import networkx as nx
@@ -91,8 +93,9 @@ class Element(Generic[LabelType], Hashable):
             return f"{self.algebra}({self.arrow.label})"
         return f"{self.algebra}({self.arrow.source}, {self.arrow.label}, {self.arrow.target})"
 
+
 class AlgebraBase(Generic[InputType, LabelType], ABC):
-    """ A Base class for Algebra """
+    """A Base class for Algebra"""
 
     is_typed: bool = True
     is_free: bool = False
@@ -113,7 +116,6 @@ class AlgebraBase(Generic[InputType, LabelType], ABC):
     @abstractmethod
     def element_factory(self, e: InputType) -> Element[LabelType]: ...
 
-
     @abstractmethod
     def multiplication(
         self,
@@ -122,7 +124,7 @@ class AlgebraBase(Generic[InputType, LabelType], ABC):
     ) -> Element[LabelType]: ...
 
     @abstractproperty
-    def type_graph(self) -> nx.DiGraph: ...
+    def type_graph(self) -> nx.MultiDiGraph: ...
 
     @property
     def objects(self) -> Iterable[Hashable]:
@@ -139,12 +141,45 @@ class AlgebraBase(Generic[InputType, LabelType], ABC):
         raise ValueError(f"{type(self)} do not admit identity")
 
     @classmethod
-    @abstractmethod
-    def typed_version(cls) -> type: ...
+    def typed_version(cls) -> Type["AlgebraBase"]:
+        if cls.is_free:
+            for ocls in FreeAlgebraBase.subclasses:
+                if ocls.is_typed and ocls.__module__ == cls.__module__:
+                    return ocls
+        else:
+            for ocls in FiniteAlgebraBase.subclasses:
+                if ocls.is_typed and ocls.__module__ == cls.__module__:
+                    return ocls
+        assert False
 
     @classmethod
-    @abstractmethod
-    def untyped_version(cls) -> type: ...
+    def untyped_version(cls) -> Type["AlgebraBase"]:
+        if cls.is_free:
+            for ocls in FreeAlgebraBase.subclasses:
+                if not ocls.is_typed and ocls.__module__ == cls.__module__:
+                    return ocls
+        else:
+            for ocls in FiniteAlgebraBase.subclasses:
+                if not ocls.is_typed and ocls.__module__ == cls.__module__:
+                    return ocls
+        assert False
+
+    @classmethod
+    def to_free(cls) -> Type["FreeAlgebraBase"]:
+        if cls.is_free:
+            return cls
+        for ocls in FreeAlgebraBase.subclasses:
+            if cls.is_typed == ocls.is_typed and cls.__module__ == ocls.__module__:
+                return ocls
+        assert False
+
+    def to_finite(cls) -> Type["FiniteAlgebraBase"]:
+        if not cls.is_free:
+            return cls
+        for ocls in FiniteAlgebraBase.subclasses:
+            if cls.is_typed == ocls.is_typed and cls.__module__ == ocls.__module__:
+                return ocls
+        assert False
 
     @classmethod
     def to_typed(cls, el: Self):
@@ -182,22 +217,22 @@ FreePath: TypeAlias = Arrow[FreePathLabel]
 
 
 class FreeAlgebraBase(Generic[InputType], AlgebraBase[InputType, FreePathLabel]):
-    """ A Base class for free algebra """
+    """A Base class for free algebra"""
 
-    is_free = True
-    subclasses: list[Type[Self]] = []
+    is_free : ClassVar[bool] = True
+    subclasses: ClassVar[list[Type[Self]]] = []
 
     def __init_subclass__(cls, **kwargs):
         super().__init_subclass__(**kwargs)
         cls.subclasses.append(cls)
 
     @property
-    def type_graph(self) -> nx.DiGraph:
+    def type_graph(self) -> nx.MultiDiGraph:
         if hasattr(self, "_type_graph"):
             return self._type_graph
-        G: nx.DiGraph = nx.DiGraph()
+        G: nx.MultiDiGraph = nx.MultiDiGraph()
         G.add_edges_from((e.source, e.target, dict(e=None)) for e in self.generators)
-        self._type_graph: nx.DiGraph = G
+        self._type_graph: nx.MultiDiGraph = G
         return G
 
     def multiplication(
@@ -213,9 +248,9 @@ class FreeAlgebraBase(Generic[InputType], AlgebraBase[InputType, FreePathLabel])
         return Element(arrow, self)
 
     @abstractmethod
-    def deconstruct(self, e: Element[FreePathLabel]) -> tuple[Element[FreePathLabel],...]:
-        ...
-        
+    def deconstruct(
+        self, e: Element[FreePathLabel],
+    ) -> tuple[Element[FreePathLabel], ...]: ...
 
     def __iter__(self) -> Iterable[Element[FreePathLabel]]:
         raise NotImplementedError
@@ -234,9 +269,10 @@ class FreeAlgebraBase(Generic[InputType], AlgebraBase[InputType, FreePathLabel])
 
 
 class FiniteAlgebraBase(Sized, AlgebraBase[InputType, Hashable]):
-    """ A Base class for finite algebra """
-    is_free = False
-    subclasses: list[Type[Self]] = []
+    """A Base class for finite algebra"""
+
+    is_free : ClassVar[bool] = False
+    subclasses: ClassVar[list[Type[Self]]] = []
 
     def __init_subclass__(cls, **kwargs):
         super().__init_subclass__(**kwargs)
@@ -249,9 +285,9 @@ class FiniteAlgebraBase(Sized, AlgebraBase[InputType, Hashable]):
     def __init__(
         self,
         generators: Iterable[InputType],
-        multiplication: Callable[[InputType, InputType], InputType],
+        multiplication: Callable[[InputType, InputType], InputType] = mul,
     ):
-        self._cache_element = {}
+        self._cache_element: dict[InputType, Element[Hashable]] = {}
         super().__init__(generators)
         self._base_multiplication = multiplication
         self._to_base = dict(self._to_base_generators)
@@ -276,7 +312,7 @@ class FiniteAlgebraBase(Sized, AlgebraBase[InputType, Hashable]):
                         continue
                     remain.add(hg)
                     self._representant[hg] = self._representant[new_element] + (g,)
-        self._left_cayley: nx.DiGraph = nx.DiGraph()
+        self._left_cayley: nx.MultiDiGraph = nx.MultiDiGraph()
         for x in elements:
             for g in self.generators:
                 if g.is_compatible(x):
@@ -307,7 +343,7 @@ class FiniteAlgebraBase(Sized, AlgebraBase[InputType, Hashable]):
         G: nx.MultiDiGraph = nx.MultiDiGraph()
         for e in self:
             G.add_edge(e.arrow.source, e.arrow.target, e=e)
-        self._type_graph: nx.DiGraph = G
+        self._type_graph: nx.MultiDiGraph = G
         return G
 
     def elements_between(self, t, u):
@@ -347,10 +383,12 @@ class FiniteAlgebraBase(Sized, AlgebraBase[InputType, Hashable]):
         cls = type(self).meet_class(type(other))
         self = cls.from_(self)
         other = cls.from_(other)
-        new_gen =  ((g,h) for g in self.generators for h in other.generators)
-        def new_mul(x,y):
-            (x1,x2), (y1,y2) = x, y
-            return (x1*y1, x2*y2)
+        new_gen = ((g, h) for g in self.generators for h in other.generators)
+
+        def new_mul(x, y):
+            (x1, x2), (y1, y2) = x, y
+            return (x1 * y1, x2 * y2)
+
         if cls.has_identity:
             cls(new_gen, new_mul, (self.identity(), other.identity()))
         return cls(new_gen, new_mul)
@@ -373,7 +411,7 @@ class FiniteAlgebraBase(Sized, AlgebraBase[InputType, Hashable]):
         return cls(**states)
 
     def sub_algebra_generated_by(
-        self, some_element: Iterable[Element[Hashable]]
+        self, some_element: Iterable[Element[Hashable]],
     ) -> Self:
         state = self.__get_state__()
         state["generators"] = some_element
diff --git a/pysemigroup/algebra/associativity.py b/pysemigroup/algebra/associativity.py
index 2ee8a8a..6ff92f6 100644
--- a/pysemigroup/algebra/associativity.py
+++ b/pysemigroup/algebra/associativity.py
@@ -1,7 +1,7 @@
 from collections.abc import Sized
 from functools import cached_property
 from itertools import chain
-from typing import Callable, Hashable, cast, Iterable
+from typing import Callable, Hashable, Iterable, Type, cast
 
 from pysemigroup.algebra.algebra_base import (
     Arrow,
@@ -15,24 +15,12 @@ from pysemigroup.views import ElementView, ω
 
 class FiniteSemigroup(FiniteAlgebraBase[Hashable]):
     is_typed = False
-    
+
     def element_factory(self, e: Hashable) -> Element:
         if e not in self._cache_element:
             self._cache_element[e] = Element(Arrow(e, 0, 0), self)
         return self._cache_element[e]
 
-    @classmethod
-    def typed_version(cls) -> type:
-        return FiniteSemigroupoid
-
-    @classmethod
-    def untyped_version(cls) -> type:
-        return FiniteSemigroup
-
-    @classmethod
-    def to_free(cls) -> type:
-        return FreeSemigroupoid
-
     def compute_identity(self):
         for g in self.generators:
             if (g**ω).is_identity():
@@ -58,76 +46,68 @@ class FiniteSemigroupoid(FiniteAlgebraBase[Arrow], Sized):
 
     def consolidate(self) -> FiniteSemigroup:
         new_gen = chain(self.generators, (0,))
-        def new_mul(x,y):
-            if x==0 or y==0 or not x.is_compatible(y):
+
+        def new_mul(x, y):
+            if x == 0 or y == 0 or not x.is_compatible(y):
                 return 0
-            return x*y
+            return x * y
+
         return self.untyped_version().from_(FiniteSemigroup(new_gen, new_mul))
 
-    def idempotent_category(self) -> "FiniteCategory":
-        from pysemigroup.algebra.with_identity import FiniteCategory
+    def idempotent_category(self) -> Type["FiniteSemigroupoid"]:
+        FiniteCategory = self.to_untype()
         if self.has_inverse:
             return self
-        new_objects = [ (t,e.arrow.label) for t in self.type_graph for e in self.local_semigroup(t).idempotents ]
-        new_gen = set(( Arrow(e*x*f, (t,e), (u,f)) for (t,e) in new_objects for (u,f) in new_objects for x in self.elements_between(t,u) ))
-        new_id = ( Arrow(e, (t,e), (t,e)) for (t,e) in new_objects )
-        def new_mul(x,y):
-            return Arrow(x.label*y.label, x.source, y.target)
-        return FiniteCategory(new_gen, new_mul, new_id)
+        new_objects = [
+            (t, e.arrow.label)
+            for t in self.type_graph
+            for e in self.local_semigroup(t).idempotents
+        ]
+        new_gen = set(
+
+                Arrow(e * x * f, (t, e), (u, f))
+                for (t, e) in new_objects
+                for (u, f) in new_objects
+                for x in self.elements_between(t, u)
 
-    @classmethod
-    def to_free(cls) -> type:
-        return FreeSemigroupoid
+        )
+        new_id = (Arrow(e, (t, e), (t, e)) for (t, e) in new_objects)
 
-    @classmethod
-    def typed_version(cls) -> type:
-        return FiniteSemigroupoid
+        def new_mul(x, y):
+            return Arrow(x.label * y.label, x.source, y.target)
 
-    @classmethod
-    def untyped_version(cls) -> type:
-        return FiniteSemigroup
+        return FiniteCategory(new_gen, new_mul, new_id)
 
     def local_semigroup(self, t: Hashable) -> FiniteSemigroup:
         multiplication = cast(
-            Callable[[Hashable, Hashable], Hashable], self.multiplication
+            Callable[[Hashable, Hashable], Hashable], self.multiplication,
         )
-        return FiniteSemigroup(self.elements_between(t,t), multiplication)
+        return FiniteSemigroup(self.elements_between(t, t), multiplication)
 
     def iter_local_semigroups(self) -> Iterable[FiniteSemigroup]:
         for t in self.type_graph:
             yield self.local_semigroup(t)
 
+
 class FreeSemigroup(FreeAlgebraBase[Hashable]):
     is_typed = False
 
     def element_factory(self, a: Hashable) -> Element[FreePathLabel]:
         return Element(Arrow((Arrow(a, 0, 0),), 0, 0), self)
 
-    def deconstruct(self, e: Element[FreePathLabel]) -> tuple[Element[FreePathLabel],...]:
-        return tuple(map(lambda g:self.element_factory(g.label), e.arrow.label))
-
-    @classmethod
-    def typed_version(cls) -> type:
-        return FreeSemigroupoid
-
-    @classmethod
-    def untyped_version(cls) -> type:
-        return FreeSemigroup
+    def deconstruct(
+        self, e: Element[FreePathLabel],
+    ) -> tuple[Element[FreePathLabel], ...]:
+        return tuple(map(lambda g: self.element_factory(g.label), e.arrow.label))
 
 
 class FreeSemigroupoid(FreeAlgebraBase[Arrow[Hashable]]):
     is_typed = True
 
-    @classmethod
-    def typed_version(cls) -> type:
-        return FreeSemigroupoid
-
-    @classmethod
-    def untyped_version(cls) -> type:
-        return FreeSemigroup
-
     def element_factory(self, a: Arrow[Hashable]) -> Element[FreePathLabel]:
         return Element(Arrow((a,), 0, 0), self)
 
-    def deconstruct(self, e: Element[FreePathLabel]) -> tuple[Element[FreePathLabel],...]:
-        return tuple(map(lambda g:self.element_factory(g), e.arrow.label))
+    def deconstruct(
+        self, e: Element[FreePathLabel],
+    ) -> tuple[Element[FreePathLabel], ...]:
+        return tuple(map(lambda g: self.element_factory(g), e.arrow.label))
diff --git a/pysemigroup/algebra/morphism.py b/pysemigroup/algebra/morphism.py
index c72c2f9..81de9e2 100644
--- a/pysemigroup/algebra/morphism.py
+++ b/pysemigroup/algebra/morphism.py
@@ -1,11 +1,14 @@
-from typing import Hashable, Mapping, Self, Iterable, Callable
 from functools import reduce
-from pysemigroup.algebra.algebra_base import FiniteAlgebraBase, Element, AlgebraBase
+from typing import Callable, Hashable, Iterable, Mapping, Self
+
+from pysemigroup.algebra.algebra_base import AlgebraBase, Element, FiniteAlgebraBase
 from pysemigroup.automata import DFA
 
+
 def multiply(x: Iterable[Element]):
     it = iter(x)
-    return reduce(lambda e,f: e*f, it, next(iter(it)))
+    return reduce(lambda e, f: e * f, it, next(iter(it)))
+
 
 class Morphism:
     def __init__(
@@ -56,18 +59,24 @@ class Morphism:
 
         return type(self)(mapping, self.obj_mapping)
 
+
 class Stamp:
     finite_algebra = None
 
-    def __init__(self, descr: dict[Hashable, Hashable], multiplication: Callable[[Hashable, Hashable], Hashable], *args):
+    def __init__(
+        self,
+        descr: dict[Hashable, Hashable],
+        multiplication: Callable[[Hashable, Hashable], Hashable],
+        *args,
+    ):
         M = self.finite_algebra(descr.values(), multiplication, *args)
         F = self.finite_algebra.to_free()(descr.keys())
-        self.key_mapping = { a: F.element_factory(a) for a in descr }
-        self.key_mapping_rev = { r:a for a,r in descr.items() }
-        self.value_mapping = { v: M.element_factory(v) for v in descr.values() }
-        self.value_mapping_rev = { t:v  for v,t in self.value_mapping.items() }
+        self.key_mapping = {a: F.element_factory(a) for a in descr}
+        self.key_mapping_rev = {r: a for a, r in descr.items()}
+        self.value_mapping = {v: M.element_factory(v) for v in descr.values()}
+        self.value_mapping_rev = {t: v for v, t in self.value_mapping.items()}
 
-        mapping = { self.key_mapping[v]: self.value_mapping[k] for v,k in descr.items()}
+        mapping = {self.key_mapping[v]: self.value_mapping[k] for v, k in descr.items()}
         self.morphism = Morphism.from_mapping(mapping)
 
     def __call__(self, u: tuple[Hashable, ...]) -> Hashable:
@@ -79,15 +88,20 @@ class Stamp:
 
     def to_regular_language(self, P: Iterable[Hashable]):
         from pysemigroup.regular_language import RegularLanguage
-        transitions = ((source, self.key_mapping_rev[self.value_mapping_rev[g]], target) for (source, target, g) in self.codomain._right_cayley.edges(data="g"))
+
+        transitions = (
+            (source, self.key_mapping_rev[self.value_mapping_rev[g]], target)
+            for (source, target, g) in self.codomain._right_cayley.edges(data="g")
+        )
         assert set(P).issubset(self.codomain)
         return RegularLanguage(DFA(transitions, self.codomain.identity, P))
-        
-l = locals()
+
+
+loc = locals()
 __all__ = []
 for alg in FiniteAlgebraBase.subclasses:
     name = f"{alg.__name__}Stamp"
-    l[name] = type(name, (Stamp,), dict(finite_algebra=alg))
+    loc[name] = type(name, (Stamp,), dict(finite_algebra=alg))
     __all__.append(alg)
-    
-del l
+
+del loc
diff --git a/pysemigroup/algebra/with_identity.py b/pysemigroup/algebra/with_identity.py
index a98bd2f..1d19c44 100644
--- a/pysemigroup/algebra/with_identity.py
+++ b/pysemigroup/algebra/with_identity.py
@@ -1,10 +1,9 @@
-from typing import Hashable, Mapping, Iterable, Callable
+from typing import Callable, Hashable, Iterable, Mapping
 
 from pysemigroup.algebra.algebra_base import Arrow, Element, FreePathLabel
 from pysemigroup.algebra.associativity import (
     FiniteSemigroup,
     FiniteSemigroupoid,
-    FreePathLabel,
     FreeSemigroup,
     FreeSemigroupoid,
 )
@@ -17,14 +16,6 @@ class FreeMonoid(FreeSemigroup):
         assert t == 0
         return Element(Arrow((), 0, 0), self)
 
-    @classmethod
-    def typed_version(cls) -> type:
-        return FreeCategory
-
-    @classmethod
-    def untyped_version(cls) -> type:
-        return FreeMonoid
-
 
 class FreeCategory(FreeSemigroupoid):
     has_identity = True
@@ -33,14 +24,6 @@ class FreeCategory(FreeSemigroupoid):
         assert t in self.objects
         return Element(Arrow((), t, t), self)
 
-    @classmethod
-    def typed_version(cls) -> type:
-        return FreeCategory
-
-    @classmethod
-    def untyped_version(cls) -> type:
-        return FreeMonoid
-
 
 class FiniteMonoid(FiniteSemigroup):
     has_identity = True
@@ -49,9 +32,9 @@ class FiniteMonoid(FiniteSemigroup):
         self,
         generators: Iterable[Hashable],
         multiplication: Callable[[Hashable, Hashable], Hashable],
-        identity: Hashable
+        identity: Hashable,
     ):
-        generators = tuple(generators) 
+        generators = tuple(generators)
         super().__init__(generators, multiplication)
         self._to_base[self.element_factory(identity)] = identity
         self._base_identity = identity
@@ -64,18 +47,6 @@ class FiniteMonoid(FiniteSemigroup):
         t["identity"] = self._base_identity
         return t
 
-    @classmethod
-    def typed_version(cls) -> type:
-        return FiniteCategory
-
-    @classmethod
-    def untyped_version(cls) -> type:
-        return FiniteMonoid
-
-    @classmethod
-    def to_free(cls) -> type:
-        return FreeMonoid
-
 
 class FiniteCategory(FiniteSemigroupoid):
     has_identity = True
@@ -84,17 +55,16 @@ class FiniteCategory(FiniteSemigroupoid):
         self,
         generators: Iterable[Arrow],
         multiplication: Callable[[Arrow, Arrow], Arrow],
-        identities: Iterable[Arrow]
+        identities: Iterable[Arrow],
     ):
-
         super().__init__(generators, multiplication)
         self._base_identities = identities
         identities_dict: Mapping[Hashable, Arrow[Hashable]] = dict()
         for t in identities:
             assert t.source == t.target
-            d[t.source] = self._to_base[t] = self.element_factory(t)
-            
-        self._identities = identities_dict 
+            identities_dict[t.source] = self._to_base[t] = self.element_factory(t)
+
+        self._identities = identities_dict
 
     def identity(self, t: Hashable = 0) -> Element:
         ident = self._identities[t]
@@ -106,22 +76,9 @@ class FiniteCategory(FiniteSemigroupoid):
         t["identities"] = self._base_identities
         return t
 
-
     def local_monoid(self, t) -> FiniteMonoid:
         return FiniteMonoid(
             generators=self.type_graph[t][t],
             multiplication=self.multiplication,
             identity=self.identity(t),
         )
-
-    @classmethod
-    def typed_version(cls) -> type:
-        return FiniteCategory
-
-    @classmethod
-    def untyped_version(cls) -> type:
-        return FiniteMonoid
-
-    @classmethod
-    def to_free(cls) -> type:
-        return FreeCategory
diff --git a/pysemigroup/datamodel/files.py b/pysemigroup/datamodel/files.py
index fbb648f..b5ed7e3 100755
--- a/pysemigroup/datamodel/files.py
+++ b/pysemigroup/datamodel/files.py
@@ -17,6 +17,19 @@ InitTuple = Annotated[
     Tuple[SomeType, ...], PlainValidator(lambda v: () if v is None else v)
 ]
 
+PathToClassAlgebras = Annotated[
+    Path, PlainValidator(lambda v: Path("classes/algebras/", v))
+]
+
+PathToClassLanguages = Annotated[
+    Path, PlainValidator(lambda v: Path("classes/languages/", v))
+]
+PathToClassLogic = Annotated[Path, PlainValidator(lambda v: Path("classes/logic/", v))]
+PathToOperator = Annotated[Path, PlainValidator(lambda v: Path("operators/", v))]
+PathToBinaryOperator = Annotated[
+    Path, PlainValidator(lambda v: Path("binary_operators/", v))
+]
+PathToPredicate = Annotated[Path, PlainValidator(lambda v: Path("predicates/", v))]
 
 class Monad(Enum):
     Semigroups = "Semigroups"
@@ -32,55 +45,24 @@ class Monad(Enum):
 class CommentedField(BaseModel):
     comment: str | None = None
 
-
-PathToClassAlgebras = Annotated[
-    Path, PlainValidator(lambda v: Path("classes/algebras/", v))
-]
-
-
 class PointerToClassAlgebras(CommentedField):
     pointer: PathToClassAlgebras
 
-
-PathToClassLanguages = Annotated[
-    Path, PlainValidator(lambda v: Path("classes/languages/", v))
-]
-
-
 class PointerToClassLanguages(CommentedField):
     pointer: PathToClassLanguages
 
-
-PathToClassLogic = Annotated[Path, PlainValidator(lambda v: Path("classes/logic/", v))]
-
-
 class PointerToClassLogic(CommentedField):
     pointer: PathToClassLogic
 
-
-PathToOperator = Annotated[Path, PlainValidator(lambda v: Path("operators/", v))]
-
-
 class PointerToOperator(CommentedField):
     pointer: PathToOperator
 
-
-PathToBinaryOperator = Annotated[
-    Path, PlainValidator(lambda v: Path("binary_operators/", v))
-]
-
-
 class PointerToBinaryOperator(CommentedField):
     pointer: PathToBinaryOperator
 
-
-PathToPredicate = Annotated[Path, PlainValidator(lambda v: Path("predicates/", v))]
-
-
 class PointerToPredicate(CommentedField):
     pointer: PathToPredicate
 
-
 class PredicateValue(PointerToPredicate):
     value: bool
 
-- 
GitLab