############################################################################# ## #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 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 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 is commutative, only "half" of the table is saved. ## This can be detected from 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 -ary number represented by a string 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 = [ , , optional ] ## Converts a decimal number to a number in base . ## Optional parameter is the minimal required number of "digits" ## of the output in new base , including zeros at the beginning ## Returns the corresponding number as a string in base (of length at least ). 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. ## is a cocycle, an n x n matrix ## is a set of cardinality b ## every entry in must lie in but not vice versa ## is an encoded cocycle, a list of the form [n, is_comm, data], ## where n=|F|, is_comm is true iff is commutative, and ## data is an encoded cocycle table ## Note: The encoded cocycle has default values in [0..b-1]. The argument ## 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);