Source code for pygplib.symrelst

"""Class of Symmetric Relational Structure over a single domain of discourse"""

from .name import NameMgr
from .baserelst import BaseRelSt

[docs] class SymRelSt(BaseRelSt): """Class of symmetric relational structure. All relations are considered to be symmetric. Variables run over a single domain of discourse. There is no function symbol. """ def __init__(self, objects: tuple[int], relation: tuple[tuple[int]],\ msg: str = ""): """Initializes an object of SymRelSt class. Initializes a structure so that each object in domain of discourse is assigned a unique code. How atomic predicates are interpreted based on the codes should be implemented individually in classes derived from this class. :: | 1 2 3 ----------|------- objects[0]| 0 0 0 objects[1]| 1 0 1 objects[2]| 1 1 0 objects[3]| 0 1 1 relation = (\ (objects[1],objects[2]),\ (objects[2],objects[3]),\ (objects[1],objects[3]),\ ) _codes = (\ (), (1,3), (1,2), (2,3), ) _pos = {\ objects[0] : 0, objects[1] : 1, objects[2] : 2, objects[3] : 3, () : 0, (1,3) : 1, (1,2) : 2, (2,3) : 3, } Args: objects: a domain of discourse, a tuple of constant symbol indices relation: a tuple of (non-empty) relation instances, where each instance need not be ordered. msg: message printed when assertion failed """ if len(objects) != len(set(objects)): raise Exception(f"duplicate object found: "+msg) for obj in objects: if not NameMgr.has_name(obj): raise ValueError(\ f"object {obj}, given as symbol index, has no name: "+msg) if not NameMgr.is_constant(obj): raise ValueError(\ f"{NameMgr.lookup_name(obj)} is not a constant symbol: "+msg) for inst in relation: if len(set(inst)) != len(inst): raise Exception(f"duplicate object found: "+msg) if False in list(map(lambda i: i > 0, inst)): raise Exception(f"invalid relation instance: "+msg) super().__init__(\ objects, \ type(self)._compute_dual_hypergraph(objects, relation), \ len(relation),\ msg=msg) @staticmethod def _compute_dual_hypergraph(vertices: tuple[int], \ hyperedges: tuple[tuple[int]]) -> tuple[tuple[int]]: """Computes a dual hypergraph. Args: vertices: tuple of vertices hyperedges: list of lists of objects Returns: dual hypergraph :: | 1 2 3 4 ----------|--------- objects[0]| 1 0 0 1 objects[1]| 0 0 0 0 objects[2]| 1 1 0 1 hyperedges = [ [objects[0],objects[2]], [objects[2]], [], [objects[0],objects[2]], ] res = [ {1,4}, {}, {1,2,4}, ] normalized_res = ( (1,4), (), (1,2,4), ) """ index = {} for pos, vert in enumerate(vertices): index[vert] = pos res = [set() for i in range(len(vertices))] for pos, tup in enumerate(hyperedges): for vert in tup: res[index[vert]].add(pos+1) normalized_res = tuple([tuple(sorted(s)) for s in res]) return normalized_res