|
#############################################################################
##
## This file is part of GAP, a system for computational discrete algebra.
## This file's authors include Andrew Solomon.
##
## Copyright of GAP belongs to its developers, whose names are too numerous
## to list here. Please refer to the COPYRIGHT file for details.
##
## SPDX-License-Identifier: GPL-2.0-or-later
##
## This file contains the implementation for binary relations, equivalence
## relations and equivalence classes on and over sets.
##
## If the underlying set is the set of n points {1..n} then a special
## representation is used to represent binary relations over them.
##
## Maintenance and further development by:
## Robert Arthur
## Robert F. Morse
## Andrew Solomon
##
##
############################################################################
##
## Table of Contents for relation.gi
## A. Representations
## 1. Binary Relations (general)
## 2. Binary Relation on points i.e. domain [1..n]
## 3. Equivalence Relations
## 4. Equivalence Class
##
## B. Constructor functions for binary relations (general)
## 1. Identity relation
## 2. Empty relation
##
## C. Properties of Binary relations (general case)
## 1. IsReflexive
## 2. IsSymmetric
## 3. IsTransitive
## 4. IsAntisymmetric
## 5. IsPreOrder
## 6. IsPartialOrder
## 7. IsEquivalenceRelation
##
## D. Closure operations for binary relations (general case)
## 1. Reflexive
## 2. Symmetric
## 3. Transitive
## 4. HasseDiagram
## 5. StronglyConnectedComponents
##
## E. Constructors for binary relations on points
## 1. BinaryRelationOnPoints (= BinaryRelationByListOfImages)
## 2. Random binary relation on n points
## 3. Identity relation
## 4. Empty relation
## 5. AsBinaryRelationOnPoints
##
## F. Special attributes for binary relations on points
## 1. Successors (= ImagesListOfBinaryRelation)
## 2. DegreeOfBinaryRelation
##
## G. Properties of binary relations on points
## (Same properties as general case only using the specialized
## representation)
##
## H. Closure operations for binary relations on points
## (Same operations as general case only using the specialized
## representation)
##
## I. Operations and methods for binary relations on points
## 1. ImagesElm (compatibility with GeneralMapping)
## 2. PreImagesElm (compatibility with GeneralMapping)
## 3. \=, \in, \<
## 4. \* for relations, transformations, and permutation
## 5. Set operations \+, \- (union, difference)
## 6. \^, POW for points, sets, zero
## 7. One, InverseOp
## 8. PrintObj
##
## J. Constructors for equivalence relations (TOCJ)
## 1. EquivalenceRelationByPartition
## 2. EquivalenceRelationByRelation
## 3. EquivalenceRelationByProperty
## 4. EquivalenceRelationByPairs
##
## K. Attributes operations and methods of equivalence relations
## 1. EquivalenceRelationPartition
## 2. GeneratorsOfEquivalenceRelationPartition
## 3. JoinEquivalenceRelations
## 4. MeetEquivalenceRelations
## 5. \=
## 6. ImagesElm (compatibility with GeneralMapping)
## 7. PreImagesElm (compatibility with GeneralMapping)
## 8. PrintObj
##
## L. Constructors of equivalence classes
## 1. EquivalenceClassOfElement
## 2. EquivalenceClasses
##
## M. Operations and methods of equivalence classes
## 1. \=, \in
## 2. PrintObj, Enumerator
## 3. \<
## 4. ImagesRepresentative
## 6. PreImagesRepresentative
##
############################################################################
############################################################################
############################################################################
##
## Representations TOC-A
##
############################################################################
############################################################################
##
#R IsBinaryRelationDefaultRep(<obj>)
##
## Representation for a binary relation on an arbitrary set of elements
##
DeclareRepresentation("IsBinaryRelationDefaultRep",
IsAttributeStoringRep, []);
############################################################################
##
#R IsBinaryRelationOnPointsRep(<obj>)
##
## Special case that the underlying set is the points 1..n
##
DeclareRepresentation("IsBinaryRelationOnPointsRep",
IsAttributeStoringRep, []);
############################################################################
##
#R IsEquivalenceRelationDefaultRep(<obj>)
##
## Representation of generatl equivalence classes
##
DeclareRepresentation("IsEquivalenceRelationDefaultRep",
IsAttributeStoringRep, []);
#############################################################################
##
#R IsEquivalenceClassDefaultRep( <M> )
##
## The default representation for equivalence classes will be to store its
## underlying relation, and a single canonical element of the class.
## Representation specific methods are installed here.
##
DeclareRepresentation("IsEquivalenceClassDefaultRep", IsAttributeStoringRep
and IsComponentObjectRep, rec());
############################################################################
############################################################################
############################################################################
##
## Special constructors for binary relations
##
############################################################################
InstallGlobalFunction(IdentityBinaryRelation,
function(d)
local rel;
if not IsDomain(d) and not IsPosInt(d) then
Error("error - requires a domain or positive integer");
fi;
if IsDomain(d) then
rel := IdentityMapping(d);
else
rel := BinaryRelationOnPointsNC(List([1..d],i->[i]));
fi;
SetIsReflexiveBinaryRelation(rel,true);
SetIsSymmetricBinaryRelation(rel,true);
SetIsTransitiveBinaryRelation(rel,true);
return rel;
end);
InstallGlobalFunction(EmptyBinaryRelation,
function(d)
if not IsDomain(d) and not IsPosInt(d) then
Error("error - requires a domain or positive integer");
fi;
if IsDomain(d) then
return GeneralMappingByElements(d,d,[]);
else
return BinaryRelationOnPointsNC(List([1..d],i->[]));
fi;
end);
InstallGlobalFunction(BinaryRelationByElements,
function(d,elms)
return GeneralMappingByElements(d,d,elms);
end);
############################################################################
##
## Properties of binary relations on arbitrary sets
##
############################################################################
############################################################################
##
#P IsReflexiveBinaryRelation(<rel>)
##
InstallMethod(IsReflexiveBinaryRelation,
"reflexive test binary relation", true,
[IsBinaryRelation], 0,
function(m)
local e;
# test for the one infinite case known to be reflexive
if HasIsOne(m) and IsOne(m) then
return true;
fi;
# otherwise iterate through the relation's source
for e in Source(m) do
if not e in Images(m,e) then
return false;
fi;
od;
return true;
end);
############################################################################
##
#P IsSymmetricBinaryRelation(<rel>)
##
## Depends on Images and Preimages returning SSorted lists.
##
InstallMethod(IsSymmetricBinaryRelation,
"symmetric test binary relation", true, [IsBinaryRelation], 0,
function(m)
local e,el;
# test for trivial relation
if HasIsOne(m) and IsOne(m) then
return true;
fi;
# the only elements needed to be considered are those
# involved in the underlying relation (which must be finite)
# the domain itself can be infinite.
el := Set(Concatenation(
List(Enumerator(UnderlyingRelation(m)),x->[x[1],x[2]])));
for e in el do
if not PreImages(m,e)=Images(m,e) then
return false;
fi;
od;
return true;
end);
############################################################################
##
#P IsTransitiveBinaryRelation(<rel>)
##
## Assumes that Images returns a sorted list
##
InstallMethod(IsTransitiveBinaryRelation,
"transitive test binary relation", true, [IsBinaryRelation], 0,
function(m)
local e,el,i,im;
# test for trivial relation
if HasIsOne(m) and IsOne(m) then
return true;
fi;
# the only elements needed to be considered are those
# involved in the underlying relation (which must be finite)
# the domain itself can be infinite.
el := Set(Concatenation(
List(Enumerator(UnderlyingRelation(m)),x->[x[1],x[2]])));
for e in el do
im := Images(m,e);
for i in im do
if not IsSubset(im,Images(m,i)) then
return false;
fi;
od;
od;
return true;
end);
############################################################################
##
#P IsAntisymmetricBinaryRelation(<rel>)
##
InstallMethod(IsAntisymmetricBinaryRelation,
"test for Antisymmetry of a binary relation", true,
[IsBinaryRelation], 0,
function(rel)
local e,el,i;
# test for trivial relation
if HasIsOne(rel) and IsOne(rel) then
return true;
fi;
# the only elements needed to be considered are those
# involved in the underlying relation (which must be finite)
# the domain itself can be infinite.
el := Set(Concatenation(
List(Enumerator(UnderlyingRelation(rel)),x->[x[1],x[2]])));
for e in el do
i := IntersectionSet(PreImages(rel,e),Images(rel,e));
if not IsEmpty(i) and not i=[e] then
return false;
fi;
od;
return true;
end);
############################################################################
##
#P IsPreOrderBinaryRelation(<rel>)
##
InstallMethod(IsPreOrderBinaryRelation,
"test for whether a binary relation is a preorder", true,
[IsBinaryRelation], 0,
function(rel)
return
IsTotal(rel) and
IsReflexiveBinaryRelation(rel) and
IsTransitiveBinaryRelation(rel);
end);
############################################################################
##
#P IsPartialOrderBinaryRelation(<rel>)
##
InstallMethod(IsPartialOrderBinaryRelation,
"test for whether a binary relation is a partial order", true,
[IsBinaryRelation], 0,
function(rel)
return
IsTotal(rel) and
IsReflexiveBinaryRelation(rel) and
IsTransitiveBinaryRelation(rel) and
IsAntisymmetricBinaryRelation(rel);
end);
#############################################################################
##
#P IsPartialOrderBinaryRelation(<rel>)
##
InstallMethod(IsLatticeOrderBinaryRelation,
"test for whether a binary relation is a lattice order", true,
[IsBinaryRelation],0,
function(rel)
local a,b, # elements of the relation
intersection, # intersection of downsets of a and b
nrel; # new relation defined on the intersection
# a lattice order is defined on a partial order
if not IsPartialOrderBinaryRelation(rel) then
return false;
fi;
# checking the existence of a top element (unique maximal)
if not Number(Source(rel), x->[x]=Images(rel,x)) = 1 then
return false;
fi;
## checking the existence of a meet for each pair
for a in Source(rel) do
for b in Source(rel) do
# intersecting downsets
intersection := Intersection(PreImages(rel,b),PreImages(rel,a));
# new relation on the intersection induced by the original relation
nrel := PartialOrderByOrderingFunction(
Domain(intersection),
function(x,y) return y in Images(rel,x);end);
# if this new order does not have a top, then a meet b does not exist
if not Number(Source(nrel), x->[x]=Images(nrel,x)) = 1 then
return false;
fi;
od;
od;
return true;
end);
############################################################################
##
#P IsEquivalenceRelation(<rel>)
##
InstallMethod(IsEquivalenceRelation,
"test for equivalence relation", true,
[IsBinaryRelation], 0,
function(rel)
return
IsTotal(rel) and
IsReflexiveBinaryRelation(rel) and
IsSymmetricBinaryRelation(rel) and
IsTransitiveBinaryRelation(rel);
end );
############################################################################
############################################################################
############################################################################
##
## Closure operations for binary relation on arbitrary sets
##
############################################################################
############################################################################
##
#O ReflexiveClosureBinaryRelation(<Rel>)
##
## This will die if the elements set of the underlying relation
## is not finite. Can install more specific methods for relations over
## infinite domains where we can do better.
##
InstallMethod(ReflexiveClosureBinaryRelation,
"for binary relation", true, [IsBinaryRelation], 0,
function(r)
local ur,i,d, newrel;
if HasIsReflexiveBinaryRelation(r) and
IsReflexiveBinaryRelation(r) then
return r;
fi;
ur := ShallowCopy(AsSSortedList(UnderlyingRelation(r)));
for i in Source(r) do
AddSet(ur,DirectProductElement([i,i]));
od;
d := Source(r);
newrel := GeneralMappingByElements(d,d,ur);
SetIsReflexiveBinaryRelation(newrel, true);
# ReflexiveClosure preserves Transitivity.
if HasIsTransitiveBinaryRelation(r) then
SetIsTransitiveBinaryRelation(newrel,
IsTransitiveBinaryRelation(r));
fi;
# ReflexiveClosure preserves Symmetry.
if HasIsSymmetricBinaryRelation(r) then
SetIsSymmetricBinaryRelation(newrel,
IsSymmetricBinaryRelation(r));
fi;
return newrel;
end );
############################################################################
##
#O SymmetricClosureBinaryRelation(<Rel>)
##
## This will die if the elements set of the underlying relation
## is not finite. Can install more specific methods for relations over
## infinite domains where we can do better.
##
InstallMethod(SymmetricClosureBinaryRelation,
"for binary relation", true, [IsBinaryRelation], 0,
function(r)
local ur,i,t,d, newrel;
if HasIsSymmetricBinaryRelation(r) and
IsSymmetricBinaryRelation(r) then
return r;
fi;
ur := UnderlyingRelation(r);
t := ShallowCopy(AsSSortedList(ur));
for i in ur do
AddSet(t,DirectProductElement([i[2],i[1]]));
od;
d := Source(r);
newrel := GeneralMappingByElements(d,d,t);
SetIsSymmetricBinaryRelation(newrel, true);
# SymmetricClosure preserves Reflexivity.
if HasIsReflexiveBinaryRelation(r) then
SetIsReflexiveBinaryRelation(newrel, IsReflexiveBinaryRelation(r));
fi;
return newrel;
end );
############################################################################
##
#O TransitiveClosureBinaryRelation(<Rel>)
##
##
## This is a modified version of the Floyd-Warshall method
## of solving the all-pairs shortest-paths problem on a directed graph. Its
## asymptotic runtime is O(n^3) where n is the size of the vertex set. It
## only assumes there is an arbitrary (but fixed) ordering of the vertex set.
##
## This will die if the elements set of the underlying relation
## is not finite. Can install more specific methods for relations over
## infinite domains where we can do better.
##
InstallMethod(TransitiveClosureBinaryRelation,
"for binary relation", true,
[IsBinaryRelation], 0,
function(r)
local t, # a list of sets that provides an adjacency list
# representation of the graph involved
el, # those elements involved in the underlying relation
i,j, # index variables
p, # 2-tuples that make up the closure
d, # Domain of the given relation
newrel; # New transitive relation
# if the given relation is already transitive the just return
if HasIsTransitiveBinaryRelation(r) and
IsTransitiveBinaryRelation(r) then
return r;
fi;
# the only elements needed to be considered are those
# involved in the underlying relation (which must be finite)
# the domain itself can be infinite.
el := Set(Concatenation(
List(Enumerator(UnderlyingRelation(r)),x->[x[1],x[2]])));
## Assumes Images returns a Sorted list -- makes sure t is
## mutable as well as its elements
t := List(el, i->ShallowCopy(Images(r,i)));
# if \i in t[j] then everything related to \i
# should be in t[j].
for i in [1..Length(el)] do
for j in [1..Length(el)] do
if el[i] in t[j] then
UniteSet(t[j],t[i]);
fi;
od;
od;
# Build the new set of underlying relations for the
# transitive closure from the adjacency list
p := [];
for i in [1..Length(el)] do
Append(p,List(t[i],x->DirectProductElement([el[i],x])));
od;
d := Source(r); ##Assumes source is a domain
newrel := GeneralMappingByElements(d,d,p);
SetIsTransitiveBinaryRelation(newrel, true);
# TransitiveClosure preserves Reflexivity.
if HasIsReflexiveBinaryRelation(r) then
SetIsReflexiveBinaryRelation(newrel, IsReflexiveBinaryRelation(r));
fi;
# TransitiveClosure preserves Symmetry.
if HasIsSymmetricBinaryRelation(r) then
SetIsSymmetricBinaryRelation(newrel, IsSymmetricBinaryRelation(r));
fi;
return newrel;
end);
############################################################################
##
#O HasseDiagramBinaryRelation(<rel>)
##
## If <rel> is a partial order then return the smallest relation contained
## in <rel> whose reflexive and transitive closure is equal to <rel>
##
InstallMethod(HasseDiagramBinaryRelation,
"for binary relation", true,
[IsBinaryRelation], 0,
function(rel)
local i, j, # iterators
d, # elements of underlying domain
lc, # pairs (x, covers(x)) for x in d
tups, # elements of the hasse diagram relation
h, # the resulting hasse diagram
# internal functions:
HDBRMinElts, # to find minimal elements
HDBREltCovers, # to find the cover of an element
HDBRListCovers; # to find the set of covers
while not IsPartialOrderBinaryRelation(rel) do
Error("Relation ",rel," is not a partial order");
od;
## return the minimal elements of a list under rel
HDBRMinElts := function(list, rel)
## x minimal if
## {y in list | y<>x and y in PreImagesElm( rel,x)} is empty
##
return Filtered(list,
x->IsEmpty(Filtered(list, y-> (y <> x) and
(y in PreImagesElm(rel,x)))));
end;
## return the elements which cover x in rel
HDBREltCovers := function(x, rel)
local xunder;
xunder := Filtered(ImagesElm(rel,x), y-> y <> x);
return HDBRMinElts(xunder,rel);
end;
## for a list, return the set of pairs (x, covers(x))
HDBRListCovers := function(list,rel)
return List(list, x->[x, HDBREltCovers(x, rel)]);
end;
d := UnderlyingDomainOfBinaryRelation(rel);
lc := HDBRListCovers(AsList(d), rel);
tups := [];
for i in lc do
for j in i[2] do
Append(tups, [DirectProductElement([i[1], j])]);
od;
od;
h := GeneralMappingByElements(d,d, tups);
SetIsHasseDiagram(h, true);
SetPartialOrderOfHasseDiagram(h,rel);
return h;
end);
#############################################################################
##
#F PartialOrderByOrderingFunction(<dom>,<orderfunc>
##
## constructs a partial order whose elements are from the domain <dom>
## and are ordered using the ordering function <orderfunc>.
##
InstallGlobalFunction(PartialOrderByOrderingFunction,
function(d,of)
local i,j, # iterators
tup, # set of defining tuples
po; # resulting partial order
## Check the input
##
if not IsDomain(d) then
Error("Partial Orders are only constructible over domains");
fi;
## Construct a set of tuples which defines the partial order
##
tup :=[];
for i in d do
for j in d do
if of(i,j) then
Add(tup,DirectProductElement([i,j]));
fi;
od;
od;
po := BinaryRelationByElements(d,tup);
## If the relation constructed is not a partial order return fail
##
if not IsReflexiveBinaryRelation(po) or
not IsTransitiveBinaryRelation(po) or
not IsAntisymmetricBinaryRelation(po) then
return fail;
else
return po;
fi;
end);
############################################################################
##
#O StronglyConnectedComponents(<R>)
##
## returns an equivalence relation on the vertices of the relation.
##
InstallMethod(StronglyConnectedComponents, "for general binary relations",
true, [IsBinaryRelation],0,
function(rel)
local r, # representation of rel as a binary relation on points
e, # Equivalence relation representation of the
# predecessor subgraph
s; # Sorted list of the source of rel
## Convert rel to a relation on points
##
r := AsBinaryRelationOnPoints(rel);
## Call the kernel function to find the strongly connected
## components
##
e := STRONGLY_CONNECTED_COMPONENTS_DIGRAPH(Successors(r));
## Eliminate singletons
e := Filtered(e, i->Length(i)>1);
s := AsSSortedList(Source(rel));
return EquivalenceRelationByPartitionNC(Source(rel),
List(e, i->s{i}));
end);
############################################################################
############################################################################
############################################################################
## #########################################
## ## ##
## ## Binary Relations on Points TOCJ ##
## ## ##
## #########################################
############################################################################
############################################################################
##
## Properties, Operations, and Methods for binary relations on points
##
############################################################################
############################################################################
## For compatibility with earlier versions
##
DeclareSynonym("ImagesListOfBinaryRelation",Successors);
DeclareSynonym("BinaryRelationByListOfImages", BinaryRelationOnPoints);
DeclareSynonym("BinaryRelationByListOfImagesNC", BinaryRelationOnPointsNC);
############################################################################
##
## Constructors for binary relations on points
##
############################################################################
############################################################################
##
#F BinaryRelationOnPoints( <list> )
#F BinaryRelationOnPointsNC( <list> )
##
InstallGlobalFunction(BinaryRelationOnPointsNC,
function( lst )
local d, # Degree of relation
fam, # Family of relation
rel; # binary relation object
d:= Length(lst);
fam:= GeneralMappingsFamily(FamilyObj(1), FamilyObj(1));
rel:= Objectify(NewType(fam, IsBinaryRelation and
IsBinaryRelationOnPointsRep and
IsNonSPGeneralMapping), rec());
SetSource(rel, Domain([1..d]));
SetRange(rel, Domain([1..d]));
SetSuccessors(rel, List(lst,AsSSortedList));
SetDegreeOfBinaryRelation(rel,d);
return rel;
end);
InstallGlobalFunction(BinaryRelationOnPoints,
function( lst )
## Check to see if the given list is dense
#
if not IsDenseList(lst) then
Error("List, ",lst,",must be dense");
fi;
## Check to see if the list defines a relation on 1..n
#
if not ForAll(Flat(lst),x->x in [1..Length(lst)]) then
Error("List ,", lst,", does not represent a binary relation on 1 .. n");
fi;
return BinaryRelationByListOfImagesNC(lst);
end);
############################################################################
##
#F AsBinaryRelationOnPoints(<rel>)
#F AsBinaryRelationOnPoints(<trans>)
#F AsBinaryRelationOnPoints(<perm>)
##
## return the relation on n points represented by general relation,
## transformation or permutation, If <rel> is a binary relation on points
## then just return <rel>.
##
InstallGlobalFunction(AsBinaryRelationOnPoints,
function(rel)
local el;
if IsTransformation(rel) then
return BinaryRelationTransformation(rel);
fi;
if IsPerm(rel) then
return AsBinaryRelationOnPoints(AsTransformation(rel));
fi;
if IsBinaryRelation(rel) and
IsBinaryRelationOnPointsRep(rel) then
return rel;
fi;
if IsBinaryRelation(rel) then
el := AsSSortedList(Source(rel));
return BinaryRelationOnPoints(
List(el, i->List(Images(rel,i),j->Position(el,j))));
fi;
end);
############################################################################
##
#F RandomBinaryRelationOnPoints(n)
##
############################################################################
InstallGlobalFunction(RandomBinaryRelationOnPoints,
function(n)
if not IsPosInt(n) then
Error("error, <n> must be a positive integer");
fi;
return BinaryRelationOnPointsNC(
List([1..n],i->List([1..Random(1,n)],j->Random(1,n))));
end);
############################################################################
##
## Properties of binary relations on points
##
############################################################################
############################################################################
##
#P IsReflexiveBinaryRelation(<rel>)
#P IsSymmetricBinaryRelation(<rel>)
#P IsTransitiveBinaryRelation(<rel>)
#P IsAnitsymmetricBinaryRelation(<rel>)
#P IsPreOrderBinaryRelation(<rel>)
#P IsPartialOrderBinaryRelation(<rel>)
#P IsEquivalenceRelation(<rel>)
##
##
InstallMethod(IsReflexiveBinaryRelation, "for binary relations on points",
true, [IsBinaryRelation and IsBinaryRelationOnPointsRep],0,
rel -> ForAll([1..DegreeOfBinaryRelation(rel)],
i->i in Successors(rel)[i])
);
InstallMethod(IsSymmetricBinaryRelation, "for binary relations on points",
true, [IsBinaryRelation and IsBinaryRelationOnPointsRep],0,
rel -> ForAll([1..DegreeOfBinaryRelation(rel)],
i-> ForAll(Successors(rel)[i], j-> i in Successors(rel)[j] ))
);
InstallMethod(IsTransitiveBinaryRelation, "for binary relations on points",
true, [IsBinaryRelation and IsBinaryRelationOnPointsRep],0,
rel -> ForAll([1..DegreeOfBinaryRelation(rel)], i->
ForAll(Successors(rel)[i], j->
IsSubset(Successors(rel)[i],Successors(rel)[j])))
);
InstallMethod(IsAntisymmetricBinaryRelation, "for binary relations on points",
true, [IsBinaryRelation and IsBinaryRelationOnPointsRep],0,
rel -> ForAll([1..DegreeOfBinaryRelation(rel)], i->
ForAll(Successors(rel)[i],
j-> j=i or (not j=i and not i in Successors(rel)[j])))
);
InstallMethod(IsPreOrderBinaryRelation, "for binary relations on points",
true, [IsBinaryRelation and IsBinaryRelationOnPointsRep],0,
rel -> IsReflexiveBinaryRelation(rel) and IsTransitiveBinaryRelation(rel)
);
InstallMethod(IsPartialOrderBinaryRelation, "for binary relations on points",
true, [IsBinaryRelation and IsBinaryRelationOnPointsRep],0,
rel -> IsPreOrderBinaryRelation(rel) and IsAntisymmetricBinaryRelation(rel)
);
InstallMethod(IsEquivalenceRelation, "for binary relations on points",
true, [IsBinaryRelation and IsBinaryRelationOnPointsRep],0,
rel -> IsReflexiveBinaryRelation(rel) and IsSymmetricBinaryRelation(rel)
and IsTransitiveBinaryRelation(rel)
);
############################################################################
##
## Closure operations of binary relations on points
##
############################################################################
############################################################################
##
#O ReflexiveClosureBinaryRelation(<rel>)
#O SymmetricClosureBinaryRelation(<rel>)
#O TransitiveClosureBinaryRelation(<rel>)
##
##
InstallMethod(ReflexiveClosureBinaryRelation, "for binary relations on points",
true, [IsBinaryRelation and IsBinaryRelationOnPointsRep],0,
rel -> BinaryRelationOnPointsNC(
List([1..DegreeOfBinaryRelation(rel)], i->
Union2(Successors(rel)[i],[i])))
);
InstallMethod(SymmetricClosureBinaryRelation, "for binary relations on points",
true, [IsBinaryRelation and IsBinaryRelationOnPointsRep],0,
function(rel)
local suc, #successors of given relation
i,j, #Index variables
newrel; #new relation which is the symmetric closure
suc := List(Successors(rel),ShallowCopy);
for i in [1..DegreeOfBinaryRelation(rel)] do
for j in Successors(rel)[i] do
UniteSet(suc[j],[i]);
od;
od;
newrel := BinaryRelationOnPointsNC(suc);
if HasIsReflexiveBinaryRelation(rel) then
SetIsReflexiveBinaryRelation(newrel, IsReflexiveBinaryRelation(rel));
fi;
return newrel;
end);
InstallMethod(TransitiveClosureBinaryRelation, "for binary relations on points",
true, [IsBinaryRelation and IsBinaryRelationOnPointsRep],0,
function(rel)
local i,j, #index variables
suc; #successors of given relation
suc := List(Successors(rel),ShallowCopy);
# if \i in suc[j] then everything related to \i
# should be in suc[j].
for i in [1..DegreeOfBinaryRelation(rel)] do
for j in [1..DegreeOfBinaryRelation(rel)] do
if i in suc[j] then
UniteSet(suc[j],suc[i]);
fi;
od;
od;
return BinaryRelationOnPointsNC(suc);
end);
#############################################################################
##
## Methods that allow binary relations on points to act and work as
## IsEndoGeneralMappings but making use of their specialized representations
##
#############################################################################
#############################################################################
##
#M ImagesElm( <rel>, <n> )
##
## For binary relations over [1..n] represented as a list of images
##
InstallMethod(ImagesElm,
"for binary relations over [1..n] with images list",
true, [IsBinaryRelation and IsBinaryRelationOnPointsRep, IsPosInt], 0,
function( rel, n )
if not n in [1..DegreeOfBinaryRelation(rel)] then
Error("<n> is not in Domain of ", rel);
fi;
return Successors(rel)[n];
end);
#############################################################################
##
#M PreImagesElm( <rel>, <n> )
##
## For binary relations over [1..n] represented as a list of images
##
InstallMethod(PreImagesElm,
"for binary rels over [1..n] with images list",
true, [IsBinaryRelation and IsBinaryRelationOnPointsRep, IsPosInt], 0,
function( rel, n )
return Filtered([1..DegreeOfBinaryRelation(rel)],
i->n in Successors(rel)[i]);
end);
#############################################################################
##
#A Successors( <rel> )
##
## Returns the list of images of a binary relation. If the underlying
## domain of the relation is not [1..n] then an error is signalled.
##
InstallMethod(Successors, "for a generic relation", true,
[IsBinaryRelation], 0,
function(r)
local eldom; # Elements of the domain
eldom:= AsSSortedList(UnderlyingDomainOfBinaryRelation(r));
if not IsRange(eldom) or eldom[1] <> 1 then
Error("Operation only makes sense for relations over [1..n]");
fi;
return List(eldom, i-> ImagesElm(r,i));
end);
#############################################################################
##
## Arithmetic and boolean methods on binary relations on points
##
## \= True if successors lists are equal (by construction each image is
## a set of integers so there is a canonical form to check)
##
## \in determines whether a tuple [x,y] in rel
##
## \< compares successors list
##
#############################################################################
#############################################################################
##
#M \= ( <rel1>, <rel2> )
##
## For binary relations on n points
##
InstallMethod( \=, "for binary relss over [1..n] with images list", true,
[IsBinaryRelation and IsBinaryRelationOnPointsRep,
IsBinaryRelation and IsBinaryRelationOnPointsRep], 0,
function(rel1, rel2)
return Successors(rel1) = Successors(rel2);
end);
#############################################################################
##
#M \in ( <tup>, <rel> )
##
## For binary relations on n points
##
InstallMethod( \in, "for binary rels over [1..n] with images list", true,
[IsList, IsBinaryRelation and IsBinaryRelationOnPointsRep], 0,
function( tup, rel )
if Length(tup) <> 2 then
Error("List ", tup, " must be of length 2");
fi;
return tup[2] in Successors(rel)[tup[1]];
end);
#############################################################################
##
#M \< ( <rel>, <rel> )
##
## For binary relations on n points
##
InstallMethod( \<, "for binary rels over [1..n] with images list", true,
[IsBinaryRelation and IsBinaryRelationOnPointsRep,
IsBinaryRelation and IsBinaryRelationOnPointsRep], 0,
function( relL, relR )
return Successors(relL) < Successors(relR);
end);
#############################################################################
##
#M \* ( <rel>, <rel> )
#M \* ( <trans>, <rel> )
#M \* ( <rel>, <trans> )
#M \* ( <perm>, <rel> )
#M \* ( <rel>, <perm> )
#M \* ( <list>, <rel> )
#M \* ( <rel>, <list> )
##
## For binary relations on n points
##
InstallMethod( \*, "for binary relations on points", true,
[IsBinaryRelation and IsBinaryRelationOnPointsRep,
IsBinaryRelation and IsBinaryRelationOnPointsRep], 0,
function( relL, relR )
if DegreeOfBinaryRelation(relL)<>DegreeOfBinaryRelation(relR) then
Error("The binary relations must have the same degree");
fi;
return BinaryRelationOnPoints(
List([1..DegreeOfBinaryRelation(relL)],i->
Union(List(Successors(relL)[i],j->Successors(relR)[j]))));
end);
InstallOtherMethod( \*, "for transformation and binary relation on points", true,
[IsTransformation,
IsBinaryRelation and IsBinaryRelationOnPointsRep], 0,
function( t, rel )
if DegreeOfTransformation(t)<>DegreeOfBinaryRelation(rel) then
Error("Transformation and binary relation must have the same degree");
fi;
return BinaryRelationOnPoints(
List([1..DegreeOfTransformation(t)],i->
Successors(rel)[i^t]));
end);
InstallOtherMethod( \*, "for binary relation on points and transformation", true,
[IsBinaryRelation and
IsBinaryRelationOnPointsRep, IsTransformation], 0,
function( rel, t )
return rel * BinaryRelationTransformation(t);
end);
InstallOtherMethod( \*, "for binary relation on points and permutation", true,
[IsBinaryRelation and IsBinaryRelationOnPointsRep, IsPerm], 0,
function( rel, p )
return rel * AsTransformation(p,DegreeOfBinaryRelation(rel));
end);
InstallOtherMethod( \*, "for permutation and binary relation on points", true,
[IsPerm, IsBinaryRelation and IsBinaryRelationOnPointsRep], 0,
function( p, rel )
return AsTransformation(p,DegreeOfBinaryRelation(rel)) * rel;
end);
InstallOtherMethod( \*, "for binary relation on points and list", true,
[IsBinaryRelation and IsBinaryRelationOnPointsRep, IsListOrCollection], 0,
function( rel,lst )
return List(lst, i->rel*i);
end);
InstallOtherMethod( \*, "for list and binary relation on points", true,
[IsListOrCollection, IsBinaryRelation and IsBinaryRelationOnPointsRep], 0,
function( lst, rel )
return List(lst, i->i*rel);
end);
#############################################################################
##
#M \+ ( <rel>, <rel> ) -- Union
#M \- ( <trans>, <rel> ) -- Difference
##
## Set operations for binary relations on points
## Union
## Difference
##
InstallMethod( \+, "for binary relations on points", true,
[IsBinaryRelation and IsBinaryRelationOnPointsRep,
IsBinaryRelation and IsBinaryRelationOnPointsRep], 0,
function( rel1, rel2 )
if DegreeOfBinaryRelation(rel1) <> DegreeOfBinaryRelation(rel2) then
Error("the union of two relations on points must have the same degree");
fi;
return
BinaryRelationOnPoints(List([1..DegreeOfBinaryRelation(rel1)],
i-> Union(Successors(rel1)[i],Successors(rel2)[i])));
end);
InstallMethod( \-, "for binary relations on points", true,
[IsBinaryRelation and IsBinaryRelationOnPointsRep,
IsBinaryRelation and IsBinaryRelationOnPointsRep], 0,
function( rel1, rel2 )
if DegreeOfBinaryRelation(rel1) <> DegreeOfBinaryRelation(rel2) then
Error("the difference of two relations on points must have the same degree");
fi;
return
BinaryRelationOnPoints(List([1..DegreeOfBinaryRelation(rel1)],
i-> Difference(Successors(rel1)[i],Successors(rel2)[i])));
end);
#############################################################################
##
#M \^ ( <int>, <rel> ) Images of an integer in domain
#M \^ ( <trans>, <rel> ) Union of the images of the set
#M \^ ( <list>, <rel> ) List of images for each element in the list
##
##
#############################################################################
##
#M \^ ( <int>, <rel> )
##
## For binary relations on points
##
InstallMethod( \^, "for binary relation on points and a positive int", true,
[IsPosInt,
IsBinaryRelation and IsBinaryRelationOnPointsRep], 0,
function( i, rel )
return ImagesElm(rel,i);
end);
#############################################################################
##
#M \^ ( <set>, <rel> )
##
## For binary relations on points
##
InstallMethod( POW, "for binary relation on points and a set of integers",true,
[IsListOrCollection,
IsBinaryRelation and IsBinaryRelationOnPointsRep], 0,
function( set, rel )
return Set(Flat(Successors(rel){set}));
end);
#############################################################################
##
#M \^ ( <list>, <rel> )
##
## For binary relations on points
##
InstallMethod( POW, "for binary relation on points and Zero",true,
[IsBinaryRelation and IsBinaryRelationOnPointsRep, IsZeroCyc], 0,
function( rel,z )
return
BinaryRelationOnPoints(List([1..DegreeOfBinaryRelation(rel)],i->[i]));
end);
#############################################################################
##
#M InverseOp( <rel> )
##
## For binary relations on points
##
InstallMethod( InverseOp, "for binary relation on points and a set of integers",true,
[IsBinaryRelation and IsBinaryRelationOnPointsRep], 0,
function(rel)
local d,suc,i,j;
d := DegreeOfBinaryRelation(rel);
suc := List([1..d],x->[]);
for i in [1..d] do
for j in Successors(rel)[i] do
AddSet(suc[j],i);
od;
od;
return BinaryRelationOnPoints(suc);
end);
#############################################################################
##
#M One( <rel> )
##
## For binary relations on points
##
InstallMethod( One, "for binary relation on points and a set of integers",true,
[IsBinaryRelation and IsBinaryRelationOnPointsRep], 0,
rel -> BinaryRelationOnPoints(List([1..DegreeOfBinaryRelation(rel)],i->[i]))
);
#############################################################################
##
#M PrintObj( <C> )
##
## Display binary relation on n points.
##
InstallMethod(PrintObj, "for a binary relation on n points", true,
[IsBinaryRelation and IsBinaryRelationOnPointsRep],0,
function(rel)
Print("Binary Relation on ",DegreeOfBinaryRelation(rel)," points");
end);
############################################################################
############################################################################
## #####################################
## ## ##
## ## Equivalence Relations TOCJ ##
## ## ##
## #####################################
############################################################################
############################################################################
##
## Constructors for Equivalence relations. Many of these construction
## are actually closure operations e.g. find the smallest equivalence
## relation containing a given relation.
##
############################################################################
#############################################################################
##
#F EquivalenceRelationByPartition( <set>, <list> )
##
##
InstallGlobalFunction(EquivalenceRelationByPartition,
function(X, subsX)
local fam, rel;
if not IsDomain(X) then
Error("Equivalence relations only constructible over domains");
fi;
# make sure there are no repetitions
if not IsSet(AsSortedList(Concatenation(subsX))) then
Error("Input does not describe a partition");
fi;
#check that subsX is contained in X
if not (IsSubset(X, AsSortedList(Concatenation(subsX)))) then
Error("Input does not describe a partition");
fi;
fam := GeneralMappingsFamily( ElementsFamily(FamilyObj(X)),
ElementsFamily(FamilyObj(X)) );
## Get rid of singletons and possible empty blocks
subsX := Filtered(subsX, i->Length(i)>1);
# Create the default type for the elements.
rel := Objectify(NewType(fam,
IsEquivalenceRelation and IsEquivalenceRelationDefaultRep), rec());
SetEquivalenceRelationPartition(rel, subsX);
SetSource(rel, X);
SetRange(rel, X);
return rel;
end);
#############################################################################
##
#F EquivalenceRelationByPartitionNC( <set>, <list> )
##
## No checks are performed except empty and singleton blocks are removed from
## the partition given (if they exist).
##
InstallGlobalFunction(EquivalenceRelationByPartitionNC,
function(X, subsX)
local fam, rel;
fam := GeneralMappingsFamily( ElementsFamily(FamilyObj(X)),
ElementsFamily(FamilyObj(X)) );
# Create the default type for the elements.
rel := Objectify(NewType(fam,
IsEquivalenceRelation and IsEquivalenceRelationDefaultRep), rec());
## The only assurance is singletons and empty blocks are removed
##
SetEquivalenceRelationPartition(rel, Filtered(subsX, i->Length(i)>1));
SetSource(rel, X);
SetRange(rel, X);
return rel;
end);
#############################################################################
##
#F EquivalenceRelationByRelation( <rel> )
##
## Checks for special cases to improve efficiency otherwise
## use general attributes and call EquivalenceRelationByPairs
##
InstallGlobalFunction(EquivalenceRelationByRelation,
function(r)
local i,j,tups;
## Special cases that do not require finding the underlying
## relation i.e. having the mapping methods find
## all tuples using images of elements
##
if IsBinaryRelation(r) and IsBinaryRelationOnPointsRep(r) then
tups :=[];
for i in [1..DegreeOfBinaryRelation(r)] do
for j in Successors(r)[i] do
Add(tups, DirectProductElement([i,j]));
od;
od;
return EquivalenceRelationByPairs(
UnderlyingDomainOfBinaryRelation(r),tups);
fi;
if IsTransformation(r) then
return EquivalenceRelationByRelation(
BinaryRelationTransformation(r));
fi;
## Need to use general mapping functions and compute underlying
## relation
##
return EquivalenceRelationByPairs(UnderlyingDomainOfBinaryRelation(r),
Enumerator(UnderlyingRelation(r)));
end);
#############################################################################
##
#F EquivalenceRelationByProperty( <domain>, <property> )
##
## Create an equivalence relation on <domain> whose only defining
## data is having the property <property>.
##
InstallGlobalFunction(EquivalenceRelationByProperty,
function(X, property )
local fam, rel;
fam := GeneralMappingsFamily( ElementsFamily(FamilyObj(X)),
ElementsFamily(FamilyObj(X)) );
# Create the default type for the elements.
rel := Objectify(NewType(fam, IsEquivalenceRelation
and IsEquivalenceRelationDefaultRep and IsNonSPGeneralMapping), rec());
SetSource(rel, X);
SetRange(rel, X);
Setter(property)(rel, true);
return rel;
end);
#############################################################################
##
#F EquivalenceRelationByPairs( <D>, <pairs> )
#F EquivalenceRelationByPairsNC( <D>, <pairs> )
##
## Construct the smallest equivalence relation containing <pairs>
##
## The closure algorithm uses a variant of Tarjan's set merge method.
## It runs in nearly linear time, O(n g(n)) where g(n) is a slow growing function
## (optimally the inverse of Ackerman's function)
##
## The NC version assumes that <D> is a domain and <pairs> are tuples (or lists
## of length 2) of the form (a,b) where a<>b
##
InstallGlobalFunction(EquivalenceRelationByPairsNC,
function(d,pairs)
local C, #Set of given pairs of the form (a,b), a<>b
i,j, #index variables
p1,p2, #indexes to blocks to merge
forest; #a list of lists representing a forest
# each tree in the forest have depth one
# (full path compression)
##
## We are assuming pairs have been sanitized
## all (a,b) a<>b
##
## Make a mutable copy of pairs
##
if (IsSet(pairs)) or
(HasIsDuplicateFreeList(pairs) and IsDuplicateFreeList(pairs)) then
C := List(pairs,ShallowCopy);
else
C := DuplicateFreeList(List(pairs,ShallowCopy));
fi;
##
## Use Tarjan's merge method to find the equivalence relation
## generated by the pairs (expressed as a set of non-trivial
## blocks determined by the input pairs).
## The first pair will be our starting forest.
##
forest := [C[1]];
##
## Put each pair in its appropriate block and merge blocks
## as necessary
##
for i in C do
p1 := Length(forest)+1;
p2 := Length(forest)+1;
for j in [1..Length(forest)] do
if p1>Length(forest) and i[1] in forest[j] then
p1 := j;
if p2 <=Length(forest) then break; fi;
fi;
if p2>Length(forest) and i[2] in forest[j] then
p2 := j;
if p1<=Length(forest) then break; fi;
fi;
od;
##
## For the pair (a,b) if a is in one block and b is in another
## merge the two blocks
##
if p1<=Length(forest) and p2<=Length(forest) and not p1=p2 then
Append(forest[p1],forest[p2]);
Unbind(forest[p2]);
if p2<Length(forest) then
forest[p2]:=Remove(forest);
fi;
##
## These cases are if only one of the components
## is in a block
##
elif p1<=Length(forest) and p2>Length(forest) then
Add(forest[p1],i[2]);
elif p2<=Length(forest) and p1>Length(forest) then
Add(forest[p2],i[1]);
##
## Neither component is in a block
##
##
elif p1>Length(forest) and p2>Length(forest) then
Add(forest,i);
fi;
od;
return EquivalenceRelationByPartitionNC(d,forest);
end);
InstallGlobalFunction(EquivalenceRelationByPairs,
function(d,pairs)
local C, #Set of given pairs of the form (a,b), a<>b
i,j, #index variables
p1,p2, #indexes to blocks to merge
forest; #a list of lists representing a forest
# each tree in the forest have depth one
# (full path compression)
## Parameter checking
## d=domain, elms=list
##
if not IsDomain(d) then
Error("Equivalence relations only constructible over domains");
fi;
if not IsList(pairs) then
Error("Second parameter must be a list of 2-tuples");
fi;
## If no pairs are given return the diagonal equivalence
##
if IsEmpty(pairs) then
return EquivalenceRelationByPartitionNC(d,[]);
fi;
## Make sure that all of the pairs are indeed pairs
if ForAny(pairs,x->not Length(x)=2 ) then
Error("Usage error, pairs must be tuples of length 2");
fi;
## Make sure that all of the elements in the pairs are in
## the domain
if ForAny(pairs,x->not x[1] in d or not x[2] in d) then
Error("One of more element pairs contain elements not in the domain");
fi;
##
## Filter out all pairs of the form (a,a).
## If this filtered set is empty return the diagonal
## equivalence
## Make a mutable copy of pairs so we don't inadvertently alter
## pairs
##
C := List(Filtered(pairs,x->not x[1]=x[2]), ShallowCopy);
##
## Return diagonal relation if all pairs are of the form (a,a)
##
if IsEmpty(C) then
return EquivalenceRelationByPartitionNC(d,[]);
fi;
C := Set(C);
return EquivalenceRelationByPairsNC(d,C);
end);
#############################################################################
##
#A EquivalenceRelationPartition(<equiv>)
##
##
InstallMethod( EquivalenceRelationPartition,
"compute the partition for an arbitrary equiv rel", true,
[IsEquivalenceRelation], 0,
function( equiv )
local part;
if IsBinaryRelationOnPointsRep(equiv) then
part := DuplicateFreeList(Successors(equiv));
return Filtered(part, x->Length(x)>1);
fi;
return EquivalenceRelationPartition(
EquivalenceRelationByPairs(Source(equiv),
AsList(UnderlyingRelation(equiv))));
end);
#############################################################################
##
#M JoinEquivalenceRelations( <equiv1>,<equiv2> )
#M MeetEquivalenceRelations( <equiv1>,<equiv2> )
##
## JoinEquivalenceRelations(<equiv1>,<equiv2>) -- form the smallest
## equivalence relation containing both equivalence relations.
##
## MeetEquivalenceRelations( <equiv1>,<equiv2> ) -- computes the
## intersection of the two equivalence relations.
##
InstallMethod( JoinEquivalenceRelations,
"join of two equivalence relations", true,
[IsEquivalenceRelation, IsEquivalenceRelation], 0,
function(er1, er2)
if Source(er1)<>Source(er2) then
Error("usage: <equiv1> and <equiv2> must have the same source");
fi;
return EquivalenceRelationByPairs(Source(er1),
Concatenation( GeneratorsOfEquivalenceRelationPartition(er1),
GeneratorsOfEquivalenceRelationPartition(er2)) );
end);
InstallMethod( MeetEquivalenceRelations,
"meet of two equivalence relations", true,
[IsEquivalenceRelation, IsEquivalenceRelation], 0,
function(er1, er2)
local part1, # Partition for equivalence relation 1
part2, # Partition for equivalence relation 2
part, # Intersection of the two partitions
meet, # Meet equivalence relation
i,j; # index variables
if Source(er1)<>Source(er2) then
Error("usage: <equiv1> and <equiv2> must have the same source");
fi;
part1 := EquivalenceRelationPartition(er1);
part2 := EquivalenceRelationPartition(er2);
part := [];
## Find the intersection of each pair of blocks
##
for i in part1 do
for j in part2 do
Add(part, Intersection(i,j));
od;
od;
## Filter out non-singletons
##
part := Filtered(part, x->Length(x)>1);
meet := EquivalenceRelationByPairs(Source(er1),[]);
meet!.EquivalenceRelationPartition := part;
return meet;
end);
#############################################################################
##
#A GeneratorsOfEquivalenceRelationPartition( <equiv> )
##
##
InstallMethod(GeneratorsOfEquivalenceRelationPartition,
"generators for an equivalence with a partition", true,
[IsEquivalenceRelation], 0,
function(equiv)
local gens, b,j,part;
part := EquivalenceRelationPartition(equiv);
gens:=[];
for b in part do
for j in [1..Length(b)-1] do
AddSet(gens,AsSSortedList([b[j],b[j+1]]));
od;
od;
return gens;
end);
#############################################################################
##
#M \= for equivalence relations
##
InstallMethod(\=, "for eqivalence relations", IsIdenticalObj,
[IsEquivalenceRelation, IsEquivalenceRelation], 0,
function(x, y)
local p, ## partition
f; ## first partition
## Check if sources are equal
##
if Source(x) <> Source(y) then
return false;
fi;
## If images of each element is equal we have equal e.r.
##
if HasSuccessors(x) and HasSuccessors(y) then
return Successors(x)=Successors(y);
fi;
## Look at partitions -- they are not in any canonical
## form.
##
if (HasEquivalenceRelationPartition(x) and
HasEquivalenceRelationPartition(y)) then
## Similar lengths of partitions
##
if Length(EquivalenceRelationPartition(x)) <>
Length(EquivalenceRelationPartition(y)) then
return false;
fi;
## Similar lengths of the partition elements
##
if Set(EquivalenceRelationPartition(x), Length) <>
Set(EquivalenceRelationPartition(y), Length) then
return false;
fi;
## OK need to take a deeper look at the partition
##
for p in EquivalenceRelationPartition(x) do
f := First(EquivalenceRelationPartition(y), i->p[1] in i);
if f=fail then return false; fi;
if not Set(f)=Set(p) then return false; fi;
od;
return true;
else
TryNextMethod();
fi;
end);
#############################################################################
##
#M \in( <T>, <R> )
##
## Checks whether a 2-tuple is contained in a relation. Implementation
## for an equivalence relation stored as a partition.
##
## This method should be selected over all others since it assumes
## that the partition information has already been computed.
## It has been given a +1 rank which WILL NEED TUNING when the
## other methods are in.
##
InstallMethod(\in, "for eq relation with partition", true,
[IsList, IsEquivalenceRelation and HasEquivalenceRelationPartition], 1,
function(tup, rel)
local f; # first block that contains first tuple component
if Length(tup) <> 2 then
Error("Left hand side must be of length 2");
elif FamilyObj(tup) <>
FamilyObj(UnderlyingDomainOfBinaryRelation(rel)) then
Error("Left hand side must contain elements of relation's domain");
fi;
## if tuple is of the form (x,x) then it is in relation
##
if tup[1]=tup[2] then
return true;
fi;
## we must have partition with (x,y) in it for result to be true
##
f := First(EquivalenceRelationPartition(rel), b->tup[1] in b);
if f=fail then
return false; ## no block contains tup[1]
else
return tup[2] in f; ## tup[1] in non-trivial block
fi;
end);
#############################################################################
##
#M ImagesRepresentative( <rel>, <elm> ) . . . for equivalence relations
##
InstallMethod( ImagesRepresentative, "equivalence relations",
FamSourceEqFamElm, [IsEquivalenceRelation, IsObject], 0,
function( map, elm )
return elm;
end);
#############################################################################
##
#M PreImagesRepresentative( <rel>, <elm> ) . . . for equivalence relations
##
InstallMethod( PreImagesRepresentative, "equivalence relations",
FamRangeEqFamElm, [IsEquivalenceRelation, IsObject], 0,
function( map, elm )
return elm;
end);
#############################################################################
##
#M ImagesElm( <rel>, <elm> ) for equivalence relations with partition
##
InstallMethod( ImagesElm,
"for equivalence relation with partition and element",
FamSourceEqFamElm,
[IsEquivalenceRelation and HasEquivalenceRelationPartition,
IsObject],0,
function( rel, elm )
local p;
for p in EquivalenceRelationPartition(rel) do
if elm in p then
return p;
fi;
od;
## singleton case
##
return [elm];
end);
#############################################################################
##
#M PreImagesElm( <rel>, <elm> ) for equivalence relations with partition
##
InstallMethod( PreImagesElm,
"equivalence relations with partition and element",
FamRangeEqFamElm,
[IsEquivalenceRelation and HasEquivalenceRelationPartition,
IsObject],0,
function( rel, elm )
## Images and preimages are the same
##
return ImagesElm(rel, elm);
end);
#############################################################################
##
#M PrintObj( <eqr> ) for equivalence relation
##
InstallMethod( PrintObj, "for an equivalence relation", true,
[ IsEquivalenceRelation ], 0,
function( map )
Print( "<equivalence relation on ", Source( map ), " >" );
end );
#############################################################################
##
#M EquivalenceClasses( <E> )
##
## Wraparound function which calls the two-argument method
##
InstallMethod(EquivalenceClasses, "wraparound to call 2-argument version",
true, [IsEquivalenceRelation], 0,
e->EquivalenceClasses(e, UnderlyingDomainOfBinaryRelation(e))
);
#############################################################################
##
#M EquivalenceClasses( <E>, <C> )
##
## Returns the list of equivalence classes of the equivalence relation <E> that intersect <C>.
## This generic method will not terminate for an equivalence over an
## infinite set.
##
InstallOtherMethod(EquivalenceClasses, "for a generic equivalence relation",
true, [IsEquivalenceRelation, IsCollection], 0,
function(E, D)
local d, classes, iter, elm, p;
## If we already have a partition then return the equivalence
## class with first element as represenative
##
classes := [];
if HasEquivalenceRelationPartition(E) then
for p in EquivalenceRelationPartition(E) do
for elm in p do
if elm in D then
Add(classes, EquivalenceClassOfElementNC(E, elm));
break;
fi;
od;
od;
## Get the singletons
##
if Sum(List(EquivalenceRelationPartition(E),Length))<>Size(D) then
d := Difference(AsSet(D), Concatenation(EquivalenceRelationPartition(E)));
for p in d do
Add(classes, EquivalenceClassOfElementNC(E,p));
od;
fi;
return classes;
fi;
## We iterate over the underlying domain, and build up the list
## of classes as new ones are found.
##
iter:= Iterator(D);
classes:= [];
for elm in iter do
if ForAll(classes, x->not elm in x) then
Add(classes, EquivalenceClassOfElementNC(E, elm));
fi;
od;
return classes;
end);
#############################################################################
############################################################################
## #####################################
## ## ##
## ## Equivalence Classes TOCJ ##
## ## ##
## #####################################
############################################################################
#############################################################################
##
#M EquivalenceClassOfElement( <R>, <rep> )
#M EquivalenceClassOfElementNC( <R>, <rep> )
##
## Returns the equivalence class of an element <rep> with respect to an
## equivalence relation <R>. No calculation is performed at this stage.
## We do not always wish to check that <rep> is in the underlying set
## of <R>, since we may wish to use equivalence relations to perform
--> --------------------
--> maximum size reached
--> --------------------
[ zur Elbe Produktseite wechseln0.65Quellennavigators
Analyse erneut starten
]
|