############################################################################# ## #W rat-def.gi Manuel Delgado <mdelgado@fc.up.pt> #W Jose Morais <josejoao@fc.up.pt> ## ## ## #Y Copyright (C) 2004, CMUP, Universidade do Porto, Portugal ## ## ## Rational Expressions ## ## RatExpOnnLetters( n, operation, list ) ## ## Constructs a rational expression on n letters. ## ## The name of the operation is "product", "union" or "star" ## list is a list (with one element in the case of "star") of rational ## expressions or a list consisting of an integer when the rational ## expression is a single letter. ## ## Example ## ## r:=RatExpOnnLetters(2,"union",[RatExpOnnLetters(2,[],[1]), ## RatExpOnnLetters(2,[],[2])]); ## (Due to the function PrintObj that follows, GAP writes aUb ) ## ## ProductRatExp(r,r); ## GAP writes (aUb)(aUb) ## ## UnionRatExp(StarRatExp(r),ProductRatExp(r,StarRatExp(r))); ## GAP writes (aUb)*U(aUb)(aUb)* ## ## The empty word is the rational expression: ## RatExpOnnLetters(5,[],[]); ## GAP writes empty set ## (5 may be replaced by any natural number) ## The empty set is considered a rational expression: ## RatExpOnnLetters(n,[],"empty_set"); ############################################################################
DeclareRepresentation( "IsRationalExpressionRep", IsComponentObjectRep,
[ "op", "list_exp" ] );
############################################################################
InstallGlobalFunction( RatExpOnnLettersObj, function( Fam, ratexpression )
return Objectify( NewType( Fam, IsRatExpOnnLettersObj and
IsRationalExpressionRep and IsAttributeStoringRep), ratexpression ); end );
############################################################################ ## #GF RatExpOnnLetters ## ## Constructs a rational expression on n letters. See example above. ##
InstallGlobalFunction( RatExpOnnLetters, function( n, operation, list )
local k, F, l, exp, list_exp, R;
if not (operation = "product" or operation = "union" or
operation = "star" or operation = [ ]) then
Error("Wrong operation given in RatExpOnnLetters"); fi;
if not (IsPosInt( n ) or IsList(n)) then
Error( "<n> must be a positive integer or a list" ); fi;
if operation = "star"then if not IsRationalExpression(list) then
Error("The star must be on a rational expression"); fi; elif not IsList(list) then
Error("list must be a list"); elif operation = [] then if not(list = [ ] or list = "empty_set" or (Length(list)=1
and IsPosInt(list[1]))) then
Error("list must be the empty list, a list of one positive integer or \"empty_set\""); fi; elif not ForAll(list, x -> IsPosInt(x) or IsRationalExpression(x)) then
Error("list must be a list of positive integers/rational expressions"); fi;
if operation <> [] and operation <> "star"then for k in [1..Length(list)] do if IsPosInt(list[k]) then
list[k] := RatExpOnnLetters(n, [ ], [k]); fi;
od; fi;
if operation = [] and Length(list) > 1 and list <> "empty_set"then
Error("When <operation> is [], the third argument must be the empty list, a list of length 1 or \"empty_list\""); fi;
# Construct the family of rational expressions on n letters. if IsInt(n) then
F:= NewFamily( Concatenation( "RatExp", String(n), "Letters" ),
IsRatExpOnnLettersObj ); else
F:= NewFamily( Concatenation( "RatExp", String(Length(n)), "Letters" ),
IsRatExpOnnLettersObj ); fi;
# Install the data. if IsPosInt(n) then
F!.alphabet := n; if n < 27then
F!.alphabet2 := List([1..n], i -> jascii[68+i]); else
F!.alphabet2 := List([1..n], i -> Concatenation("a", String(i))); fi; else # l := SSortedList(n);
l := n; if'@' in l then
Error("'@' must not be in the alphabet"); fi;
F!.alphabet := Length(l);
F!.alphabet2 := l; fi;
exp := rec(op := operation,
list_exp := list );
R := RatExpOnnLettersObj( F, exp );
# Return the rational expression.
return R; end );
############################################################################ ## #F RatExpToString(r) ##
InstallGlobalFunction( RatExpToString, function( r, count )
local A, i, hasUnion, xstr, xout, str, e, ret, flag;
if not IsRatExpOnnLettersObj(r) then
Error("The argument to RatExpToString must be a rational expression"); fi;
A := []; if IsChar(AlphabetOfRatExpAsList(r)[1]) then for i in AlphabetOfRatExpAsList(r) do
Add(A, [i]);
od; else for i in AlphabetOfRatExpAsList(r) do
Add(A, i);
od; fi;
# Tests if a rational expression has a union rational subexpression
hasUnion := function(r) if r!.op = [] then
return(false); elif r!.op = "star"then
return(false); elif r!.op = "union"then
return(true); else
return(ForAny(r!.list_exp, e -> hasUnion(e))); fi; end;
if r!.list_exp = "empty_set"then
return(["empty_set", count]); elif r!.op = [] then
count := count + 1; if r!.list_exp = [] then
return(["@", count]); else if IsString(A[r!.list_exp[1]]) then
return([String(ShallowCopy(A[r!.list_exp[1]])), count]); else
xstr := "";
xout := OutputTextString( xstr, false );
PrintTo( xout, ShallowCopy(A[r!.list_exp[1]]));
CloseStream( xout );
return([xstr, count]); fi; fi; elif r!.op = "product"then
str := ""; for e in r!.list_exp do
ret := RatExpToString(e, count);
count := ret[2]; if hasUnion(e) then
str := Concatenation(str, "(", ret[1], ")"); else
str := Concatenation(str, ret[1]); fi;
od;
return([str, count]); elif r!.op = "union"then
flag := false;
str := ""; for e in r!.list_exp do
ret := RatExpToString(e, count);
count := ret[2]; if e!.op = "union"then if str = ""then
str := ret[1]; else
str := Concatenation(str, "U", ret[1]); fi; else if str = ""then
str := ret[1]; else
str := Concatenation(str, "U", ret[1]); fi; fi;
od;
return([str, count]); else if r!.list_exp!.op = [] then# This is star of a single letter
ret := RatExpToString(r!.list_exp, count);
return([Concatenation(ret[1], "*"), ret[2]]); else
ret := RatExpToString(r!.list_exp, count);
return([Concatenation("(", ret[1], ")*"), ret[2]]); fi; fi; end);
####################################################################### ## #M PrintObj(R) ## ## Is used to display a rational expression <R> in a form that is readable by ## a human being ##
InstallMethod( PrintObj, "for rational expressions",
true,
[ IsRatExpOnnLettersObj and IsRationalExpressionRep ], 0, function(r)
local ret, string;
ret := RatExpToString(r, 0);
string := ret[1];
Setter(SizeRatExp)(r,ret[2]);
Print(string); end );
############################################################################# ## #F RationalExpression(arg) ## ## Given the number of alphabet symbols and a string (S) returns ## the rational expression represented by S ##
InstallGlobalFunction(RationalExpression, function(arg)
local i, I0, S0, RationalExp, processPowers;
# This function parses a string and replaces a^n by aaa.. (n times)
processPowers := function(S)
local S2, lc, i, j, k, num;
if S = [] then
return []; fi;
lc := S[1]; # The last character read
S2 := [lc]; # The converted string
i := 2; while IsBound(S[i]) do if S[i] = '^' and IsBound(S[i+1]) and IsDigitChar(S[i+1]) then
j := i + 1;
num := []; # Get the power while IsBound(S[j]) and IsDigitChar(S[j]) do
Add(num, S[j]);
j := j + 1;
od;
num := Int(num); for k in [2..num] do
Add(S2, lc);
od;
i := j - 1; else
Add(S2, S[i]); fi;
lc := S[i];
i := i + 1;
od;
return S2; end; ## End of processPowers() --
if Length(arg) = 0then
Error("Please specify a rational expression as a string"); elif IsBound(arg[2]) then
I0 := arg[2];
S0 := processPowers(arg[1]); if not ((IsPosInt(I0) or IsString(I0)) and IsString(S0)) then
Error("The arguments to RationalExpression must be a string [and a positive integer or a string]"); fi; if IsString(I0) then if'@' in I0 or '*' in I0 or '(' in I0 or ')' in I0 or 'U' in I0 then
Error("'@', '*', '(', ')' and 'U' must not be in the alphabet"); fi; # I0 := SSortedList(I0); else if Length(SSortedList(Concatenation(S0, "U*()@"))) > I0+5then
Error("The expression contains more different letters than the alphabet"); fi; fi; else
I0 := [];
S0 := processPowers(arg[1]); if S0 = "@"then
Error("When defining @, please specify the alphabet"); fi; for i in S0 do if not (i = '@' or i = '*' or i = 'U' or i = '(' or i = ')') then
AddSet(I0, i); fi;
od; fi;
RationalExp := function(S, I)
local i, op, ord, I0, S0,
getTopOp, buildStar, buildProduct,
sub_exps, union_inds, star_inds, union_sub_exps;
if S = "" or S = "@"then
return(RatExpOnnLetters(I, [], [])); elif S = "empty_set"then
return(RatExpOnnLetters(I, [], "empty_set")); elif Length(S) = 1then if IsInt(I) then
ord := Ord(S[1]) - Ord('a') + 1; else
ord := Position(I, S[1]); if ord = fail then
Error(Concatenation("Letter of expression not in alphabet: ", S[1])); fi; fi;
return(RatExpOnnLetters(I, [], [ord])); fi;
sub_exps := [];
union_inds := [];
star_inds := [];
union_sub_exps := [];
## This functions returns the "top" most operation of the given ## expression ## getTopOp("aaUab*") returns "union" ## getTopOp("(bUa)*") returns "star" ## getTopOp("(bUa)*b") returns "product" ## ## it also fills the array sub_exps with the sub expressions, ## union_inds with the indexes in sub_exps of the positions of ## the U symbols ## and star_inds with the indexes in sub_exps of the positions ## of the * symbols
getTopOp := function(e)
local i, c, stack, istack, star, nonstar, union, len, sub;
if e = "" or Length(e) = 1then
return([]); else
stack := [];
istack := 0;
star := false;
nonstar := false;
union := false;
len := Length(e);
sub := []; for i in [1 .. len] do
c := e[i]; if c = '('then if istack > 0then
Add(sub, c); fi;
istack := istack + 1;
stack[istack] := c; elif c = ')'then if istack > 0then
istack := istack - 1; if istack = 0then if i < len - 1then
nonstar := true; fi;
Add(sub_exps, String(sub));
sub := []; else
Add(sub, c); fi; else
Error("Mismatched parenthesis"); fi; elif istack = 0then if c = 'U'then
union := true;
Add(union_inds, Length(sub_exps) + 1); elif c = '*'then
star := true;
Add(star_inds, Length(sub_exps) + 1); else
Add(sub_exps, [c]); fi; else
Add(sub, c); fi;
od; if istack > 0then
Error("Mismatched parenthesis"); fi; if union then
return("union"); elif star and ((e[1] = '(' and e[len-1] = ')' and nonstar = false) or (len = 2)) then
return("star"); else
return("product"); fi; fi; end; ## End of getTopOp() --
## This function scans the array sub_exps and replaces ## all the strings that are meant to be star expressions ## by the corresponding star rational subexpression
buildStar := function()
local i;
if not star_inds = [] then for i in star_inds do if i-1 > 0then if IsString(sub_exps[i-1]) then
sub_exps[i-1] := RatExpOnnLetters(I, "star", RationalExp(sub_exps[i-1], I)); else
Error("Malformed expression"); fi; else
Error("Malformed expression"); fi;
od; fi; end; ## End of buildStar() --
## When the "top" most operation is "union", this functions ## groups the product subexpressions of the union, building ## the list union_sub_exps to be used in ## RatExpOnnLetters(I, "union", union_sub_exps
buildProduct := function()
local i, j, k, list, len;
list := [];
j := 1;
len := Length(sub_exps); for i in union_inds do if i > len then
Error("Malformed expression"); fi; for k in [j .. i-1] do
Add(list, sub_exps[k]);
od; if Length(list) = 1then
Add(union_sub_exps, list[1]); else
Add(union_sub_exps, RatExpOnnLetters(I, "product", list)); fi;
j := i;
list := [];
od; for k in [j .. len] do
Add(list, sub_exps[k]);
od; if Length(list) = 1then
Add(union_sub_exps, list[1]); else
Add(union_sub_exps, RatExpOnnLetters(I, "product", list)); fi; end; ## End of buildProduct() --
op := getTopOp(S);
buildStar(); if op = "star"then
return(sub_exps[1]); elif op = "product"then for i in [1 .. Length(sub_exps)] do if IsString(sub_exps[i]) then
sub_exps[i] := RationalExp(sub_exps[i], I); fi;
od;
return(RatExpOnnLetters(I, "product", sub_exps)); else# op = "union" for i in [1 .. Length(sub_exps)] do if IsString(sub_exps[i]) then
sub_exps[i] := RationalExp(sub_exps[i], I); fi;
od;
buildProduct();
return(RatExpOnnLetters(I, "union", union_sub_exps)); fi; end;
return(RationalExp(S0, I0)); end);
####################################################################### ## #M String(R) ## ## Outputs a rational expression as a string ##
InstallMethod( String, "for rational expressions",
true,
[ IsRatExpOnnLettersObj and IsRationalExpressionRep ], 0, function(r)
local ret, string;
ret := RatExpToString(r, 0);
string := ret[1];
Setter(SizeRatExp)(r,ret[2]);
return(string); end );
############################################################################# ## #F RandomRatExp(arg) ## ## Given the number of symbols of the alphabet and (possibly) a factor m, ## returns a pseudo random rational expression over that alphabet. ##
InstallGlobalFunction(RandomRatExp, function(arg)
local aut, m, n;
if Length(arg) = 0then
Error("Please specify the number of letters of the alphabet of the rational expression or a string"); fi;
n := arg[1]; if not (IsPosInt( n ) or IsList(n)) then
Error( "The argument must be a positive integer or a string" ); fi; if IsString(n) then if'@' in n then
Error("@ must not be in the alphabet"); fi; fi; if IsBound(arg[2]) then
m := arg[2]; else
m := 1; fi;
aut := RandomAutomaton("det", (Runtime() mod (m*7)) + 2, n);
return(FAtoRatExp(aut)); end);
######################################################################### ## #M SizeRatExp(r) ## ## Computes the size of the rational expression r ## ##
InstallMethod(SizeRatExp, "size of RatExp",
[IsRatExpOnnLettersObj], function( r )
local count, e;
if not IsRatExpOnnLettersObj(r) then
Error("The argument to RatExpToString must be a rational expression"); fi;
count := 0; if r!.list_exp = "empty_set"then
return(0); elif r!.op = [] then
return(1); elif r!.op = "product" or r!.op = "union"then for e in r!.list_exp do
count := count + SizeRatExp(e);
od;
return(count); else
return(SizeRatExp(r!.list_exp)); fi; end);
######################################################################### ## #M AlphabetOfRatExp(r) ## ## Returns the number of symbols in the alphabet of the rational expression r ## ##
InstallGlobalFunction(AlphabetOfRatExp, function( R )
return(ShallowCopy(FamilyObj(R)!.alphabet)); end);
############################################################################# ## #F AlphabetOfRatExpAsList(R) ## ## Returns the alphabet of the rational expression as a list. ## If the alphabet of the rational expression is given by means of an integer ## less than 27 it returns the list "abcd....", ## otherwise returns [ "a1", "a2", "a3", "a4", ... ]. ##
InstallGlobalFunction(AlphabetOfRatExpAsList, function( R ) if not IsRatExpOnnLettersObj(R) then
Error("The argument must be a rational expression"); fi;
return(ShallowCopy(FamilyObj(R)!.alphabet2)); end);
############################################################################ ## #F IsRationalExpression ##
InstallGlobalFunction(IsRationalExpression, function(R)
return IsRatExpOnnLettersObj(R) and IsRationalExpressionRep(R); end); ############################################################################ ## #M Methods for the comparison operations. ##
InstallMethod( \=, "for two rational sets",
ReturnTrue,
[ IsRatExpOnnLettersObj and IsRationalExpressionRep,
IsRatExpOnnLettersObj and IsRationalExpressionRep, ], 0, function( L1, L2 )
return( AlphabetOfRatExp(L1) = AlphabetOfRatExp(L2) and L1!.op = L2!.op and L1!.list_exp = L2!.list_exp ); end );
InstallMethod( \<, "for two rational expressions", # IsIdenticalObj,
true,
[ IsRatExpOnnLettersObj and IsRationalExpressionRep,
IsRatExpOnnLettersObj and IsRationalExpressionRep, ], 0, function( x, y ) if x = y then
return(false); elif x!.list_exp = "empty_set"then
return(true); elif x!.op = [] and y!.op = [] and not y!.list_exp = "empty_set"then
return(x!.list_exp < y!.list_exp); elif x!.op = [] and (y!.op = "star" or y!.op = "product" or y!.op = "union") then
return(true); elif x!.op = "star" and (y!.op = "product" or y!.op = "union") then
return(true); elif x!.op = "product" and y!.op = "union"then
return(true); elif x!.op = y!.op then
return(x!.list_exp < y!.list_exp); else
return(false); fi; end );
## #E
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.29 Sekunden
(vorverarbeitet am 2026-10-12)
¤
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.