|
#############################################################################
##
#W linear.gi Laurent Bartholdi
##
##
#Y Copyright (C) 2007, Laurent Bartholdi
##
#############################################################################
##
## This file implements the category of linear machines and elements, with
## a free algebra as stateset.
##
#############################################################################
# apply a ring homomorphism to expr. here im is the list of images of
# generators of a free algebra; expr is an element of the free algebra.
# the last two entries in im are 0 and 1.
BindGlobal("SUBS@", function(expr,im)
local mapped, i, j, m, e, w, one;
e := ExtRepOfObj(expr);
one := One(e[1]);
e := e[2];
if e=[] then return im[Length(im)-1]; fi;
mapped := fail;
for i in [2,4..Length(e)] do
w := e[i-1];
if w=[] then
m := im[Length(im)];
else
m := im[w[1]]^w[2];
for j in [4,6..Length(w)] do
if w[j]=1 then
m := m*im[w[j-1]];
else
m := m*im[w[j-1]]^w[j];
fi;
od;
fi;
if e[i]<>one then m := e[i]*m; fi;
if mapped=fail then mapped := m; else mapped := mapped+m; fi;
od;
return mapped;
end);
BindGlobal("AUGMENTATION@", function(expr)
local e;
e := ExtRepOfObj(expr);
if e[2]<>[] and e[2][1]=[] then
return e[2][2];
else
return e[1];
fi;
end);
BindGlobal("ALGEBRAELEMENT@", function(f,M,s)
return Objectify(NewType(f,IsLinearFRElement and IsFRElementStdRep),
[M,s]);
end);
############################################################################
##
#O Output(<Machine>, <State>)
#O Transition(<Machine>, <State>, <Input>, <Output>)
#O Transitions(<Machine>, <State>, <Input>)
##
InstallMethod(InitialState, "(FR) for a linear machine",
[IsLinearFRElement and IsFRElementStdRep],
E->E![2]);
InstallMethod(Output, "(FR) for a linear machine",
[IsLinearFRMachine and IsAlgebraFRMachineRep,IsElementOfFreeMagmaRing],
function(M,s)
return SUBS@(s,M!.output);
end);
InstallMethod(Output, "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep],
E->SUBS@(E![2],E![1]!.output));
InstallMethod(Transitions, "(FR) for a linear machine",
[IsLinearFRMachine and IsAlgebraFRMachineRep,IsElementOfFreeMagmaRing,IsVector],
function(M,s,a)
return a*SUBS@(s,M!.transitions);
end);
InstallMethod(Transition, "(FR) for a linear machine",
[IsLinearFRMachine and IsAlgebraFRMachineRep,IsElementOfFreeMagmaRing,IsVector,IsVector],
function(M,s,a,b)
return a*SUBS@(s,M!.transitions)*b;
end);
InstallMethod(Transitions, "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep,IsVector],
function(E,a)
return a*SUBS@(E![2],E![1]!.transitions);
end);
InstallOtherMethod(\[\], "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep,IsPosInt],
function(E,i)
return List(SUBS@(E![2],E![1]!.transitions)[i],v->ALGEBRAELEMENT@(FamilyObj(E),E![1],v));
end);
InstallMethod(Transition, "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep,IsVector,IsVector],
function(E,a,b)
return a*SUBS@(E![2],E![1]!.transitions)*b;
end);
InstallMethod(StateSet, "(FR) for a linear machine in vector rep",
[IsLinearFRMachine and IsAlgebraFRMachineRep],
M->M!.free);
InstallMethod(StateSet, "(FR) for a linear element in vector rep",
[IsLinearFRElement and IsFRElementStdRep],
E->E![1]!.free);
InstallMethod(GeneratorsOfFRMachine, "(FR) for a linear machine",
[IsLinearFRMachine and IsAlgebraFRMachineRep],
M->GeneratorsOfAlgebraWithOne(M!.free));
InstallOtherMethod(\^, "(FR) for a vector and a linear element",
[IsVector, IsLinearFRElement and IsFRElementStdRep],
function(v,E)
return v*MATRIX@(SUBS@(E![1],E![2]!.transitions),v->SUBS@(v,E![1]!.output));
end);
InstallMethod(Activity, "(FR) for a linear machine and a level",
[IsLinearFRElement and IsFRElementStdRep, IsInt],
function(E,n)
local i, j, b, m, mm, oldm, e, x;
m := [[E![2]]];
for j in [1..n] do
oldm := m;
m := [];
for x in oldm do
mm := List(E![1]!.transitions[1],i->[]);
for x in x do
e := SUBS@(x,E![1]!.transitions);
for i in [1..Length(e)] do
Append(mm[i],e[i]);
od;
od;
Append(m,mm);
od;
od;
m := MATRIX@(m,v->SUBS@(v,E![1]!.output));
b := ValueOption("blocks");
if b=fail then
ConvertToMatrixRep(m);
else
m := AsBlockMatrix(m,b,b);
fi;
if IsJacobianElement(E) then
m := LieObject(m);
fi;
return m;
end);
InstallMethod(Activities, "(FR) for a linear machine and a level",
[IsLinearFRElement and IsFRElementStdRep, IsInt],
function(E,n)
local b, i, j, m, mm, oldm, e, x, result;
m := [[E![2]]];
result := [[[SUBS@(E![2],E![1]!.output)]]];
b := ValueOption("blocks");
for j in [1..n] do
oldm := m;
m := [];
for x in oldm do
mm := List(E![1]!.transitions[1],i->[]);
for x in x do
e := SUBS@(x,E![1]!.transitions);
for i in [1..Length(e)] do
Append(mm[i],e[i]);
od;
od;
Append(m,mm);
od;
x := MATRIX@(m,v->SUBS@(v,E![1]!.output));
if b=fail then
ConvertToMatrixRep(m);
else
x := AsBlockMatrix(x,b,b);
fi;
if IsJacobianElement(E) then
x := LieObject(x);
fi;
Add(result,x);
od;
return result;
end);
BindGlobal("LINEARSTATES@", function(l)
local W, todo, x;
todo := NewFIFO(l);
W := VectorSpace(LeftActingDomain(l[1]),[],Zero(l[1]));
for x in todo do
if not x in W then
W := ClosureLeftModule(W,x);
for x in DecompositionOfFRElement(x) do
Append(todo,x);
od;
if RemInt(Dimension(W),10)=0 then
Info(InfoFR,2,"The states have dimension at least ",Dimension(W));
fi;
fi;
od;
return W;
end);
InstallOtherMethod(State, "(FR) for a linear element and two vectors",
[IsLinearFRElement and IsFRElementStdRep, IsVector, IsVector],
function(E,a,b)
return ALGEBRAELEMENT@(FamilyObj(E),E![1],a*SUBS@(E![2],E![1]!.transitions)*b);
end);
InstallOtherMethod(NestedMatrixState, "(FR) for a linear element and two lists",
[IsLinearFRElement and IsFRElementStdRep, IsList, IsList],
function(E,ilist,jlist)
local x, n;
x := E![2];
for n in [1..Length(ilist)] do
x := SUBS@(x,E![1]!.transitions)[ilist[n]][jlist[n]];
od;
return ALGEBRAELEMENT@(FamilyObj(E),E![1],x);
end);
InstallOtherMethod(NestedMatrixCoefficient, "(FR) for a linear element and two lists",
[IsLinearFRElement and IsFRElementStdRep, IsList, IsList],
function(E,ilist,jlist)
local x, n;
x := E![2];
for n in [1..Length(ilist)] do
x := SUBS@(x,E![1]!.transitions)[ilist[n]][jlist[n]];
od;
return SUBS@(x,E![1]!.output);
end);
InstallMethod(DecompositionOfFRElement, "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep],
function(E)
return MATRIX@(SUBS@(E![2],E![1]!.transitions),
v->ALGEBRAELEMENT@(FamilyObj(E),E![1],v));
end);
InstallMethod(States, "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep],
E->LINEARSTATES@([E]));
InstallMethod(States, "(FR) for a space of linear elements",
[IsVectorSpace and IsFRElementCollection],
V->LINEARSTATES@(GeneratorsOfVectorSpace(V)));
InstallMethod(States, "(FR) for a collection of linear elements",
[IsFRElementCollection],1, # give it higher priority than FR method
function(L)
if not ForAll(L,IsLinearFRElement) then
TryNextMethod();
fi;
return LINEARSTATES@(L);
end);
InstallMethod(TransposedFRElement, "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep],
function(E)
return AlgebraElementNC(FamilyObj(E),E![1]!.free,List(E![1]!.transitions,TransposedMat),E![1]!.output,E![2]);
end);
############################################################################
############################################################################
##
#O AlgebraMachine
#O AlgebraElement
##
InstallMethod(AlgebraMachineNC, "(FR) for family, free, transitions, output",
[IsFamily,IsFreeMagmaRing,IsTransitionTensor,IsVector],
function(f,free,transitions,output)
local M;
M := Objectify(NewType(f, IsLinearFRMachine and IsAlgebraFRMachineRep),
rec(free := free,
transitions := transitions,
output := output));
return M;
end);
BindGlobal("PREPARESUBS@", function(n,l)
if Length(l)<n then
Error("Substitution list is too short -- should have at least ",n," elements\n");
fi;
if Length(l)=n+2 then return l; fi;
l := ShallowCopy(l);
if Length(l)<n+1 then l[n+1] := Zero(l[1]); fi;
if Length(l)<n+2 then l[n+2] := One(l[1]); fi;
return l;
end);
InstallMethod(AlgebraMachine, "(FR) for domain, free, transitions, output",
[IsRing,IsFreeMagmaRing,IsTransitionTensor,IsVector],
function(r,free,transitions,output)
local n;
n := Length(GeneratorsOfAlgebraWithOne(free));
transitions := PREPARESUBS@(n,transitions);
output := PREPARESUBS@(n,output);
return AlgebraMachineNC(FRMFamily(r^Length(transitions[1])),
free,transitions,output);
end);
InstallMethod(AlgebraMachine, "(FR) for free, transitions, output",
[IsFreeMagmaRing,IsTransitionTensor,IsVector],
function(free,transitions,output)
return AlgebraMachine(LeftActingDomain(free),free,transitions,output);
end);
InstallMethod(UnderlyingFRMachine, "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep],
E->E![1]);
InstallMethod(AlgebraElementNC, "(FR) for family, free, transitions, output and input",
[IsFamily,IsFreeMagmaRing,IsTransitionTensor,
IsVector,IsElementOfFreeMagmaRing],
function(f,free,transitions,output,input)
local M;
M := AlgebraMachineNC(FRMFamily(f), free, transitions, output);
return ALGEBRAELEMENT@(f,M,input);
end);
InstallMethod(AlgebraElement, "(FR) for domain, free, transitions, output and input",
[IsRing,IsFreeMagmaRing,IsTransitionTensor,
IsVector,IsElementOfFreeMagmaRing],
function(r,free,transitions,output,input)
local M;
M := AlgebraMachine(r, free, transitions, output);
return ALGEBRAELEMENT@(FREFamily(M),M,input);
end);
InstallMethod(AlgebraElement, "(FR) for domain, free, transitions, output, input and category",
[IsRing,IsFreeMagmaRing,IsTransitionTensor,
IsVector,IsElementOfFreeMagmaRing,IsOperation],
function(r,free,transitions,output,input,cat)
local M, f;
M := AlgebraMachine(r, free, transitions, output);
if cat=IsJacobianElement then
f := FRJFAMILY@(M);
else
f := FREFamily(M);
fi;
return ALGEBRAELEMENT@(f,M,input);
end);
InstallMethod(AlgebraElement, "(FR) for free, transitions, output and input",
[IsFreeMagmaRing,IsTransitionTensor,IsVector,IsElementOfFreeMagmaRing],
function(free,transitions,output,input)
return AlgebraElement(LeftActingDomain(free),free,transitions,output,input);
end);
InstallMethod(FRElement, "(FR) for a linear machine and a state",
[IsLinearFRMachine and IsAlgebraFRMachineRep,IsElementOfFreeMagmaRing],
function(M,s)
return ALGEBRAELEMENT@(FREFamily(M),M,s);
end);
InstallMethod(FRElement, "(FR) for a linear machine, a state and a category",
[IsLinearFRMachine and IsAlgebraFRMachineRep,IsElementOfFreeMagmaRing,IsOperation],
function(M,s,cat)
local f;
if cat=IsJacobianElement then
f := FRJFAMILY@(M);
else
f := FREFamily(M);
fi;
return ALGEBRAELEMENT@(f,M,s);
end);
InstallMethod(FRElement, "(FR) for a linear element and a state",
[IsLinearFRElement and IsFRElementStdRep, IsElementOfFreeMagmaRing],
function(E,s)
return ALGEBRAELEMENT@(FamilyObj(E),E![1],s);
end);
InstallMethod(FRElement, "(FR) for a linear machine and a state index",
[IsLinearFRMachine and IsAlgebraFRMachineRep,IsInt],
function(M,s)
return ALGEBRAELEMENT@(FREFamily(M),M,GeneratorsOfAlgebraWithOne(M!.free)[s]);
end);
InstallMethod(FRElement, "(FR) for a linear element and a state index",
[IsLinearFRElement and IsFRElementStdRep, IsInt],
function(E,s)
return ALGEBRAELEMENT@(FamilyObj(E),E![1],GeneratorsOfAlgebraWithOne(E![1]!.free)[s]);
end);
InstallMethod(LieObject, "(FR) for an associative linear element",
[IsLinearFRElement and IsFRElementStdRep and IsAssociativeElement],
e->ALGEBRAELEMENT@(FRJFAMILY@(e),e![1],e![2]));
InstallMethod(AssociativeObject, "(FR) for a jacobian linear element",
[IsLinearFRElement and IsFRElementStdRep and IsJacobianElement],
e->ALGEBRAELEMENT@(FREFamily(e),e![1],e![2]));
#############################################################################
#############################################################################
##
#M ViewObj
#M String
#M Display
##
InstallMethod(ViewString, "(FR) for a linear machine",
[IsLinearFRMachine and IsAlgebraFRMachineRep],
function(M)
return CONCAT@("<Linear machine on alphabet ", LeftActingDomain(M), "^",
Length(M!.transitions[1]), " with generators ",
GeneratorsOfAlgebraWithOne(M!.free), ">");
end);
InstallMethod(ViewString, "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep],
function(E)
local s;
s := CONCAT@("<", LeftActingDomain(E), "^", Length(E![1]!.transitions[1]), "|",
E![2]);
if IsJacobianElement(E) then Append(s,"-"); fi;
Append(s,">");
return s;
end);
InstallMethod(String, "(FR) Linear machine to string",
[IsLinearFRMachine and IsAlgebraFRMachineRep],
function(M)
return CONCAT@("AlgebraMachine(",LeftActingDomain(M),", ", M!.transitions,", ", M!.output,")");
end);
InstallMethod(String, "(FR) Linear element to string",
[IsLinearFRElement and IsFRElementStdRep],
function(E)
local x;
if IsJacobianElement(E) then
x := ",IsJacobianElement";
else
x := "";
fi;
return CONCAT@("AlgebraElement(",LeftActingDomain(E),", ",
E![1]!.free,", ",
E![1]!.transitions,", ",
E![1]!.output,", ",E![2],x,")");
end);
BindGlobal("ALG2STRING@", function(expr)
local i, j, m, e, w, map, mapped, one;
e := ExtRepOfObj(expr);
one := One(e[1]);
e := e[2];
if e=[] then return "0"; fi;
mapped := fail;
for i in [2,4..Length(e)] do
w := e[i-1];
if w=[] then
map := "1";
else
map := fail;
for j in [2,4..Length(w)] do
m := FamilyObj(expr)!.names[w[j-1]];
if w[j]>1 then
m := Concatenation(m,"^",String(w[j]));
fi;
if map=fail then
map := m;
else
map := Concatenation(map,"*",m);
fi;
od;
fi;
if e[i]=one then;
elif e[i]=-one then
map := Concatenation("-",map);
elif IsFFE(e[i]) then
map := Concatenation(String(IntFFE(e[i])),"*",map);
else
map := Concatenation(String(e[i]),"*",map);
fi;
if mapped=fail then
mapped := map;
elif map[1]='-' then
mapped := Concatenation(mapped,map);
else
mapped := Concatenation(mapped,"+",map);
fi;
od;
return mapped;
end);
InstallMethod(DisplayString, "(FR) for a linear machine",
[IsLinearFRMachine and IsAlgebraFRMachineRep],
function(M)
local r, i, j, k, l, m, n, xlen, xprint, xrule, headlen, headrule, headblank, s;
r := LeftActingDomain(M);
n := Length(M!.transitions[1]);
m := Length(GeneratorsOfAlgebraWithOne(M!.free));
xlen := Maximum(List(Flat(M!.transitions),x->Length(ALG2STRING@(x))))+1;
xprint := x->String(ALG2STRING@(x),xlen-1);
xrule := ListWithIdenticalEntries(xlen,'-');
headlen := Length(String(r))+1;
headrule := ListWithIdenticalEntries(headlen,'-');
headblank := ListWithIdenticalEntries(headlen,' ');
s := Concatenation(String(r,headlen)," |");
for i in [1..n] do
APPEND@(s,String(i,QuoInt(xlen,2)+1),String("",xlen-QuoInt(xlen,2)),"|");
od;
APPEND@(s,"\n");
APPEND@(s,headrule, "-+");
for i in [1..n] do APPEND@(s,xrule,"-+"); od;
APPEND@(s,"\n");
for i in [1..n] do
APPEND@(s,String(i,headlen)," |");
for j in [1..m] do
if j>1 then APPEND@(s,headblank," |"); fi;
for k in [1..n] do
APPEND@(s," ",xprint(M!.transitions[j][i][k])," |");
od;
APPEND@(s,"\n");
od;
APPEND@(s,headrule,"-+");
for i in [1..n] do APPEND@(s,xrule,"-+"); od;
APPEND@(s,"\n");
od;
APPEND@(s,"Output:");
for i in [1..m] do
APPEND@(s," ");
if IsFFE(M!.output[i]) then
APPEND@(s,IntFFE(M!.output[i]));
else
APPEND@(s,M!.output[i]);
fi;
od;
APPEND@(s,"\n");
return s;
end);
InstallMethod(DisplayString, "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep],
function(E)
local s;
s := DisplayString(E![1]);
if IsJacobianElement(E) then
Append(s, "Jacobian; ");
fi;
APPEND@(s,"Initial state: ",ALG2STRING@(E![2]),"\n");
return s;
end);
#############################################################################
#############################################################################
##
#M AsAlgebraMachine
#M AsAlgebraElement
##
BindGlobal("ASALGEBRAMACHINE@", function(r,M)
local s, f, g, inj, A, trans, out, zero, i, x;
g := GeneratorsOfFRMachine(M);
f := FreeAssociativeAlgebraWithOne(r,ElementsFamily(FamilyObj(M!.free))!.names);
inj := MagmaHomomorphismByFunctionNC(StateSet(M),f,w->MappedWord(w,g,GeneratorsOfAlgebraWithOne(f)));
trans := [];
out := [];
zero := List(AlphabetOfFRObject(M),i->List(AlphabetOfFRObject(M),j->Zero(f)));
for s in g do
x := StructuralCopy(zero);
for i in AlphabetOfFRObject(M) do
x[i][Output(M,s,i)] := Transition(M,s,i)^inj;
od;
Add(trans,x);
Add(out,One(r));
od;
Add(trans,zero);
Add(trans,One(zero));
Add(out,Zero(r));
Add(out,One(r));
A := AlgebraMachineNC(FRMFamily(r^Size(AlphabetOfFRObject(M))),f,trans,out);
SetCorrespondence(A,inj);
return A;
end);
InstallMethod(AsAlgebraMachine, "(FR) for a semigroup FR machine",
[IsRing,IsSemigroupFRMachine],
ASALGEBRAMACHINE@);
InstallMethod(AsAlgebraMachine, "(FR) for a monoid FR machine",
[IsRing,IsMonoidFRMachine],
ASALGEBRAMACHINE@);
InstallMethod(AsAlgebraMachine, "(FR) for a group FR machine",
[IsRing,IsGroupFRMachine],
function(r,M)
local N, A;
N := AsMonoidFRMachine(M);
A := ASALGEBRAMACHINE@(r,N);
A!.Correspondence := Correspondence(N)*Correspondence(A);
return A;
end);
InstallMethod(AsAlgebraMachine, "(FR) for a Mealy machine",
[IsRing,IsMealyMachine and IsMealyMachineIntRep],
function(r,M)
local N, A;
Info(InfoFR,2,"AsAlgebraMachine: converting to monoid machine");
N := AsMonoidFRMachine(M);
A := ASALGEBRAMACHINE@(r,N);
A!.Correspondence := List(Correspondence(N),x->x^Correspondence(A));
return A;
end);
InstallMethod(AsLinearMachine, "(FR) for an FR machine",
[IsRing,IsFRMachine],
AsAlgebraMachine);
BindGlobal("VECTOR2ALGEBRA@", function(fam,M)
local i, f, g, N, trans, out;
f := FreeAssociativeAlgebraWithOne(LeftActingDomain(M),Length(M!.output));
g := GeneratorsOfAlgebraWithOne(f);
trans := [];
for i in [1..Length(g)] do
Add(trans,MATRIX@(M!.transitions,v->v[i]*g));
od;
Add(trans,Zero(trans[1]));
Add(trans,One(trans[1]));
out := ShallowCopy(M!.output);
Add(out,Zero(out[1]));
Add(out,One(out[1]));
N := AlgebraMachineNC(fam,f,trans,out);
SetCorrespondence(N,g);
return N;
end);
InstallMethod(AsAlgebraMachine, "(FR) for a vector machine",
[IsLinearFRMachine and IsVectorFRMachineRep],
M->VECTOR2ALGEBRA@(FamilyObj(M),M));
InstallMethod(AsAlgebraMachine, "(FR) for an algebra machine",
[IsLinearFRMachine],
X->X);
InstallMethod(AsVectorMachine, "(FR) for an algebra machine",
[IsLinearFRMachine and IsAlgebraFRMachineRep],
function(M)
local gens, states, B, corr, d, trans, out, i, j, s, t;
gens := List(GeneratorsOfFRMachine(M),x->FRElement(M,x));
states := LINEARSTATES@(gens);
B := Basis(states);
d := List(B,DecompositionOfFRElement);
trans := [];
out := List(B,Output);
for i in [1..Length(d[1])] do
t := [];
for j in [1..Length(d[1])] do
Add(t,List(d,s->Coefficients(B,s[i][j])));
od;
Add(trans,t);
od;
M := VectorMachineNC(FamilyObj(M),trans,out);
SetCorrespondence(M,List(gens,s->Coefficients(B,s)));
return M;
end);
InstallMethod(AsVectorMachine, "(FR) for a linear machine",
[IsLinearFRMachine],
X->X);
BindGlobal("ASALGEBRAELEMENT@", function(r,E)
local A;
A := ASALGEBRAMACHINE@(r,E![1]);
return FRElement(A,E![2]^Correspondence(A));
end);
InstallMethod(AsAlgebraElement, "(FR) for a semigroup FR element",
[IsRing,IsSemigroupFRElement],
ASALGEBRAELEMENT@);
InstallMethod(AsAlgebraElement, "(FR) for a monoid FR element",
[IsRing,IsMonoidFRElement],
ASALGEBRAELEMENT@);
InstallMethod(AsAlgebraElement, "(FR) for a group FR element",
[IsRing,IsGroupFRElement],
function(r,E)
local M, A;
M := AsMonoidFRMachine(E![1]);
A := ASALGEBRAMACHINE@(r,M);
return FRElement(A,(E![2]^Correspondence(M))^Correspondence(A));
end);
InstallMethod(AsAlgebraElement, "(FR) for a Mealy element",
[IsRing,IsMealyElement and IsMealyMachineIntRep],
function(r,E)
Info(InfoFR,2,"AsAlgebraElement: converting to monoid element");
return ASALGEBRAELEMENT@(r,AsMonoidFRElement(E));
end);
InstallMethod(AsLinearElement, "(FR) for an FR element",
[IsRing,IsFRElement],
AsAlgebraElement);
InstallMethod(AsAlgebraElement, "(FR) for a vector element",
[IsLinearFRElement and IsVectorFRMachineRep],
function(E)
local N;
N := VECTOR2ALGEBRA@(FRMFamily(E),E);
return FRElement(N,Correspondence(N)[1]);
end);
InstallMethod(AsAlgebraElement, "(FR) for a linear element",
[IsLinearFRElement],
X->X);
InstallMethod(AsVectorElement, "(FR) for an algebra element",
[IsLinearFRElement and IsFRElementStdRep],
function(E)
local B, input, output, trans, dec, i, j, k, row, col;
B := Basis(States(E));
input := Coefficients(B,E);
output := List(B,Output);
dec := List(B,DecompositionOfFRElement);
trans := [];
for i in [1..Length(dec[1])] do
row := [];
for j in [1..Length(dec[1])] do
col := [];
for k in dec do
Add(col,Coefficients(B,k[i][j]));
od;
Add(row,col);
od;
Add(trans,row);
od;
B := VECTORMINIMIZE@(FamilyObj(E),LeftActingDomain(E),
trans,output,input,0,false);
return B;
end);
InstallMethod(AsVectorElement, "(FR) for a linear element",
[IsLinearFRElement],
X->X);
#############################################################################
############################################################################
##
#M InverseOp
#M OneOp
#M ZeroOp
##
InstallMethod(InverseOp, "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep],
function(E)
Info(InfoFR, 1, "InverseOp: converting to vector element");
return InverseOp(AsVectorElement(E));
end);
InstallMethod(OneOp, "(FR) for a linear machine",
[IsLinearFRMachine and IsAlgebraFRMachineRep],
function(M)
local f, n;
n := Length(M!.transitions);
f := FreeAssociativeAlgebraWithOne(LeftActingDomain(M),0);
return AlgebraMachineNC(FamilyObj(M),f,
M!.transitions{[n-1..n]},M!.output{[n-1..n]});
end);
InstallMethod(OneOp, "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep],
E->ALGEBRAELEMENT@(FamilyObj(E),E![1],One(E![2])));
InstallMethod(ZeroOp, "(FR) for a linear machine",
[IsLinearFRMachine and IsAlgebraFRMachineRep],
function(M)
local f, n;
n := Length(M!.transitions);
f := FreeAssociativeAlgebraWithOne(LeftActingDomain(M),0);
return AlgebraMachineNC(FamilyObj(M),f,
M!.transitions{[n-1..n]},M!.output{[n-1..n]});
end);
InstallMethod(ZeroOp, "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep],
E->ALGEBRAELEMENT@(FamilyObj(E),E![1],Zero(E![2])));
InstallMethod(\+, "for two linear machines", IsIdenticalObj,
[IsLinearFRMachine and IsAlgebraFRMachineRep,
IsLinearFRMachine and IsAlgebraFRMachineRep],
function(M,N)
local x, y, m, trans, i;
if LeftActingDomain(M)<>LeftActingDomain(N) then
Error("Cannot (yet) add two machines with different acting domains\n");
fi;
x := ElementsFamily(FamilyObj(M!.free))!.names;
y := ElementsFamily(FamilyObj(N!.free))!.names;
if Intersection(x,y)=[] then
x := Concatenation(x,y);
else
x := Concatenation(List(x,x->Concatenation(x,".1")),
List(y,x->Concatenation(x,".2")));
fi;
x := FreeAssociativeAlgebraWithOne(LeftActingDomain(M),x);
m := Length(M!.output)-2;
y := [GeneratorsOfAlgebraWithOne(x){[1..m]},
GeneratorsOfAlgebraWithOne(x){[1..Length(N!.output)-2]+m}];
Add(y[1],Zero(x)); Add(y[1],One(x));
Add(y[2],Zero(x)); Add(y[2],One(x));
trans := [];
for i in [1..m] do
Add(trans,MATRIX@(M!.transitions[i],v->SUBS@(v,y[1])));
od;
for i in N!.transitions do
Add(trans,MATRIX@(i,v->SUBS@(v,y[2])));
od;
x := AlgebraMachineNC(FamilyObj(M),x,
trans,Concatenation(M!.output{[1..m]},N!.output));
SetCorrespondence(x,y);
return x;
end);
InstallMethod(\+, "for two linear elements", IsIdenticalObj,
[IsLinearFRElement and IsFRElementStdRep,
IsLinearFRElement and IsFRElementStdRep],
function(E,F)
local M;
if E![1]=F![1] then
return ALGEBRAELEMENT@(FamilyObj(E),E![1],E![2]+F![2]);
else
M := E![1]+F![1];
return ALGEBRAELEMENT@(FamilyObj(E),M,
SUBS@(E![2],Correspondence(M)[1])+
SUBS@(F![2],Correspondence(M)[2]));
fi;
end);
InstallMethod(\+, "for a scalar and a linear element",
[IsScalar,IsLinearFRElement and IsFRElementStdRep],
function(x,E)
if not IsRat(x) and not x in LeftActingDomain(E) then TryNextMethod(); fi; # matrix?
return ALGEBRAELEMENT@(FamilyObj(E),E![1],x*One(E![1]!.free)+E![2]);
end);
InstallMethod(\+, "for a linear element and a scalar",
[IsLinearFRElement and IsFRElementStdRep,IsScalar],
function(E,x)
if not IsRat(x) and not x in LeftActingDomain(E) then TryNextMethod(); fi; # matrix?
return ALGEBRAELEMENT@(FamilyObj(E),E![1],E![2]+x*One(E![1]!.free));
end);
InstallMethod(\+, "(FR) for two linear elements", IsIdenticalObj,
[IsLinearFRElement and IsVectorFRMachineRep,
IsLinearFRElement and IsFRElementStdRep],
function(E,F)
Info(InfoFR, 1, "\\+: converting first argument to algebra element");
return AsAlgebraElement(E)+F;
end);
InstallMethod(\+, "(FR) for two linear elements", IsIdenticalObj,
[IsLinearFRElement and IsFRElementStdRep,
IsLinearFRElement and IsVectorFRMachineRep],
function(E,F)
Info(InfoFR, 1, "\\+: converting second argument to algebra element");
return E+AsAlgebraElement(F);
end);
InstallMethod(AdditiveInverseSameMutability, "for a linear machine",
[IsLinearFRMachine and IsAlgebraFRMachineRep],
function(M)
return AlgebraMachineNC(FamilyObj(M),M!.free,M!.transitions,-M!.output);
end);
InstallMethod(AdditiveInverseSameMutability, "for a linear element",
[IsLinearFRElement and IsFRElementStdRep],
function(E)
return ALGEBRAELEMENT@(FamilyObj(E),E![1],-E![2]);
end);
InstallMethod(\*, "for two linear machines", IsIdenticalObj,
[IsLinearFRMachine and IsAlgebraFRMachineRep,
IsLinearFRMachine and IsAlgebraFRMachineRep],
function(M,N)
Error("Multiplication of algebra machines is not implemented. Please use ADD\n");
end);
InstallMethod(\*, "for two linear elements", IsIdenticalObj,
[IsLinearFRElement and IsFRElementStdRep and IsAssociativeElement,
IsLinearFRElement and IsFRElementStdRep and IsAssociativeElement],
function(E,F)
local M;
if E![1]=F![1] then
return ALGEBRAELEMENT@(FamilyObj(E),E![1],E![2]*F![2]);
else
M := E![1]+F![1];
return ALGEBRAELEMENT@(FamilyObj(E),M,
SUBS@(E![2],Correspondence(M)[1])*
SUBS@(F![2],Correspondence(M)[2]));
fi;
end);
InstallMethod(\*, "for two linear elements", IsIdenticalObj,
[IsLinearFRElement and IsFRElementStdRep and IsJacobianElement,
IsLinearFRElement and IsFRElementStdRep and IsJacobianElement],
function(E,F)
local M;
if E![1]=F![1] then
return ALGEBRAELEMENT@(FamilyObj(E),E![1],LieBracket(E![2],F![2]));
else
M := E![1]+F![1];
return ALGEBRAELEMENT@(FamilyObj(E),M,
LieBracket(SUBS@(E![2],Correspondence(M)[1]),
SUBS@(F![2],Correspondence(M)[2])));
fi;
end);
InstallMethod(PthPowerImage, "for a linear element",
[IsLinearFRElement and IsFRElementStdRep and IsJacobianElement],
function(x)
local p;
p := Characteristic(LeftActingDomain(x));
if not IsPrime(p) then TryNextMethod(); fi;
return ALGEBRAELEMENT@(FamilyObj(x),x![1],x![2]^p);
end);
InstallMethod(PthPowerImage, "for a linear element and a number",
[IsLinearFRElement and IsFRElementStdRep and IsJacobianElement,IsInt],
function(x,n)
local p;
p := Characteristic(LeftActingDomain(x));
if not IsPrime(p) then TryNextMethod(); fi;
return ALGEBRAELEMENT@(FamilyObj(x),x![1],x![2]^(p^n));
end);
InstallMethod(\*, "for a scalar and a linear machine",
[IsScalar,IsLinearFRMachine and IsAlgebraFRMachineRep],
function(x,M)
if not IsRat(x) and not x in LeftActingDomain(M) then TryNextMethod(); fi; # matrix?
return AlgebraMachineNC(FamilyObj(M),M!.free,M!.transitions,x*M!.output);
end);
InstallMethod(\*, "for a linear machine and a scalar",
[IsLinearFRMachine and IsAlgebraFRMachineRep,IsScalar],
function(M,x)
if not IsRat(x) and not x in LeftActingDomain(M) then TryNextMethod(); fi; # matrix?
return AlgebraMachineNC(FamilyObj(M),M!.free,M!.transitions,M!.output*x);
end);
InstallMethod(\*, "for a scalar and a linear element",
[IsScalar,IsLinearFRElement and IsFRElementStdRep],
function(x,E)
if not IsRat(x) and not x in LeftActingDomain(E) then TryNextMethod(); fi; # matrix?
return ALGEBRAELEMENT@(FamilyObj(E),E![1],x*E![2]);
end);
InstallMethod(\*, "for a linear element and a scalar",
[IsLinearFRElement and IsFRElementStdRep,IsScalar],
function(E,x)
if not IsRat(x) and not x in LeftActingDomain(E) then TryNextMethod(); fi; # matrix?
return ALGEBRAELEMENT@(FamilyObj(E),E![1],E![2]*x);
end);
InstallMethod(\*, "(FR) for two linear elements", IsIdenticalObj,
[IsLinearFRElement and IsVectorFRMachineRep,
IsLinearFRElement and IsFRElementStdRep],
function(E,F)
Info(InfoFR, 1, "\\*: converting first argument to algebra element");
return AsAlgebraElement(E)*F;
end);
InstallMethod(\*, "(FR) for two linear elements", IsIdenticalObj,
[IsLinearFRElement and IsFRElementStdRep,
IsLinearFRElement and IsVectorFRMachineRep],
function(E,F)
Info(InfoFR, 1, "\\*: converting second argument to algebra element");
return E*AsAlgebraElement(F);
end);
############################################################################
############################################################################
##
#M Minimized . . . . . . . . . . . . . . . . . . . .minimize linear machine
##
InstallMethod(Minimized, "(FR) for a linear machine",
[IsLinearFRMachine and IsAlgebraFRMachineRep],
function(M)
local f, gens, imgs, i, j, found, newgens, N, trans, out;
gens := List(GeneratorsOfFRMachine(M),i->FRElement(M,i));
imgs := [];
newgens := [];
for i in [1..Length(gens)] do
if IsZero(gens[i]) then
Add(imgs,[fail,-1]);
found := true;
elif IsOne(gens[i]) then
Add(imgs,[fail,0]);
found := true;
else
found := false;
for j in imgs do if gens[i]=j[1] then
found := true; Add(imgs,[fail,j[2]]); break;
fi; od;
fi;
if not found then
Add(newgens,ElementsFamily(FamilyObj(M!.free))!.names[i]);
Add(imgs,[gens[i],Length(newgens)]);
fi;
od;
f := FreeAssociativeAlgebraWithOne(LeftActingDomain(M),newgens);
gens := [];
for j in [1..Length(imgs)] do
if imgs[j][2] = -1 then
Add(gens,Zero(f));
elif imgs[j][2] = 0 then
Add(gens,One(f));
else
Add(gens,GeneratorsOfAlgebraWithOne(f)[imgs[j][2]]);
fi;
od;
Add(gens,Zero(f));
Add(gens,One(f));
trans := [];
out := [];
for j in [1..Length(gens)-2] do if imgs[j][1]<>fail then
Add(trans,MATRIX@(M!.transitions[j],v->SUBS@(v,gens)));
Add(out,M!.output[j]);
fi; od;
Add(trans,Zero(trans[1]));
Add(trans,One(trans[1]));
Add(out,Zero(out[1]));
Add(out,One(out[1]));
N := AlgebraMachineNC(FamilyObj(M),f,trans,out);
SetCorrespondence(N,gens);
return N;
end);
InstallMethod(Minimized, "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep],
E->E);
############################################################################
############################################################################
##
#M IsOne
#M IsZero
#M =
#M <
##
InstallMethod(\=, "(FR) for two linear machines", IsIdenticalObj,
[IsLinearFRMachine and IsAlgebraFRMachineRep,
IsLinearFRMachine and IsAlgebraFRMachineRep],
function(M,N)
return M!.free=N!.free and M!.transitions=N!.transitions
and M!.output=N!.output;
end);
InstallMethod(\<, "(FR) for two linear machines", IsIdenticalObj,
[IsLinearFRMachine and IsAlgebraFRMachineRep,
IsLinearFRMachine and IsAlgebraFRMachineRep],
function(M,N)
return M!.free<N!.free or (M!.free=N!.free and
(M!.transitions<N!.transitions or
(M!.transitions=N!.transitions and M!.output<N!.output)));
end);
InstallMethod(IsOne, "(FR) for a linear machine",
[IsLinearFRMachine and IsAlgebraFRMachineRep],
function(M)
return M!.output=[];
end);
InstallMethod(IsZero, "(FR) for a linear machine",
[IsLinearFRMachine and IsAlgebraFRMachineRep],
function(M)
return M!.output=[];
end);
if IsPackageMarkedForLoading("gbnp","") then
ReadPackage("FR","gap/linear-gbnp.gi");
else
BindGlobal("ALGEBRAISZERO@", function(M,x)
local zero, todo, i;
zero := Subspace(M!.free,[]);
todo := NewFIFO([x]);
for x in todo do
if not x in zero then
if not IsZero(SUBS@(x,M!.output)) then return false; fi;
zero := ClosureLeftModule(zero,x);
x := SUBS@(x,M!.transitions);
for i in x do Append(todo,i); od;
fi;
od;
return true;
end);
fi;
InstallMethod(\=, "(FR) for two linear elements", IsIdenticalObj,
[IsLinearFRElement and IsFRElementStdRep,
IsLinearFRElement and IsFRElementStdRep],
function(E,F)
local M;
if IsIdenticalObj(E![1], F![1]) then
return ALGEBRAISZERO@(E![1],E![2]-F![2]);
else
M := E![1]+F![1];
return ALGEBRAISZERO@(M,
SUBS@(E![2],Correspondence(M)[1])-
SUBS@(F![2],Correspondence(M)[2]));
fi;
end);
InstallMethod(\=, "(FR) for two linear elements", IsIdenticalObj,
[IsLinearFRElement and IsVectorFRMachineRep,
IsLinearFRElement and IsFRElementStdRep],
function(E,F)
Info(InfoFR, 1, "\\=: converting first argument to algebra element");
return AsAlgebraElement(E)=F;
end);
InstallMethod(\=, "(FR) for two linear elements", IsIdenticalObj,
[IsLinearFRElement and IsFRElementStdRep,
IsLinearFRElement and IsVectorFRMachineRep],
function(E,F)
Info(InfoFR, 1, "\\=: converting second argument to algebra element");
return E=AsAlgebraElement(F);
end);
InstallMethod(\<, "(FR) for two linear elements", IsIdenticalObj,
[IsLinearFRElement and IsFRElementStdRep,
IsLinearFRElement and IsFRElementStdRep],
function(left,right)
local out, trans, todo, mach, idle, states, i, j, t, row, x, y, a, b, c, p, u;
if left=right then return false; fi;
# now we know they're different, it's just a matter of finding where
mach := [left![1],right![1]];
todo := [[left![2]],[right![2]]];
out := [[],[]];
trans := [[],[]];
states := [VectorSpace(LeftActingDomain(left),[left]),
VectorSpace(LeftActingDomain(right),[right])];
i := 1;
repeat
idle := [true,true];
for p in [1,2] do
if i <= Length(todo[p]) then
idle[p] := false;
x := SUBS@(todo[p][i],mach[p]!.transitions);
Add(out[p],SUBS@(todo[p][i],mach[p]!.output));
t := [];
Add(trans[p],t);
for a in x do
row := [];
Add(t,row);
for b in a do
c := FRElement(mach[p],b);
y := Coefficients(Basis(states[p]),c);
if y<>fail then
Add(row,y);
else
Add(todo[p],b);
y := LeftModuleByGenerators(LeftActingDomain(states[p]),Concatenation(BasisVectors(Basis(states[p])),[c]));
for u in trans do for u in u do
Add(u,Zero(LeftActingDomain(states[p])));
od; od;
Add(row,Coefficients(Basis(y),c));
states[p] := y;
fi;
od;
od;
fi;
od;
if idle[2] then
return false; # right machine is finite state, left has more states
elif idle[1] then
return true; # left machine is finite state, right has more states
elif out[1][i]<>out[2][i] then
return out[1][i]<out[2][i]; # compare outputs lexicographically
fi;
for j in [1..i] do # compare transitions lexicographically
if trans[1][i][j]<>trans[2][i][j] then
return trans[1][i][j]<trans[2][i][j];
fi;
od;
for j in [1..i-1] do
if trans[1][j][i]<>trans[2][j][i] then
return trans[1][j][i]<trans[2][j][i];
fi;
od;
i := i+1;
until false;
end);
InstallMethod(\<, "(FR) for a vector and a linear element", IsIdenticalObj,
[IsLinearFRElement and IsFRElementStdRep,
IsLinearFRElement and IsVectorFRMachineRep],
function(E,F)
Info(InfoFR, 1, "\\<: converting second argument to linear element");
return E<AsAlgebraElement(F);
end);
InstallMethod(\<, "(FR) for a linear and a vector element", IsIdenticalObj,
[IsLinearFRElement and IsVectorFRMachineRep,
IsLinearFRElement and IsFRElementStdRep],
function(E,F)
Info(InfoFR, 1, "\\<: converting first argument to linear element");
return AsAlgebraElement(E)<F;
end);
InstallMethod(IsOne, "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep],
function(E)
return ALGEBRAISZERO@(E![1],E![2]-One(E![1]!.free));
end);
InstallMethod(IsZero, "(FR) for a linear element",
[IsLinearFRElement and IsFRElementStdRep],
function(E)
return ALGEBRAISZERO@(E![1],E![2]);
end);
############################################################################
############################################################################
##
#M Nice basis
##
InstallHandlingByNiceBasis("IsLinearFRElementSpace", rec(
# info stores 'gens', the generators;
# 'where', a list of tuples [ilist,jlist,values] of the evaluations
# of generators at (nested) coordinates (ilist,jlist)
# 'hom', a quotient map from the vector space on the generators
# to a basis of V
detect := function(R,l,V,z)
if l=[] then
return IsLinearFRElement(z) and IsFRElementStdRep(z)
and LeftActingDomain(z)=R;
else
return ForAll(l,x->IsLinearFRElement(x) and LeftActingDomain(x)=R)
and not ForAll(l,IsVectorFRMachineRep);
# there's a faster method for purely vector FR element spaces
fi;
end,
NiceFreeLeftModuleInfo := function(V)
local m, n, info, o, t, space, kernel, image,
i, j, x, todo, machine;
info := rec(gens := ShallowCopy(GeneratorsOfLeftModule(V)),
where := []);
m := Length(info.gens);
if m=0 then
return rec(trivial := true);
fi;
n := Length(info.gens[1]![1]!.transitions[1]);
for i in [1..m] do
if IsVectorFRMachineRep(info.gens[i]) then
info.gens[i] := AsAlgebraElement(info.gens[i]);
fi;
od;
space := LeftActingDomain(V)^m;
image := Subspace(space,[]);
todo := [[],[],[]]; # row address, col addr, element
machine := UnderlyingFRMachine(info.gens[1]);
if ForAll(info.gens,x->UnderlyingFRMachine(x)=machine) then
todo[3] := List(info.gens,x->x![2]);
else
machine := Sum(List(info.gens,UnderlyingFRMachine));
j := 0;
for i in [1..m] do
x := Length(GeneratorsOfAlgebraWithOne(info.gens[i]![1]!.free));
o := Concatenation(GeneratorsOfAlgebraWithOne(machine!.free){[j+1..j+x]},[Zero(machine!.free),One(machine!.free)]);
Add(todo[3],SUBS@(info.gens[i]![2],o));
j := j+x;
od;
machine := Minimized(machine);
for i in [1..m] do
todo[3][i] := SUBS@(todo[3][i],Correspondence(machine));
od;
fi;
todo := NewFIFO([todo]);
for t in todo do
o := List(t[3],v->SUBS@(v,machine!.output));
if not o in image then
image := ClosureLeftModule(image,o);
Add(info.where,[t[1],t[2],o]);
kernel := NullspaceMat(TransposedMat(Basis(image)));
if kernel=[] or IsZero(kernel*info.gens) then
break;
fi;
fi;
x := List(t[3],e->SUBS@(e,machine!.transitions));
# !!! and reduce... keep space of FreeAlgebra-tuples that have been considered.
# unfortunately, GAP cannot handle vector spaces over machine!.free
for i in [1..n] do
for j in [1..n] do
Add(todo,[Concatenation(t[1],[i]),Concatenation(t[2],[j]),
List(x,m->m[i][j])]);
od;
od;
od;
info.hom := NaturalHomomorphismBySubspace(space,Subspace(space,kernel));
info.basis := List(Basis(Range(info.hom)),
v->PreImagesRepresentativeNC(info.hom,v));
for i in info.where do
i[3] := info.basis*i[3];
od;
return info;
end,
NiceVector := function(V,v)
local i, info, m, x;
info := NiceFreeLeftModuleInfo(V);
if IsBound(info.trivial) then
if IsZero(v) then return []; else return fail; fi;
fi;
m := [];
x := [];
for i in info.where do
Add(m,i[3]);
Add(x,NestedMatrixCoefficient(v,i[1],i[2]));
od;
m := ShallowCopy(TransposedMat(m));
Add(m,x);
m := NullspaceMat(m);
if m=[] then
return fail;
else
m := -m[1]{[1..Length(m[1])-1]}/m[1][Length(m[1])];
if (m*info.basis)*info.gens=v then
return m;
else
return fail;
fi;
fi;
end,
UglyVector := function(V,v)
local info;
info := NiceFreeLeftModuleInfo(V);
if IsBound(info.trivial) then
if v=[] then return Zero(V); else return fail; fi;
fi;
if v in Range(info.hom) then
return PreImagesRepresentativeNC(info.hom,v)*info.gens;
else
return fail;
fi;
end));
InstallMethod(IsFiniteDimensional, "(FR) for an algebra of linear elements",
# could be made a global method; but it's so primitive that
# it's probably useless in general. Indeed it either returns true
# or runs forever.
[IsAlgebra and IsLinearFRElementSpace],
function(A)
local R, B, V, todo, t, v;
R := LeftActingDomain(A);
B := [];
V := VectorSpace(R,B,Zero(A));
todo := NewFIFO(GeneratorsOfAlgebra(A));
for t in todo do
if not t in V then
Add(B, t);
V := LeftModuleByGenerators(R, B);
Append(todo, t*GeneratorsOfAlgebra(A));
fi;
od;
return true; # else we're in an infinite loop
end);
############################################################################
[ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet)
]
|