diff --git a/lib/accum.gd b/lib/accum.gd new file mode 100644 index 00000000000..b676859987c --- /dev/null +++ b/lib/accum.gd @@ -0,0 +1,22 @@ +DeclareCategory("IsAccumulator", IsCopyable); + +DeclareOperation("ValueAccumulator", [IsAccumulator]); + +DeclareConstructor("AccumulatorCons", [IsAccumulator, IsObject]); + +DeclareOperation("RightAdd", [IsAccumulator and IsMutable, IsExtAElement] ); +DeclareOperation("LeftAdd", [IsAccumulator and IsMutable, IsExtAElement] ); +DeclareOperation("Subtract", [IsAccumulator and IsMutable, IsNearAdditiveElementWithInverse] ); +DeclareOperation("Negate", [IsAccumulator and IsMutable] ); +DeclareOperation("RightMultiply", [IsAccumulator and IsMutable, IsExtLElement] ); +DeclareOperation("LeftMultiply", [IsAccumulator and IsMutable, IsExtRElement] ); +DeclareOperation("RightDivide", [IsAccumulator and IsMutable, IsMultiplicativeElementWithInverse] ); +DeclareOperation("LeftDivide", [IsAccumulator and IsMutable, IsMultiplicativeElementWithInverse] ); +DeclareOperation("Invert", [IsAccumulator and IsMutable] ); +DeclareOperation("Exponentiate", [IsAccumulator and IsMutable, IsInt] ); +DeclareOperation("Conjugate", [IsAccumulator and IsMutable, IsMultiplicativeElementWithInverse] ); + +DeclareCategory("IsPermutationAccumulator", IsAccumulator); +DeclareOperation("OnPointsAccumulator", [IsPosInt, IsPermutationAccumulator]); +DeclareOperation("OnTuplesAccumulator", [IsRowVector and IsCyclotomicCollection, + IsPermutationAccumulator]); diff --git a/lib/genacc.gi b/lib/genacc.gi new file mode 100644 index 00000000000..22065e4794d --- /dev/null +++ b/lib/genacc.gi @@ -0,0 +1,30 @@ +InstallMethod(Conjugate, [IsAccumulator and IsMutable, IsMultiplicativeElementWithInverse], + function(acc, x) + acc := LeftDivide(acc, x); + if acc = fail then + return fail; + fi; + return RightMultiply(acc,x); +end); + +InstallMethod(Exponentiate, [IsAccumulator and IsMutable, IsInt], + function(acc, pow) + local v, i; + if pow < 0 then + Invert(acc); + pow := -pow; + fi; + v := ValueAccumulator(acc); + if pow = 0 then + RightDivide(acc,v); + else + for i in [2..pow] do + RightMultiply(acc,v); + od; + fi; + return acc; +end); + + + + diff --git a/lib/lazypermacc.gi b/lib/lazypermacc.gi new file mode 100644 index 00000000000..3b7b55c8b75 --- /dev/null +++ b/lib/lazypermacc.gi @@ -0,0 +1,144 @@ +DeclareRepresentation("IsLazyPermutationAccumulatorRep", + IsPositionalObjectRep and IsPermutationAccumulator, 2); +BindGlobal("AccumulatorsFamily", NewFamily(IsAccumulator)); + +BindGlobal("LazyPermutationAccumulatorDefaultType", + NewType(AccumulatorsFamily, IsMutable and IsLazyPermutationAccumulatorRep)); + + +InstallMethod(AccumulatorCons,[IsLazyPermutationAccumulatorRep, IsPerm], + function(type, p) + return Objectify(LazyPermutationAccumulatorDefaultType, [[],[p],[],[true]]); +end); + +InstallMethod(RightMultiply, [IsLazyPermutationAccumulatorRep and IsMutable, IsPerm], + function(acc,p) + Add(acc![2],p); + Add(acc![4],true); + return acc; +end); + +InstallMethod(LeftMultiply, [IsLazyPermutationAccumulatorRep and IsMutable, IsPerm], + function(acc,p) + Add(acc![1],p); + Add(acc![3],true); + return acc; +end); + +InstallMethod(RightDivide, [IsLazyPermutationAccumulatorRep and IsMutable, IsPerm], + function(acc,p) + Add(acc![2],p); + Add(acc![4],false); + return acc; + +end); + +InstallMethod(LeftDivide, [IsLazyPermutationAccumulatorRep and IsMutable, IsPerm], + function(acc,p) + Add(acc![1],p); + Add(acc![3],false); + return acc; +end); + +InstallMethod(Invert, [IsLazyPermutationAccumulatorRep and IsMutable], + function(acc) + local x; + x := acc![1]; + acc![1] := acc![2]; + acc![2] := x; + x := acc![3]; + acc![3] := List(acc![4], y-> not y); + acc![4] := List(x, y-> not y); + return acc; +end); + +InstallMethod(Exponentiate, [IsLazyPermutationAccumulatorRep and IsMutable, IsInt], + function (acc, pow) + local i, new, x, l, j; + if pow < 0 then + Invert(acc); + pow := -pow; + fi; + if pow = 0 then + for i in [1..4] do + acc![i] := []; + od; + return acc; + fi; + if pow = 1 then + return acc; + fi; + new := [[],[],[],[]]; + for i in [1..4] do + x := acc![i]; + l := ShallowCopy(x); + for j in [2..pow] do + Append(l,x); + od; + acc![i] := l; + od; + return acc; +end); + + +InstallMethod(ShallowCopy,[IsLazyPermutationAccumulatorRep], + function(acc) + return Objectify(LazyPermutationAccumulatorDefaultType, List([1..4], + i -> ShallowCopy(acc![i]))); +end); + +# +# Could be implemented better usign an EagerPermutationAccumulator +# + +InstallMethod(ValueAccumulator, [IsLazyPermutationAccumulatorRep], + function(acc) + local v, l, i; + v := (); + l := Length(acc![1]); + for i in [l,l-1..1] do + if acc![3][i] then + v := v*acc![1][i]; + else + v := v/acc![1][i]; + fi; + od; + for i in [1..Length(acc![2])] do + if acc![4][i] then + v := v*acc![2][i]; + else + v := v/acc![2][i]; + fi; + od; + acc![2] := [v]; + acc![1] := []; + acc![3] := []; + acc![4] := [true]; + return v; +end); + + +InstallMethod(OnPointsAccumulator,[IsPosInt, IsLazyPermutationAccumulatorRep], + function(pt, acc) + local l, i; + l := Length(acc![1]); + for i in [l,l-1..1] do + if acc![3][i] then + pt := pt^acc![1][i]; + else + pt := pt/acc![1][i]; + fi; + od; + for i in [1..Length(acc![2])] do + if acc![4][i] then + pt := pt^acc![2][i]; + else + pt := pt/acc![2][i]; + fi; + od; + return pt; +end); + + + + diff --git a/lib/permacc.gi b/lib/permacc.gi new file mode 100644 index 00000000000..49c86b5230e --- /dev/null +++ b/lib/permacc.gi @@ -0,0 +1,12 @@ +InstallMethod(RightAdd,[IsPermutationAccumulator and IsMutable, IsExtAElement], ReturnFail); +InstallMethod(LeftAdd,[IsPermutationAccumulator and IsMutable, IsExtAElement], ReturnFail); +InstallMethod(Subtract,[IsPermutationAccumulator and IsMutable, + IsNearAdditiveElementWithInverse], ReturnFail); +InstallMethod(Negate,[IsPermutationAccumulator and IsMutable], ReturnFail); + +InstallMethod(OnTuplesAccumulator, + [IsSmallList and IsCyclotomicCollection and IsRowVector, IsPermutationAccumulator], + function(tup,acc) + return List(tup, x -> OnPointsAccumulator(acc,x)); +end); + diff --git a/lib/read3.g b/lib/read3.g index b4febe5dc33..90b4c10e60b 100644 --- a/lib/read3.g +++ b/lib/read3.g @@ -251,3 +251,8 @@ ReadLib("function.gd"); # random sources ReadLib("random.gi"); + +# accumulators + +ReadLib("accum.gd"); + diff --git a/lib/read5.g b/lib/read5.g index 9064433d171..abb0c0666e0 100644 --- a/lib/read5.g +++ b/lib/read5.g @@ -258,3 +258,9 @@ ReadLib( "function.gi"); # floateans, now really install all handlers ReadLib( "float.gi" ); ReadLib( "ieee754.g" ); + +# accumulators + +ReadLib("genacc.gi"); +ReadLib("permacc.gi"); +ReadLib("lazypermacc.gi");