1# This files contains the functions: 2# DTP_SolveEquation 3# DTP_Inverse 4# DTP_Exp 5# DTP_NormalForm 6# DTP_Order 7# 8# DTP_DetermineMultiplicationFunction 9# DTP_IsInNormalForm 10# _DTP_DetermineNormalForm 11# _DTP_DetermineOrder 12# 13# DTP_PCP_SolveEquation 14# DTP_PCP_Inverse 15# DTP_PCP_Exp 16# DTP_PCP_NormalForm 17# DTP_PCP_Order 18############################################################################## 19 20# Each application (DTP_SolveEquation, DTP_NormalForm, DTP_Order, ...) may 21# take an DTObj where DTObj![PC_DTPPolynomials] is either the output of the 22# function DTP_DTpols_rs or the output of DTP_DTpols_r. Let 23# polynomials := DTObj![PC_DTPPolynomials]. 24# Since the condition IsInt(polynomials[1][1][1]) is true if and only if 25# "polynomials" is the ouput of DTP_DTpols_r, we can decide which 26# multiplication function we should use for computations. Explanation: 27# For DTP_DTpols_r: 28# polynomials[1] <-> f_1 29# polynomials[1][1] <-> first g_alpha in f_1 30# polynomials[1][1][1] <-> constant coefficient in first g_alpha in f_1 31# 32# For DTP_DTpols_rs: 33# polynomials[1] <-> list of the n polynomials f_{r, 1} (1 <= r <= n) 34# polynomials[1][1] <-> polynomial f_{1, 1} 35# polynomials[1][1][1] <-> first g_alpha in f_{1, 1}, this is a list 36# 37# Hence, we can determine the suitable multiplication function "multiply" 38# by using 39# if IsInt(DTObj![PC_DTPPolynomials][1][1][1]) then 40# # version f_r 41# multiply := DTP_Multiply_r; 42# else 43# # version f_rs 44# multiply := DTP_Multiply_rs; 45# fi; 46# Input: DTObj 47# Output: function DTP_Multiply_r or DTP_Multiply_rs depending on whether 48# polynomials f_r or f_rs were computed for DTObj. 49InstallGlobalFunction( DTP_DetermineMultiplicationFunction, 50function(DTObj) 51 if IsInt(DTObj![PC_DTPPolynomials][1][1][1]) then 52 # version f_r 53 return DTP_Multiply_r; 54 else 55 # version f_rs 56 return DTP_Multiply_rs; 57 fi; 58end) ; 59 60# Input: - exponent vectors x, z 61# - DTObj 62# Output: exponent vector y such that for the corresponding elements 63# x * y = z. If DTObj![PC_DTPConfluent] = true, y describes a normal 64# form. 65InstallGlobalFunction( DTP_SolveEquation, 66function(x, z, DTObj) 67 local y, i, n, multiply; 68 69 multiply := DTP_DetermineMultiplicationFunction(DTObj); 70 71 n := DTObj![PC_NUMBER_OF_GENERATORS]; 72 y := []; 73 74 # both exponent vectors must have length n 75 if Length(x) <> n or Length(z) <> n then 76 Error("Exponent vectors x and z must have length ", n); 77 fi; 78 79 for i in [1 .. n] do 80 # Loop invariant: 81 # x = a_1^z_1 ... a_{i-1}^{z_{i-1}} * a_i^x_i ... a_n^x_n 82 y[i] := z[i] - x[i]; 83 # calculate x * a_i^y_i 84 x := multiply(x, ExponentsByObj(DTObj, [i, y[i]]), DTObj); 85 od; 86 # Now by the loop invariant: x = z 87 # On the other hand: x = x * y by construction 88 89 if DTObj![PC_DTPConfluent] then 90 return DTP_NormalForm(y, DTObj); 91 else 92 return y; 93 fi; 94end) ; 95 96# Input: pcp elements pcp1, pcp2 belonging to the same collector 97# Output: pcp element res such that pcp1 * res = pcp2 98InstallGlobalFunction( DTP_PCP_SolveEquation, 99function(pcp1, pcp2) 100 local dtobj; 101 102 dtobj := Collector(pcp1); 103 104 if not IsDTObj(dtobj) then 105 Error("Collector(pcp1) must be a DTObj"); 106 elif not Collector(pcp2) = dtobj then 107 Error("pcp1 and pcp2 must belong to the same DTObj"); 108 else 109 return PcpElementByExponentsNC(dtobj, DTP_SolveEquation(Exponents(pcp1), Exponents(pcp2), dtobj)); 110 fi; 111 112end ); 113 114# Input: - exponent vector x 115# - DTObj 116# Output: exponent vector of x^{-1}. If DTObj![PC_DTPConfluent] = true, y 117# describes a normal form. 118InstallGlobalFunction( DTP_Inverse, 119function(x, DTObj) 120 local n; 121 n := DTObj![PC_NUMBER_OF_GENERATORS]; 122 return DTP_SolveEquation(x, [1 .. n] * 0, DTObj); 123end) ; 124 125# Input: pcp element pcp 126# Output: inverse of pcp as pcp element 127InstallGlobalFunction( DTP_PCP_Inverse, 128function(pcp) 129 local dtobj; 130 131 dtobj := Collector(pcp); 132 133 if not IsDTObj(dtobj) then 134 Error("Collector(pcp) must be a DTObj"); 135 else 136 return PcpElementByExponentsNC(dtobj, DTP_Inverse(Exponents(pcp), dtobj)); 137 fi; 138 139end ); 140 141# DTP_IsInNormalFrom checks whether the element described by the exponent 142# vector x is in normal form or not. 143# It returns "true", if x describes a normal form and otherwise 144# the smallest generator index for which the condition 145# r[i] <> 0 and (x[i] < 0 or x[i] >= r[i]) 146# is NOT fulfilled is returned. Here, r = RelativeOrders(coll). 147InstallGlobalFunction( DTP_IsInNormalForm, 148function(x, coll) 149 local i, r; 150 151 r := RelativeOrders(coll); 152 # If the relative order r[i] is finite, check whether 153 # 0 <= x[i] < r[i] is fulfilled. 154 for i in [1 .. coll![PC_NUMBER_OF_GENERATORS]] do 155 if r[i] <> 0 then 156 if x[i] < 0 or x[i] >= r[i] then 157 return i; 158 fi; 159 fi; 160 od; 161 162 return true; 163end) ; 164 165 166# Input: - exponent vector x 167# - integer q 168# - DTObj 169# Output: exponent vector of x^q. If DTObj![PC_DTPConfluent] = true, then 170# the result is in normal form. 171InstallGlobalFunction( DTP_Exp, 172function(x, q, DTObj) 173 local multiply, y; 174 175 multiply := DTP_DetermineMultiplicationFunction(DTObj); 176 y := [1 .. NumberOfGenerators(DTObj)] *0; # y = 1 177 if q < 0 then 178 x := DTP_Inverse(x, DTObj); 179 q := -q; 180 fi; 181 while q > 0 do 182 if q mod 2 = 1 then 183 y := multiply(y, x, DTObj); 184 fi; 185 q := QuoInt(q, 2); 186 x := multiply(x, x, DTObj); 187 od; 188 return y; 189end) ; 190 191# Input: - pcp element pcp 192# - integer q 193# Output: pcp^q 194InstallGlobalFunction( DTP_PCP_Exp, 195function(pcp, q) 196 local dtobj, exp; 197 198 dtobj := Collector(pcp); 199 200 if not IsDTObj(dtobj) then 201 Error("Collector(pcp) must be a DTObj"); 202 else 203 exp := ShallowCopy(Exponents(pcp)); 204 return PcpElementByExponentsNC(dtobj, DTP_Exp(exp, q, dtobj)); 205 fi; 206 207end ); 208 209# Input: - exponent vector x 210# - DTObj 211# - empty list nf = [] where normal form is stored 212# - function multiply which is either DTP_Multiply_r or 213# DTP_Multiply_rs depending the polynomials used in DTObj 214# Output: exponent vector of the normal form of x 215_DTP_DetermineNormalForm := function(x, DTObj, nf, multiply) 216 local n, j, i, q, r, q_list, l, z, pwr, k, w1, w2, w; 217 218 # DTObj![PC_DTPPolynomials] = DTpols(coll) 219 n := DTObj![PC_NUMBER_OF_GENERATORS]; 220 221 # find j = min{ 1 <= i <= n | s_i < infinity and 222 # (x_i < 0 or x_i >= s_i) } \cup {infinity} 223 j := DTP_IsInNormalForm(x, DTObj); 224 225 if j <> true then 226 # replace a_j^x[j] by suitable power of the power relation a_j^s_j 227 228 # x[j] = q * rel_orders[j] + r, 0 <= r < rel_orders[j]: 229 r := x[j] mod RelativeOrders(DTObj)[j]; 230 q := (x[j] - r)/RelativeOrders(DTObj)[j]; 231 232 # In the following, compute w = w1 * w2, where 233 # w1 = ( a_j^rel_orders[j] )^q 234 # = ( a_{j + 1}^{c_{j, j, j + 1}} ... a_n^{c_{j, j, n}} )^q 235 # and 236 # w2 = a_{j + 1}^{x_{j + 1}} ... a_n^{x_n} 237 # Then w only depends on the generators a_{j + 1}, ..., a_n and 238 # its normal form can be computed (recursively). 239 240 pwr := GetPower(DTObj, j); 241 # z = a_{j + 1}^c_{j, j, j + 1} ... a_n^{c_{j, j, n}} 242 z := [1 .. n] * 0; 243 for k in [1, 3 .. (Length(pwr) - 1)] do 244 z[pwr[k]] := pwr[k + 1]; 245 od; 246 247 # Compute w1 = z^q 248 w1 := DTP_Exp(z, q, DTObj); 249 250 # w2 = a_{j + 1}^{x_{j + 1}} ... a_n^{x_n} 251 w2 := [1 .. j] * 0; # [0, ..., 0] of length j 252 for i in [(j + 1) .. n] do 253 Add(w2, x[i]); 254 od; 255 256 # w = w1 * w2 257 w := multiply(w1, w2, DTObj); 258 259 # At this point, nf is a list describing the beginning of the 260 # exponent vector of the normal form of x. If some relative orders 261 # are infinite, the corresponding exponents in x are simply added, 262 # and lastly the exponent r of the generator a_j is added. Afterwards, 263 # nf is a list of length j, which must be completed in the following 264 # recursion steps, in which the normal form of "the rest" w" of x is 265 # computed. 266 for i in [(Length(nf) + 1) .. (j - 1)] do 267 Add(nf, x[i]); 268 od; 269 Add(nf, r); # j-th entry 270 271 return _DTP_DetermineNormalForm(w, DTObj, nf, multiply); 272 else 273 # Since all further relative orders are infinite, the word is 274 # now in normal form and we simply append the exponents to the 275 # already calculated normal form nf. 276 for i in [(Length(nf) + 1) .. n] do 277 Add(nf, x[i]); 278 od; 279 return nf; 280 fi; 281end; 282 283# Input: - exponent vector x 284# - DTObj 285# Output: exponent vector of normal form of x 286InstallGlobalFunction( DTP_NormalForm, 287function(x, DTObj) 288 local multiply; 289 290 multiply := DTP_DetermineMultiplicationFunction(DTObj); 291 292 return _DTP_DetermineNormalForm(x, DTObj, [], multiply); 293end ); 294 295 296# Input: pcp element 297# Output: pcp element in normal form 298InstallGlobalFunction( DTP_PCP_NormalForm, 299function(pcp) 300 local dtobj; 301 302 dtobj := Collector(pcp); 303 304 if not IsDTObj(dtobj) then 305 Error("Collector(pcp) must be a DTObj"); 306 elif not dtobj![PC_DTPConfluent] = true then 307 Error("collector must be confluent"); 308 else 309 return PcpElementByExponentsNC(dtobj, DTP_NormalForm(Exponents(pcp), dtobj)); 310 fi; 311 312end ); 313 314# Input: - exponent vector x (must describe a normal form) 315# - DTObj 316# Output: order of x in group of coll 317_DTP_DetermineOrder := function(x, DTObj, multiply) 318 local j, s, ord; 319 ord := 1; 320 # DTObj![PC_DTPPolynomials] = DTpols(coll) 321 322 while x <> [1 .. DTObj![PC_NUMBER_OF_GENERATORS]] * 0 do 323 j := 1; 324 while x[j] = 0 do 325 j := j + 1; # exists, since x <> neutral element 326 od; 327 if RelativeOrders(DTObj)[j] = 0 then # relative order s_j = infinity 328 return infinity; 329 else 330 # s = s_j/gcd(s_j, x_j) 331 s := RelativeOrders(DTObj)[j]/Gcd(RelativeOrders(DTObj)[j], x[j]); 332 333 # ord(x) = infinity <=> ord(x^s) = infinity 334 # ord(x) < infinity => s | ord(x) 335 336 # Compute y = x^s: 337 x := DTP_Exp(x, s, DTObj); 338 # The normal form of x is needed, i.e. isConfl = true! 339 # (Otherwise one may run into a infinite recursion, since the 340 # termination of the algorithm needs the normal form of x to 341 # begin with a generator with index greater than j.) 342 ord := ord * s; 343 fi; 344 od; 345 return ord; 346end; 347 348# Input: - exponent vector x 349# - DTObj 350# Output: order of x in group of coll 351InstallGlobalFunction( DTP_Order, 352function(x, DTObj) 353 local multiply; 354 355 multiply := DTP_DetermineMultiplicationFunction(DTObj); 356 357 # check whether x is in normal form, if not call _DTP_DetermineNormalForm 358 # DTP_IsInNormalForm returns true or an intger, if not in normal form 359 if DTP_IsInNormalForm(x, DTObj) <> true then 360 x := _DTP_DetermineNormalForm(x, DTObj, [], multiply); 361 fi; 362 363 return _DTP_DetermineOrder(x, DTObj, multiply); 364end ); 365 366# Input: pcp element 367# Output: order of pcp 368InstallGlobalFunction( DTP_PCP_Order, 369function(pcp) 370 local dtobj; 371 372 dtobj := Collector(pcp); 373 374 if not IsDTObj(dtobj) then 375 Error("Collector(pcp) must be a DTObj"); 376 elif not dtobj![PC_DTPConfluent] = true then 377 Error("collector must be confluent"); 378 else 379 return DTP_Order(Exponents(pcp), dtobj); 380 fi; 381 382end ); 383