273 lines
9.1 KiB
Plaintext
273 lines
9.1 KiB
Plaintext
|
#############################################################################
|
||
|
##
|
||
|
#W convert.gi Conversions, encoding and decoding [loops]
|
||
|
##
|
||
|
#H @(#)$Id: convert.gi, v 3.0.0 2015/06/02 gap Exp $
|
||
|
##
|
||
|
#Y Copyright (C) 2004, G. P. Nagy (University of Szeged, Hungary),
|
||
|
#Y P. Vojtechovsky (University of Denver, USA)
|
||
|
##
|
||
|
|
||
|
############################################################################
|
||
|
##
|
||
|
## CONVERSIONS BETWEEN CHARACTERS AND "DIGITS" IN BASE 91.
|
||
|
## -------------------------------------------------------------------------
|
||
|
##
|
||
|
## Suitable characters to represent digits in GAP are found in the interval
|
||
|
## CHAR_INT(35)..CHAR_INT(126), except for CHAR_INT[92] = '\\'.
|
||
|
## This leads to natural base 91 = 126-35.
|
||
|
## To implement binary, decimal and hexadecimal numbers naturally,
|
||
|
## we reorder the suitable 91 characters to read as follows:
|
||
|
|
||
|
BindGlobal(
|
||
|
"LOOPS_conversion_string",
|
||
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%&'()*+,-./:;<=>?@[]^_`{|}~"
|
||
|
);
|
||
|
|
||
|
#############################################################################
|
||
|
##
|
||
|
#O LOOPS_DigitToChar( d )
|
||
|
##
|
||
|
## Converts an integer <d> in the range [0..90] to a character.
|
||
|
|
||
|
InstallMethod( LOOPS_DigitToChar, "for integer",
|
||
|
[ IsInt ],
|
||
|
function( d )
|
||
|
return LOOPS_conversion_string[ d + 1 ];
|
||
|
end );
|
||
|
|
||
|
|
||
|
#############################################################################
|
||
|
##
|
||
|
#O LOOPS_CharToDigit( c )
|
||
|
##
|
||
|
## Converts a character <c> to an integer in the range [0..90].
|
||
|
|
||
|
InstallMethod( LOOPS_CharToDigit, "for character",
|
||
|
[ IsChar ],
|
||
|
function( c )
|
||
|
return Position( LOOPS_conversion_string, c ) - 1;
|
||
|
end );
|
||
|
|
||
|
#############################################################################
|
||
|
##
|
||
|
#O LOOPS_EncodeCayleyTable( ct )
|
||
|
#O LOOPS_DecodeCayleyTable( str )
|
||
|
##
|
||
|
## Auxiliary routines for encoding and decoding of loop Cayley tables
|
||
|
## of order in [1..91], using characters instead of numbers.
|
||
|
## When n>2, first row and column are ignored because they can be
|
||
|
## reconstructed from the rest of the table.
|
||
|
## When <ct> is commutative, only "half" of the table is saved.
|
||
|
## This can be detected from <str> and decoded appropriately.
|
||
|
|
||
|
InstallMethod( LOOPS_EncodeCayleyTable, "for list",
|
||
|
[ IsList ],
|
||
|
function( ct )
|
||
|
local n, ret, start, i, j;
|
||
|
n := Length( ct );
|
||
|
ret := "";
|
||
|
start := 2;
|
||
|
# small cases
|
||
|
if n<3 then
|
||
|
start := 1;
|
||
|
fi;
|
||
|
if n>91 then
|
||
|
Error("LOOPS: Encoding of Cayley tables is supported only for order less than 92.");
|
||
|
fi;
|
||
|
ret := "";
|
||
|
if ct <> TransposedMat( ct ) then # general case
|
||
|
for i in [start..n] do for j in [start..n] do
|
||
|
Add(ret, LOOPS_DigitToChar( ct[i][j]-1 ) );
|
||
|
od; od;
|
||
|
else # commutative case
|
||
|
for i in [start..n] do for j in [i..n] do
|
||
|
Add(ret, LOOPS_DigitToChar( ct[i][j]-1 ) );
|
||
|
od; od;
|
||
|
fi;
|
||
|
return ret;
|
||
|
end );
|
||
|
|
||
|
InstallMethod( LOOPS_DecodeCayleyTable, "for string",
|
||
|
[ IsString ],
|
||
|
function( str )
|
||
|
local symbols, n, pos, ret, i, j;
|
||
|
symbols := Set( Set( str ), c -> LOOPS_CharToDigit(c) + 1 );
|
||
|
if Length(str)=1 then
|
||
|
return [[LOOPS_CharToDigit(str[1])+1]];
|
||
|
fi;
|
||
|
if Length(str)=3 and Size(symbols)=2 then # n=2 (automatically commutative)
|
||
|
return [
|
||
|
[LOOPS_CharToDigit(str[1])+1, LOOPS_CharToDigit(str[2])+1],
|
||
|
[LOOPS_CharToDigit(str[2])+1, LOOPS_CharToDigit(str[3])+1]
|
||
|
];
|
||
|
fi;
|
||
|
# n>2
|
||
|
n := Size( symbols ); # number of distinct symbols
|
||
|
if n>91 then
|
||
|
Error("LOOPS: Decoding of Cayley tables is supported only for order less than 92.");
|
||
|
fi;
|
||
|
ret := List([1..n], i -> List( [1..n], j -> -1 ) );
|
||
|
# the table except for the first row and first column
|
||
|
pos := 1;
|
||
|
if Length(str) = (n-1)^2 then # noncommutative case
|
||
|
for i in [2..n] do for j in [2..n] do
|
||
|
ret[i][j] := LOOPS_CharToDigit( str[pos] ) + 1;
|
||
|
pos := pos+1;
|
||
|
od; od;
|
||
|
else # commutative case
|
||
|
for i in [2..n] do for j in [i..n] do
|
||
|
ret[i][j] := LOOPS_CharToDigit( str[pos] ) + 1;
|
||
|
ret[j][i] := ret[i][j];
|
||
|
pos := pos + 1;
|
||
|
od; od;
|
||
|
fi;
|
||
|
# determining the first row and first column
|
||
|
for i in [2..n] do
|
||
|
ret[i][1] := Difference( symbols, ret[i] )[1];
|
||
|
ret[1][i] := Difference( symbols, List( [2..n], j->ret[j][i] ) )[1];
|
||
|
od;
|
||
|
ret[1][1] := Difference( symbols, ret[1] )[1];
|
||
|
return ret;
|
||
|
end );
|
||
|
|
||
|
#############################################################################
|
||
|
##
|
||
|
#O LOOPS_ConvertToDecimal( s, n )
|
||
|
##
|
||
|
## Converts an <n>-ary number represented by a string <s> to a decimal
|
||
|
## number represented as integer.
|
||
|
|
||
|
InstallMethod( LOOPS_ConvertToDecimal, "for string and integer",
|
||
|
[ IsString, IsInt ],
|
||
|
function( s, n )
|
||
|
local ls, d, i;
|
||
|
ls := Length( s );
|
||
|
d := 0;
|
||
|
for i in [1..ls] do
|
||
|
d := d + LOOPS_CharToDigit(s[i])*(n^(ls-i));
|
||
|
od;
|
||
|
return d;
|
||
|
end );
|
||
|
|
||
|
|
||
|
#############################################################################
|
||
|
##
|
||
|
#F LOOPS_ConvertFromDecimal( arg )
|
||
|
##
|
||
|
## arg = [ <d>, <m>, optional <k> ]
|
||
|
## Converts a decimal number <d> to a number in base <m>.
|
||
|
## Optional parameter <k> is the minimal required number of "digits"
|
||
|
## of the output in new base <m>, including zeros at the beginning
|
||
|
## Returns the corresponding number as a string in base <m> (of length at least <k>).
|
||
|
|
||
|
InstallGlobalFunction( LOOPS_ConvertFromDecimal, function( arg )
|
||
|
local d, m, s, r, prefix_s;
|
||
|
d := arg[1];
|
||
|
m := arg[2];
|
||
|
s := "";
|
||
|
while d>0 do
|
||
|
r := d mod m;
|
||
|
Add( s, LOOPS_DigitToChar( r ) );
|
||
|
d := (d-r)/m;
|
||
|
od;
|
||
|
s := Reversed( s );
|
||
|
if Length( arg ) > 2 then
|
||
|
prefix_s := List( [1..arg[3]-Length(s)], i -> LOOPS_DigitToChar( 0 ) );
|
||
|
s := Concatenation( prefix_s, s );
|
||
|
fi;
|
||
|
return s;
|
||
|
end );
|
||
|
|
||
|
|
||
|
#############################################################################
|
||
|
##
|
||
|
#F LOOPS_ConvertBase( arg )
|
||
|
##
|
||
|
## arg = [ s, n, m, optional k ]
|
||
|
## s is a string that represents a number in base n
|
||
|
## m is a new base
|
||
|
## optional parameter k is the minimal required number of "digits"
|
||
|
## of the output in new base m, including zeros at the beginning
|
||
|
## Returns the corresponding number in base m (with at least k digits).
|
||
|
|
||
|
InstallGlobalFunction( LOOPS_ConvertBase, function( arg )
|
||
|
local d;
|
||
|
d := LOOPS_ConvertToDecimal( arg[1], arg[2] );
|
||
|
if Length(arg)>3 then
|
||
|
return LOOPS_ConvertFromDecimal( d, arg[3], arg[4] );
|
||
|
fi;
|
||
|
return LOOPS_ConvertFromDecimal( d, arg[3] );
|
||
|
end );
|
||
|
|
||
|
#############################################################################
|
||
|
##
|
||
|
#O LOOPS_EncodeCocycle( coc, values )
|
||
|
#O LOOPS_DecodeCocycle( ecoc, values )
|
||
|
##
|
||
|
## Given loops F and K, a cocycle is a mapping from F x F to K.
|
||
|
## Let n=|F| and b=|K|.
|
||
|
## Cocycles are represented as n x n arrays with entries in a b-element set.
|
||
|
##
|
||
|
## These are auxiliary routines for encoding and decoding of cocycles.
|
||
|
## <coc> is a cocycle, an n x n matrix
|
||
|
## <values> is a set of cardinality b
|
||
|
## every entry in <coc> must lie in <values> but not vice versa
|
||
|
## <ecoc> is an encoded cocycle, a list of the form [n, is_comm, data],
|
||
|
## where n=|F|, is_comm is true iff <coc> is commutative, and
|
||
|
## data is an encoded cocycle table
|
||
|
## Note: The encoded cocycle has default values in [0..b-1]. The argument
|
||
|
## <values> can be used to populate the cocycle with other values.
|
||
|
|
||
|
InstallMethod( LOOPS_EncodeCocycle, "for two lists",
|
||
|
[ IsList, IsList ],
|
||
|
function( coc, values )
|
||
|
local b, n, is_commutative, ret, i, start, j;
|
||
|
b := Length( values );
|
||
|
if not b < 92 then
|
||
|
Error("LOOPS: Encoding of cocycles is supported only for loops of order less than 92.");
|
||
|
fi;
|
||
|
n := Length(coc);
|
||
|
is_commutative := coc = TransposedMat(coc);
|
||
|
ret := [ n, is_commutative, "" ];
|
||
|
for i in [1..n] do
|
||
|
start := 1;
|
||
|
if is_commutative then start := i; fi;
|
||
|
for j in [start..n] do
|
||
|
Add( ret[3], LOOPS_DigitToChar( Position( values, coc[i][j] ) - 1 ) );
|
||
|
od;
|
||
|
od;
|
||
|
ret[3] := LOOPS_ConvertBase( ret[3], b, 91 );
|
||
|
return ret;
|
||
|
end);
|
||
|
|
||
|
InstallMethod( LOOPS_DecodeCocycle, "for two lists",
|
||
|
[ IsList, IsList ],
|
||
|
function( ecoc, values )
|
||
|
local n, is_commutative, b, s, coc, pos, i, j;
|
||
|
n := ecoc[1];
|
||
|
is_commutative := ecoc[2];
|
||
|
b := Length( values );
|
||
|
if is_commutative then
|
||
|
s := LOOPS_ConvertBase( ecoc[3], 91, b, n*(n+1)/2 );
|
||
|
else
|
||
|
s := LOOPS_ConvertBase( ecoc[3], 91, b, n^2 );
|
||
|
fi;
|
||
|
coc := List([1..n], i -> [1..n]);
|
||
|
pos := 1;
|
||
|
if is_commutative then
|
||
|
for i in [1..n] do for j in [i..n] do
|
||
|
coc[i][j] := values[ LOOPS_CharToDigit( s[pos] ) + 1 ];
|
||
|
coc[j][i] := coc[i][j];
|
||
|
pos := pos + 1;
|
||
|
od; od;
|
||
|
else
|
||
|
for i in [1..n] do for j in [1..n] do
|
||
|
coc[i][j] := values[ LOOPS_CharToDigit( s[pos] ) + 1 ];
|
||
|
pos := pos + 1;
|
||
|
od; od;
|
||
|
fi;
|
||
|
return coc;
|
||
|
end);
|
||
|
|