############################################################################ ## #W aut-basics.gi Manuel Delgado <mdelgado@fc.up.pt> #W Jose Morais <josejoao@fc.up.pt> ## ## #Y Copyright (C) 2004, CMUP, Universidade do Porto, Portugal ## ############################################################################# ## ## This file contains some basic functions or generic methods involving ## automata. ## ############################################################################# ## #F IsDeterministicAutomaton(A) ## ## Tests if A is a deterministic automaton ##
InstallGlobalFunction(IsDeterministicAutomaton, function(A)
return IsAutomatonObj(A) and A!.type = "det"; end); ############################################################################# ## #F IsNonDeterministicAutomaton(A) ## ## Tests if A is a non deterministic automaton ##
InstallGlobalFunction(IsNonDeterministicAutomaton, function(A)
return IsAutomatonObj(A) and A!.type = "nondet"; end); ############################################################################# ## #F IsEpsilonAutomaton(A) ## ## Tests if A is an automaton with epsilon transitions ##
InstallGlobalFunction(IsEpsilonAutomaton, function(A)
return IsAutomatonObj(A) and A!.type = "epsilon"; end); ############################################################################# ## #F AlphabetOfAutomaton(A) ## ## Returns the number of symbols in the alphabet of the automaton ##
InstallGlobalFunction(AlphabetOfAutomaton, function( A ) if not IsAutomaton(A) then
Error("The argument must be an automaton"); fi;
return(ShallowCopy(A!.alphabet)); end); ############################################################################# ## #F AlphabetOfAutomatonAsList(A) ## ## Returns the alphabet of the automaton as a list. ## ## Note that when the alphabet of the automaton is given as an integer ## (meaning the number of symbols) less than 27 it returns the list "abcd....". ## If the alphabet is given by means of an integer greater than 27, the ## function returns [ "a1", "a2", "a3", "a4", ... ]. ##
InstallGlobalFunction(AlphabetOfAutomatonAsList, function( A )
local a; if not IsAutomaton(A) then
Error("The argument must be an automaton"); fi;
return(ShallowCopy(FamilyObj(A)!.alphabet)); end); ############################################################################# ## #F TransitionMatrixOfAutomaton(A) ## ## returns the transition matrix of the automaton ##
InstallGlobalFunction(TransitionMatrixOfAutomaton, function( A ) if not IsAutomaton(A) then
Error("The argument must be an automaton"); fi;
return(A!.transitions); end); ############################################################################# ## #F InitialStatesOfAutomaton(A) ## ## returns the initial states of the automaton ##
InstallGlobalFunction(InitialStatesOfAutomaton, function( A ) if not IsAutomaton(A) then
Error("The argument must be an automaton"); fi;
return(ShallowCopy(A!.initial)); end); ############################################################################# ## #F SetInitialStatesOfAutomaton(A) ## ## Sets the initial states of the automaton ##
InstallGlobalFunction(SetInitialStatesOfAutomaton, function( A, I ) if not IsAutomaton(A) then
Error("The first argument must be an automaton"); fi; if IsInt(I) then if not (I > 0 and I <= A!.states) then
Error("The second argument must be a list of positive integers (or just a positive integer) <= ", A!.states); fi;
A!.initial := [I];
return; fi; if not (IsList(I) and ForAll(I, i->IsPosInt(i)) and ForAll(I, i-> i <= A!.states)) then
Error("The second argument must be a list of positive integers (or just a positive integer) <= ", A!.states); fi;
A!.initial := ShallowCopy(I); end); ############################################################################# ## #F FinalStatesOfAutomaton(A) ## ## returns the final states of the automaton ##
InstallGlobalFunction(FinalStatesOfAutomaton, function( A ) if not IsAutomaton(A) then
Error("The argument must be an automaton"); fi;
return(ShallowCopy(A!.accepting)); end); ############################################################################# ## #F SetFinalStatesOfAutomaton(A, F) ## ## Sets the final states of the automaton ##
InstallGlobalFunction(SetFinalStatesOfAutomaton, function( A, F ) if not IsAutomaton(A) then
Error("The first argument must be an automaton"); fi; if IsInt(F) then if not (F > 0 and F <= A!.states) then
Error("The second argument must be a list of positive integers (or just a positive integer) <= ", A!.states); fi;
A!.accepting := [F];
return; fi; if not (IsList(F) and ForAll(F, i->IsPosInt(i)) and ForAll(F, i-> i <= A!.states)) then
Error("The second argument must be a list of positive integers <= ", A!.states); fi;
A!.accepting := ShallowCopy(F); end); ############################################################################# ## #A NumberStatesOfAutomaton(A) ## ## returns the number of states of the automaton ##
InstallGlobalFunction(NumberStatesOfAutomaton, function( A ) if not IsAutomaton(A) then
Error("The argument must be an automaton"); fi;
return(A!.states); end);
############################################################################# ## #F CopyAutomaton(A) ## ## Returns a copy of the automaton A. ##
InstallGlobalFunction(CopyAutomaton, function ( A ) if not IsAutomatonObj(A) then
Error("The argument must be an automaton"); fi;
return Automaton( ShallowCopy( A!.type ), A!.states,
AlphabetOfAutomatonAsList(A), StructuralCopy( A!.transitions ),
ShallowCopy( A!.initial ),
ShallowCopy( A!.accepting ) ); end);
############################################################################# ## #F NullCompletionAutomaton(aut) ## ## Given an incomplete deterministic automaton returns a deterministic ## automaton completed with a new null state. ##
InstallGlobalFunction(NullCompletionAutomaton, function(aut)
local t, b, i, j;
if not IsAutomatonObj(aut) then
Error("The argument must be an automaton"); fi; if not aut!.type = "det"then
Error("<aut> must be deterministic"); fi;
t := []; if IsDenseAutomaton(aut) then
return aut; fi;
b := aut!.states + 1; for i in [1 .. aut!.alphabet] do
t[i] := Concatenation(aut!.transitions[i], [b]); for j in [1 .. b] do if t[i][j] = 0then
t[i][j] := b; fi;
od;
od;
return Automaton("det", b, AlphabetOfAutomatonAsList(aut), t, aut!.initial, aut!.accepting); end);
############################################################################# ## #F ListPermutedAutomata(A) ## ## Given an automaton, returns a list of automata with permuted states ##
InstallGlobalFunction(ListPermutedAutomata, function(A)
local perms, # List of permutations
perm, # Permutation
T, # Transition function of the permuted automaton
list, # List of the permuted automata
a, q;
if not IsAutomatonObj(A) then
Print("The argument to PermutedAutomata must be an automaton\n");
return; fi; if A!.type = "epsilon"then
list := []; # List of the permuted automata
perms := PermutationsOfN(A!.states); # Compute the list of permutations for perm in perms do# For each permutation compute the permuted automaton
T := []; # New transition function for a in [1 .. A!.alphabet] do
T[a] := []; for q in [1 .. A!.states] do if A!.transitions[a][q] = [] then
T[a][perm[q]] := []; else
T[a][perm[q]] := List(A!.transitions[a][q], s -> perm[s]); fi;
od;
od;
Add(list, Automaton("epsilon", A!.states, AlphabetOfAutomatonAsList(A), T, List(A!.initial, q -> perm[q]), List(A!.accepting, q -> perm[q])));
od; elif A!.type = "nondet"then
list := []; # List of the permuted automata
perms := PermutationsOfN(A!.states); # Compute the list of permutations for perm in perms do# For each permutation compute the permuted automaton
T := []; # New transition function for a in [1 .. A!.alphabet] do
T[a] := []; for q in [1 .. A!.states] do if A!.transitions[a][q] = [] then
T[a][perm[q]] := []; else
T[a][perm[q]] := List(A!.transitions[a][q], s -> perm[s]); fi;
od;
od;
Add(list, Automaton("nondet", A!.states, AlphabetOfAutomatonAsList(A), T, List(A!.initial, q -> perm[q]), List(A!.accepting, q -> perm[q])));
od; else
list := []; # List of the permuted automata
perms := PermutationsOfN(A!.states); # Compute the list of permutations for perm in perms do# For each permutation compute the permuted automaton
T := []; # New transition function for a in [1 .. A!.alphabet] do
T[a] := []; for q in [1 .. A!.states] do if A!.transitions[a][q] = 0then
T[a][perm[q]] := 0; else
T[a][perm[q]] := perm[A!.transitions[a][q]]; fi;
od;
od;
Add(list, Automaton("det", A!.states, AlphabetOfAutomatonAsList(A), T, [perm[A!.initial[1]]], List(A!.accepting, q -> perm[q])));
od; fi;
return(list); end);
############################################################################# ## #F PermutedAutomaton(A, perm) ## ## Given an automaton and a list representing a permutation of the states ## outputs the permuted automaton. ##
InstallGlobalFunction(PermutedAutomaton, function(A, perm)
local len, list, T, a, q;
if not IsAutomatonObj(A) then
Print("The argument to PermutedAutomaton must be an automaton\n");
return; fi; if not (A!.states = Length(perm) and Set(perm) = [1 .. A!.states]) then
Error("The list must represent a permutation of the states of the automaton"); fi;
len := 0;
list := [];
T := []; # New transition function if A!.type = "det"then for a in [1 .. A!.alphabet] do
T[a] := []; for q in [1 .. A!.states] do if A!.transitions[a][q] = 0then
T[a][perm[q]] := 0; else
T[a][perm[q]] := perm[A!.transitions[a][q]]; fi;
od;
od;
return(Automaton("det", A!.states, AlphabetOfAutomatonAsList(A), T, [perm[A!.initial[1]]], List(A!.accepting, q -> perm[q]))); elif A!.type = "nondet"then for a in [1 .. A!.alphabet] do
T[a] := []; for q in [1 .. A!.states] do if A!.transitions[a][q] = [] then
T[a][perm[q]] := []; else
T[a][perm[q]] := List(A!.transitions[a][q], x->perm[x]); fi;
od;
od;
return(Automaton("nondet", A!.states, AlphabetOfAutomatonAsList(A), T, List(A!.initial, q -> perm[q]), List(A!.accepting, q -> perm[q]))); else for a in [1 .. A!.alphabet] do
T[a] := []; for q in [1 .. A!.states] do if A!.transitions[a][q] = [] then
T[a][perm[q]] := []; else
T[a][perm[q]] := List(A!.transitions[a][q], x->perm[x]); fi;
od;
od;
return(Automaton("epsilon", A!.states, AlphabetOfAutomatonAsList(A), T, List(A!.initial, q -> perm[q]), List(A!.accepting, q -> perm[q]))); fi;
end);
############################################################################# ## #F IsDenseAutomaton(A) ## ## Tests whether a deterministic automaton is complete ##
InstallGlobalFunction(IsDenseAutomaton, function(A)
local n;
if not IsDeterministicAutomaton(A) then
Error("<A> must be a deterministic automaton"); fi;
return(ForAll(A!.transitions, n -> IsDenseList(n) and
ForAll(n,IsPosInt))); end); ############################################################################# ## #F IsInverseAutomaton ## ## Tests whether a deterministic automaton is inverse, i.e. each letter of ## the alphabet induces a partial injective function on the vertices. ##
InstallGlobalFunction(IsInverseAutomaton,function(aut)
local T, L, i;
if not IsDeterministicAutomaton(aut) then
Error("<A> must be a deterministic automaton"); fi;
T := StructuralCopy(aut!.transitions); for L in T do for i in [1..Length(L)] do if L[i] = 0then
Unbind(L[i]); fi;
od; if Length(Compacted(L))<> Length(Set(L)) then
return false; fi;
od;
return true; end); ############################################################################# ## #F IsPermutationAutomaton ## ## Tests whether a deterministic automaton is a permutation automaton, ## i.e. each letter of the alphabet induces a permutation on the vertices. ##
InstallGlobalFunction(IsPermutationAutomaton,function(aut)
local T, L, i;
if not IsDeterministicAutomaton(aut) then
Error("<A> must be a deterministic automaton"); fi;
T := StructuralCopy(aut!.transitions); for L in T do for i in [1..Length(L)] do if L[i] = 0then
return false; fi;
od; if aut!.states <> Length(Set(L)) then
return false; fi;
od;
return true; end);
############################################################################# #F ListSinkStatesAut(A) ## ## Returns the list of sink states of the automaton A. ## q is said to be a sink state iff it is not initial nor accepting and ## for all a in A!.alphabet A!.transitions[a][q] = q ## ## <A> must be an automaton. ## ##
InstallGlobalFunction(ListSinkStatesAut, function(A)
local list, j;
if not IsAutomatonObj(A) then
Error("The argument to ListSinkStatesAut must be an automaton"); fi;
list := []; if A!.type = "det"then for j in [1 .. A!.states] do if ForAll([1 .. A!.alphabet], i -> A!.transitions[i][j] = 0 or A!.transitions[i][j] = j) then
Add(list, j); fi;
od; elif A!.type = "nondet"then for j in [1 .. A!.states] do if ForAll([1 .. A!.alphabet], i -> A!.transitions[i][j] = [] or A!.transitions[i][j] = [j]) then
Add(list, j); fi;
od; else
return(ListSinkStatesAut(EpsilonToNFA(A))); fi;
list := Difference(list, A!.initial);
list := Difference(list, A!.accepting);
return(list); end);
############################################################################# ## #F RemovedSinkStates(A) ## ## Removes the sink states of the automaton A ##
InstallGlobalFunction(RemovedSinkStates, function(A)
local aut, ls, initial_states, final_states, new_ini, new_fin,
transitions, Al, alph, n_states, matrix, p, a, q;
if not IsDeterministicAutomaton(A) then
Error("The argument must be a deterministic automaton"); fi;
aut := CopyAutomaton(A);
ls := Difference([1..aut!.states], ListSinkStatesAut(aut));
initial_states := Intersection(aut!.initial, ls);
final_states := Intersection(aut!.accepting, ls);
new_ini := List(initial_states, s -> Position(ls, s));
new_fin := List(final_states, s -> Position(ls, s));
transitions := aut!.transitions; # the transition matrix of the original automaton
Al := aut!.alphabet;
alph := FamilyObj(aut)!.alphabet;
n_states := Length(ls); # the number of states of the subautomaton
matrix := NullMat(Al, n_states); # the transition matrix of the subautomaton for p in [1 .. n_states] do# for each new state p for a in [1 .. Al] do# for each letter of the alphabet of CG
q := transitions[a][ls[p]]; # here we found the edge: Position(ls, p) --a--> q if q in ls then# if q is in ls
matrix[a][p] := Position(ls, q); # the edge belongs to the subautomaton, so add it fi;
od;
od;
return Automaton("det", n_states, alph, matrix, new_ini, new_fin); end);
############################################################################# ## #F IsRecognizedByAutomaton(A, word, alphabet) ## ## Tests if a given word is recognized by the given automaton ##
InstallGlobalFunction(IsRecognizedByAutomaton, function(arg)
local A, w, alph, a, s, c;
if Length(arg) < 2then
Error("Please supply an automaton and a string"); fi; if not IsAutomatonObj(arg[1]) then
Error("The first argument must be an automaton"); fi; if not IsList(arg[2]) then
Error("The second argument must be a list"); fi;
A := MinimalAutomaton(arg[1]);
w := arg[2];
alph := AlphabetOfAutomatonAsList(A); # if IsList(alph) then for a in w do if not a in alph then
Error("....");
return(false);
Error(".."); fi;
od; # else # if alph < 22 then # alph := "abcdefghijklmnopqrstu"; # else # alph := List([1..alph], k -> Concatenation("a", String(k))); # fi; # fi; #
s := A!.initial[1]; for c in w do
a := Position(alph, c); if a = 0 or a > A!.alphabet then
return(false); fi;
s := A!.transitions[a][s];
od; if s in A!.accepting then
return(true); else
return(false); fi; end);
############################################################################# ## #F NormalizedAutomaton(A) ## ## Returns the equivalent automaton but the initial state is numbered 1 ## and the final states have the last numbers ##
InstallGlobalFunction(NormalizedAutomaton, function(A)
local comp_list, q, p, r, X, n, s, j;
if not IsAutomaton(A) then
Error("The argument must be a deterministic automaton"); fi; if not IsDeterministicAutomaton(A) then
Error("The argument must be a deterministic automaton"); fi;
comp_list := function(ls, re)# auxiliary function # ls is a list with holes with length q; # re is a list # with as many elements as the holes in ls # which may occur at the end of the list
local h, k, i;
h := Filtered([1 .. q], n -> not IsBound(ls[n]));
k := 1; for i in h do
ls[i] := re[k];
Unbind(re[k]);
k := k + 1;
od;
ls := Concatenation(ls,Compacted(re));
return ls; end;
q := A!.states;
p := [];
r := A!.initial[1];
X := ShallowCopy(A!.accepting);
X := Difference(X, A!.initial);
n := Length(X);
s := Difference(Difference([1 .. q], A!.initial), A!.accepting);
p[r] := 1; for j in [1 .. n] do
p[X[j]] := q - n +j;
od;
s := [2..q-n];
return(PermutedAutomaton(A, comp_list(p, s))); end);
############################################################################# ## #F UnionAutomata(A, B) ## ## Produces the disjoint union of the automata A and B ##
InstallGlobalFunction(UnionAutomata, function(A, B)
local QA, T, a, i, I, F, mA,mB;
if not (IsAutomatonObj( A ) and IsAutomatonObj( B )) then
Error( "The arguments must be two automata" ); fi;
if A!.type = "epsilon"then
mA := AlphabetOfAutomaton(A)-1; else
mA := AlphabetOfAutomaton(A); fi; if B!.type = "epsilon"then
mB := AlphabetOfAutomaton(B)-1; else
mB := AlphabetOfAutomaton(B); fi; if mA <> mB then
Error( "The arguments must be two automata over the same alphabet" ); fi;
QA := A!.states;
T := List( A!.transitions, ShallowCopy ); if A!.type <> "epsilon" and B!.type = "epsilon"then
Add(T,[]); fi;
for a in [ 1 .. B!.alphabet ] do for i in [ 1 .. B!.states ] do if B!.transitions[a][i] = 0then
T[a][QA + i] := 0; else
T[a][QA + i] := QA + B!.transitions[a][i]; fi;
od;
od; if A!.type = "epsilon" and B!.type <> "epsilon"then for i in [1..B!.states] do
Add(T[mA+1],0);
od; fi;
I := ShallowCopy( A!.initial );
Append( I, QA + B!.initial );
if A!.type = "epsilon" or B!.type = "epsilon"then
return Automaton( "epsilon", QA + B!.states, mA+1, T, I, F ); else
return Automaton( "nondet", QA + B!.states, AlphabetOfAutomatonAsList( A ), T, I, F ); fi; end );
############################################################################# ## #F ReversedAutomaton(A) ## ## Returns the automaton obtained from A by reversing its edges and ## switching the accepting and initial states ##
InstallGlobalFunction(ReversedAutomaton, function(A)
local T, a, q, s, u;
if not IsAutomatonObj(A) then
Error("The argument must be an automaton"); fi;
T := []; for a in [1 .. A!.alphabet] do
T[a] := []; for q in [1 .. A!.states] do
T[a][q] := [];
od;
od; for a in [1 .. A!.alphabet] do for q in [1 .. A!.states] do
s := A!.transitions[a][q]; if IsList(s) then for u in s do if IsPosInt(u) then
Add(T[a][u], q); fi;
od; elif IsPosInt(s) then
Add(T[a][s], q); fi;
od;
od;
return(Automaton("nondet", A!.states, AlphabetOfAutomatonAsList(A), T, ShallowCopy(A!.accepting), ShallowCopy(A!.initial))); end);
############################################################################# ## #F IsReversibleAutomaton(A) ## ## Tests if the given automaton is reversible in the sense ## that the reversed automaton might be regarded as deterministic ## automaton ##
############################################################################
local B,#W Jose Morais <josejoao@fc.up.pt>
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 2 ##
local ,, T , ;
notIsAutomatonObj) then
return(false)java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
if
Print =]
return(false A. "" fi if LengthT]= [;
( automaton oneacceptingstate)
return(false);
java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 7
fi for q in [od; if LengthB!transitions[]q) >1then
return(false); fi;
od;
od;
return(true); end);
############################################################################# ## #F ProductOfLanguages(a1, a2) ## ## Given two regular languages (as automata or rational expressions), ## returns an automaton that recognizes the concatenation of the given ## languages, that is, the set of words <M>uv</M> such that ## <M>u</M> belongs to the first language and <M>v</M> ## belongs to the second language. ##
java.lang.StringIndexOutOfBoundsException: Range [22, 21) out of bounds for length 51
[i0java.lang.StringIndexOutOfBoundsException: Range [28, 29) out of bounds for length 28
()then
a1; elif java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 2
a1 := RatExpToAut(a1); else
Error("The java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28 fi if java.lang.StringIndexOutOfBoundsException: Range [25, 24) out of bounds for length 25
a2nkStatesAut(A) elif ## q is said to be a sink state iff it is not initial nor accepting and
a2## <A> must be an automaton. else
Error(ListSinkStatesAut, function(A) fi;
java.lang.StringIndexOutOfBoundsException: Range [12, 9) out of bounds for length 21
Error("A1 and ;
;
=()
a2: (java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
!t ="then
for a in [1..a2!.alphabet] do
q 1..]do if a2!.transitions[a][q] = 0then
Add(T[a], []); else
.transitionsa[]+ a1!states]; fi;
od;
;
for q in a1!.accepting do
s a2!initial do
Add([1!alphabet +1[,a1!.tates+s;
od;
od;
",a1!.states +a2!states,java.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 55
a1. 1
T,
ShallowCopy(a1!. final_states := Intersection(aut: (!accepting,ls)java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 53
List(a2!.accepting, q -> q + a1!.states));
A := MinimalAutomaton(A);
A = (A;
FamilyObj(A)!.alphabet := AlphabetOfAutomatonAsList(a1);
return(A alph =(aut!alphabetjava.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37 end);matrix: Al ) of the subautomaton
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.