[2024f6a] | 1 | /*********************************************** |
---|
| 2 | * Copyright (C) 2011 Sebastian Jambor * |
---|
| 3 | * sebastian@momo.math.rwth-aachen.de * |
---|
| 4 | ***********************************************/ |
---|
| 5 | |
---|
| 6 | |
---|
| 7 | #include<cmath> |
---|
[5b2745] | 8 | #include<Singular/mod2.h> |
---|
[2024f6a] | 9 | |
---|
| 10 | #include "minpoly.h" |
---|
| 11 | |
---|
| 12 | // TODO: avoid code copying, use subclassing instead! |
---|
| 13 | |
---|
[5b2745] | 14 | LinearDependencyMatrix::LinearDependencyMatrix (unsigned n, unsigned long p) |
---|
| 15 | { |
---|
| 16 | this->n = n; |
---|
| 17 | this->p = p; |
---|
| 18 | |
---|
| 19 | matrix = new unsigned long *[n]; |
---|
[47a616d] | 20 | for(int i = 0; i < n; i++) |
---|
[5b2745] | 21 | { |
---|
| 22 | matrix[i] = new unsigned long[2 * n + 1]; |
---|
| 23 | } |
---|
| 24 | pivots = new unsigned[n]; |
---|
| 25 | tmprow = new unsigned long[2 * n + 1]; |
---|
| 26 | rows = 0; |
---|
[2024f6a] | 27 | } |
---|
| 28 | |
---|
[5b2745] | 29 | LinearDependencyMatrix::~LinearDependencyMatrix () |
---|
| 30 | { |
---|
| 31 | delete[]tmprow; |
---|
| 32 | delete[]pivots; |
---|
[2024f6a] | 33 | |
---|
[47a616d] | 34 | for(int i = 0; i < n; i++) |
---|
[5b2745] | 35 | { |
---|
| 36 | delete[](matrix[i]); |
---|
| 37 | } |
---|
| 38 | delete[]matrix; |
---|
[2024f6a] | 39 | } |
---|
| 40 | |
---|
[5b2745] | 41 | void LinearDependencyMatrix::resetMatrix () |
---|
| 42 | { |
---|
| 43 | rows = 0; |
---|
[2024f6a] | 44 | } |
---|
| 45 | |
---|
[5b2745] | 46 | int LinearDependencyMatrix::firstNonzeroEntry (unsigned long *row) |
---|
| 47 | { |
---|
[47a616d] | 48 | for(int i = 0; i < n; i++) |
---|
[5b2745] | 49 | if(row[i] != 0) |
---|
| 50 | return i; |
---|
[2024f6a] | 51 | |
---|
[5b2745] | 52 | return -1; |
---|
[2024f6a] | 53 | } |
---|
| 54 | |
---|
[5b2745] | 55 | void LinearDependencyMatrix::reduceTmpRow () |
---|
| 56 | { |
---|
[47a616d] | 57 | for(int i = 0; i < rows; i++) |
---|
[5b2745] | 58 | { |
---|
| 59 | unsigned piv = pivots[i]; |
---|
| 60 | unsigned long x = tmprow[piv] % p; |
---|
| 61 | // if the corresponding entry in the row is zero, there is nothing to do |
---|
| 62 | if(x != 0) |
---|
| 63 | { |
---|
| 64 | // subtract tmprow[i] times the i-th row |
---|
[47a616d] | 65 | for(int j = piv; j < n + rows + 1; j++) |
---|
[5b2745] | 66 | { |
---|
| 67 | unsigned long tmp = matrix[i][j] * x % p; |
---|
| 68 | tmp = p - tmp; |
---|
| 69 | tmprow[j] += tmp; |
---|
| 70 | // We don't normalize here, so remember to do it after all reductions. |
---|
| 71 | // tmprow[j] %= p; |
---|
| 72 | } |
---|
| 73 | } |
---|
| 74 | } |
---|
| 75 | |
---|
| 76 | // normalize the entries of tmprow. |
---|
[47a616d] | 77 | for(int i = 0; i < n + rows + 1; i++) |
---|
[5b2745] | 78 | { |
---|
| 79 | tmprow[i] %= p; |
---|
| 80 | } |
---|
[2024f6a] | 81 | } |
---|
| 82 | |
---|
| 83 | |
---|
[5b2745] | 84 | void LinearDependencyMatrix::normalizeTmp (unsigned i) |
---|
| 85 | { |
---|
| 86 | unsigned long inv = modularInverse (tmprow[i], p); |
---|
| 87 | tmprow[i] = 1; |
---|
[47a616d] | 88 | for(int j = i + 1; j < 2 * n + 1; j++) |
---|
[5b2745] | 89 | tmprow[j] = (tmprow[j] * inv) % p; |
---|
[2024f6a] | 90 | } |
---|
[ec9db9] | 91 | |
---|
[5b2745] | 92 | bool LinearDependencyMatrix::findLinearDependency (unsigned long *newRow, |
---|
| 93 | unsigned long *dep) |
---|
| 94 | { |
---|
| 95 | // Copy newRow to tmprow (we need to add RHS) |
---|
[47a616d] | 96 | for(int i = 0; i < n; i++) |
---|
[5b2745] | 97 | { |
---|
| 98 | tmprow[i] = newRow[i]; |
---|
| 99 | tmprow[n + i] = 0; |
---|
| 100 | } |
---|
| 101 | tmprow[2 * n] = 0; |
---|
| 102 | tmprow[n + rows] = 1; |
---|
| 103 | |
---|
| 104 | reduceTmpRow (); |
---|
| 105 | |
---|
| 106 | // Is tmprow reduced to zero? Then we have found a linear dependence. |
---|
| 107 | // Otherwise, we just add tmprow to the matrix. |
---|
[47a616d] | 108 | unsigned newpivot = firstNonzeroEntry (tmprow); |
---|
[5b2745] | 109 | if(newpivot == -1) |
---|
| 110 | { |
---|
[47a616d] | 111 | for(int i = 0; i <= n; i++) |
---|
[5b2745] | 112 | { |
---|
| 113 | dep[i] = tmprow[n + i]; |
---|
| 114 | } |
---|
| 115 | |
---|
| 116 | return true; |
---|
| 117 | } |
---|
| 118 | else |
---|
| 119 | { |
---|
| 120 | normalizeTmp (newpivot); |
---|
| 121 | |
---|
[47a616d] | 122 | for(int i = 0; i < 2 * n + 1; i++) |
---|
[5b2745] | 123 | { |
---|
| 124 | matrix[rows][i] = tmprow[i]; |
---|
| 125 | } |
---|
| 126 | |
---|
| 127 | pivots[rows] = newpivot; |
---|
| 128 | rows++; |
---|
| 129 | |
---|
| 130 | return false; |
---|
| 131 | } |
---|
[2024f6a] | 132 | } |
---|
| 133 | |
---|
[ec9db9] | 134 | #if 0 |
---|
[5b2745] | 135 | std::ostream & operator<< (std::ostream & out, |
---|
| 136 | const LinearDependencyMatrix & mat) |
---|
| 137 | { |
---|
| 138 | int width = ((int) log10 (mat.p)) + 1; |
---|
[2024f6a] | 139 | |
---|
[47a616d] | 140 | out << "Pivots: " << std::endl; |
---|
| 141 | for(int j = 0; j < mat.n; j++) |
---|
| 142 | { |
---|
| 143 | out << std::setw (width) << mat.pivots[j] << " "; |
---|
| 144 | } |
---|
| 145 | out << std::endl; |
---|
| 146 | out << "matrix:" << std::endl; |
---|
[5b2745] | 147 | for(int i = 0; i < mat.rows; i++) |
---|
| 148 | { |
---|
| 149 | for(int j = 0; j < mat.n; j++) |
---|
| 150 | { |
---|
| 151 | out << std::setw (width) << mat.matrix[i][j] << " "; |
---|
[2024f6a] | 152 | } |
---|
| 153 | out << "| "; |
---|
[5b2745] | 154 | for(int j = mat.n; j <= 2 * mat.n; j++) |
---|
| 155 | { |
---|
| 156 | out << std::setw (width) << mat.matrix[i][j] << " "; |
---|
[2024f6a] | 157 | } |
---|
| 158 | out << std::endl; |
---|
[5b2745] | 159 | } |
---|
[47a616d] | 160 | out << "tmprow: " << std::endl; |
---|
[5b2745] | 161 | for(int j = 0; j < mat.n; j++) |
---|
| 162 | { |
---|
| 163 | out << std::setw (width) << mat.tmprow[j] << " "; |
---|
| 164 | } |
---|
| 165 | out << "| "; |
---|
| 166 | for(int j = mat.n; j <= 2 * mat.n; j++) |
---|
| 167 | { |
---|
| 168 | out << std::setw (width) << mat.tmprow[j] << " "; |
---|
| 169 | } |
---|
| 170 | out << std::endl; |
---|
| 171 | |
---|
| 172 | return out; |
---|
[2024f6a] | 173 | } |
---|
[ec9db9] | 174 | #endif |
---|
[2024f6a] | 175 | |
---|
| 176 | |
---|
[5b2745] | 177 | NewVectorMatrix::NewVectorMatrix (unsigned n, unsigned long p) |
---|
| 178 | { |
---|
| 179 | this->n = n; |
---|
| 180 | this->p = p; |
---|
[2024f6a] | 181 | |
---|
[5b2745] | 182 | matrix = new unsigned long *[n]; |
---|
[47a616d] | 183 | for(int i = 0; i < n; i++) |
---|
[5b2745] | 184 | { |
---|
| 185 | matrix[i] = new unsigned long[n]; |
---|
| 186 | } |
---|
[2024f6a] | 187 | |
---|
[5b2745] | 188 | pivots = new unsigned[n]; |
---|
| 189 | rows = 0; |
---|
[2024f6a] | 190 | } |
---|
| 191 | |
---|
[5b2745] | 192 | NewVectorMatrix::~NewVectorMatrix () |
---|
| 193 | { |
---|
| 194 | delete pivots; |
---|
[2024f6a] | 195 | |
---|
[47a616d] | 196 | for(int i = 0; i < n; i++) |
---|
[5b2745] | 197 | { |
---|
| 198 | delete[]matrix[i]; |
---|
| 199 | } |
---|
| 200 | delete matrix; |
---|
[2024f6a] | 201 | } |
---|
| 202 | |
---|
[5b2745] | 203 | int NewVectorMatrix::firstNonzeroEntry (unsigned long *row) |
---|
| 204 | { |
---|
[47a616d] | 205 | for(int i = 0; i < n; i++) |
---|
[5b2745] | 206 | if(row[i] != 0) |
---|
| 207 | return i; |
---|
[2024f6a] | 208 | |
---|
[5b2745] | 209 | return -1; |
---|
[2024f6a] | 210 | } |
---|
| 211 | |
---|
| 212 | //void NewVectorMatrix::subtractIthRow(unsigned long* row, unsigned i) { |
---|
| 213 | // unsigned piv = pivots[i]; |
---|
| 214 | // unsigned long x = row[piv]; |
---|
| 215 | // for (int j = piv; j < n; j++) { |
---|
| 216 | // unsigned tmp = matrix[i][j]*x % p; |
---|
| 217 | // tmp = p - tmp; |
---|
| 218 | // row[j] += tmp; |
---|
| 219 | // row[j] %= p; |
---|
| 220 | // } |
---|
| 221 | //} |
---|
| 222 | // |
---|
[5b2745] | 223 | void NewVectorMatrix::normalizeRow (unsigned long *row, unsigned i) |
---|
| 224 | { |
---|
| 225 | unsigned long inv = modularInverse (row[i], p); |
---|
| 226 | row[i] = 1; |
---|
| 227 | |
---|
[47a616d] | 228 | for(int j = i + 1; j < n; j++) |
---|
[5b2745] | 229 | { |
---|
| 230 | row[j] = (row[j] * inv) % p; |
---|
| 231 | } |
---|
[2024f6a] | 232 | } |
---|
| 233 | |
---|
[5b2745] | 234 | void NewVectorMatrix::insertRow (unsigned long *row) |
---|
| 235 | { |
---|
[47a616d] | 236 | for(int i = 0; i < rows; i++) |
---|
[5b2745] | 237 | { |
---|
| 238 | unsigned piv = pivots[i]; |
---|
| 239 | unsigned long x = row[piv] % p; |
---|
| 240 | // if the corresponding entry in the row is zero, there is nothing to do |
---|
| 241 | if(x != 0) |
---|
| 242 | { |
---|
| 243 | // subtract row[i] times the i-th row |
---|
[47a616d] | 244 | for(int j = piv; j < n; j++) |
---|
[5b2745] | 245 | { |
---|
| 246 | unsigned long tmp = matrix[i][j] * x % p; |
---|
| 247 | tmp = p - tmp; |
---|
| 248 | row[j] += tmp; |
---|
| 249 | // We don't normalize here, so remember to do it after all reductions. |
---|
| 250 | // row[j] %= p; |
---|
| 251 | } |
---|
| 252 | } |
---|
| 253 | } |
---|
| 254 | |
---|
| 255 | // normalize the entries of row. |
---|
[47a616d] | 256 | for(int i = 0; i < n + rows + 1; i++) |
---|
[5b2745] | 257 | { |
---|
| 258 | row[i] %= p; |
---|
| 259 | } |
---|
| 260 | |
---|
[47a616d] | 261 | unsigned piv = firstNonzeroEntry (row); |
---|
[5b2745] | 262 | |
---|
| 263 | if(piv != -1) |
---|
| 264 | { |
---|
| 265 | // normalize and insert row into the matrix |
---|
| 266 | normalizeRow (row, piv); |
---|
[47a616d] | 267 | for(int i = 0; i < n; i++) |
---|
[5b2745] | 268 | { |
---|
| 269 | matrix[rows][i] = row[i]; |
---|
| 270 | } |
---|
| 271 | |
---|
| 272 | pivots[rows] = piv; |
---|
| 273 | rows++; |
---|
| 274 | } |
---|
[2024f6a] | 275 | } |
---|
| 276 | |
---|
| 277 | |
---|
[5b2745] | 278 | void NewVectorMatrix::insertMatrix (LinearDependencyMatrix & mat) |
---|
| 279 | { |
---|
| 280 | // The matrix in LinearDependencyMatrix is already in reduced form. |
---|
| 281 | // Thus, if the current matrix is empty, we can simply copy the other matrix. |
---|
| 282 | if(rows == 0) |
---|
| 283 | { |
---|
[47a616d] | 284 | for(int i = 0; i < mat.rows; i++) |
---|
[5b2745] | 285 | { |
---|
[47a616d] | 286 | for(int j = 0; j < n; j++) |
---|
[5b2745] | 287 | { |
---|
| 288 | matrix[i][j] = mat.matrix[i][j]; |
---|
| 289 | |
---|
| 290 | rows = mat.rows; |
---|
[47a616d] | 291 | for(int i = 0; i < rows; i++) |
---|
[5b2745] | 292 | { |
---|
[47a616d] | 293 | pivots[i] = mat.pivots[i]; |
---|
[2024f6a] | 294 | } |
---|
[5b2745] | 295 | } |
---|
[2024f6a] | 296 | } |
---|
[5b2745] | 297 | } |
---|
| 298 | else |
---|
| 299 | { |
---|
[47a616d] | 300 | for(int i = 0; i < mat.rows; i++) |
---|
[5b2745] | 301 | { |
---|
| 302 | insertRow (mat.matrix[i]); |
---|
| 303 | } |
---|
| 304 | } |
---|
[2024f6a] | 305 | } |
---|
| 306 | |
---|
[5b2745] | 307 | int NewVectorMatrix::findSmallestNonpivot () |
---|
| 308 | { |
---|
| 309 | // This method isn't very efficient, but it is called at most a few times, so efficiency is not important. |
---|
| 310 | if(rows == n) |
---|
| 311 | return -1; |
---|
[2024f6a] | 312 | |
---|
[47a616d] | 313 | for(int i = 0; i < n; i++) |
---|
[5b2745] | 314 | { |
---|
| 315 | bool isPivot = false; |
---|
[47a616d] | 316 | for(int j = 0; j < rows; j++) |
---|
[5b2745] | 317 | { |
---|
| 318 | if(pivots[j] == i) |
---|
| 319 | { |
---|
| 320 | isPivot = true; |
---|
| 321 | break; |
---|
| 322 | } |
---|
| 323 | } |
---|
| 324 | |
---|
| 325 | if(!isPivot) |
---|
| 326 | { |
---|
| 327 | return i; |
---|
| 328 | } |
---|
| 329 | } |
---|
| 330 | assume(0); |
---|
| 331 | return -1; // to make the compiler happy |
---|
[47a616d] | 332 | |
---|
[2024f6a] | 333 | } |
---|
| 334 | |
---|
| 335 | |
---|
[5b2745] | 336 | void vectorMatrixMult (unsigned long *vec, unsigned long **mat, |
---|
| 337 | unsigned long *result, unsigned n, unsigned long p) |
---|
| 338 | { |
---|
| 339 | unsigned long tmp; |
---|
[47a616d] | 340 | for(int i = 0; i < n; i++) |
---|
[5b2745] | 341 | { |
---|
| 342 | result[i] = 0; |
---|
[47a616d] | 343 | for(int j = 0; j < n; j++) |
---|
[5b2745] | 344 | { |
---|
| 345 | tmp = vec[j] * mat[j][i] % p; |
---|
| 346 | result[i] += tmp; |
---|
| 347 | } |
---|
| 348 | // We can afford to reduce mod p only after all additions, since p < 2^31, but an unsigned long can store 2^64. |
---|
| 349 | // Thus the only possibility for an overflow would occurr for matrices with about 2^31 rows. |
---|
| 350 | result[i] %= p; |
---|
| 351 | } |
---|
[2024f6a] | 352 | } |
---|
| 353 | |
---|
[ec9db9] | 354 | #if 0 |
---|
[5b2745] | 355 | void printVec (unsigned long *vec, int n) |
---|
| 356 | { |
---|
| 357 | for(int i = 0; i < n; i++) |
---|
| 358 | { |
---|
| 359 | std::cout << vec[i] << ", "; |
---|
| 360 | } |
---|
| 361 | |
---|
| 362 | std::cout << std::endl; |
---|
[2024f6a] | 363 | } |
---|
[ec9db9] | 364 | #endif |
---|
| 365 | |
---|
[5b2745] | 366 | unsigned long *computeMinimalPolynomial (unsigned long **matrix, unsigned n, |
---|
| 367 | unsigned long p) |
---|
| 368 | { |
---|
| 369 | LinearDependencyMatrix lindepmat (n, p); |
---|
| 370 | NewVectorMatrix newvectormat (n, p); |
---|
[2024f6a] | 371 | |
---|
[5b2745] | 372 | unsigned long *result = new unsigned long[n + 1]; |
---|
| 373 | unsigned long *mpvec = new unsigned long[n + 1]; |
---|
| 374 | unsigned long *tmp = new unsigned long[n + 1]; |
---|
[2024f6a] | 375 | |
---|
[47a616d] | 376 | // initialize result = 1 |
---|
| 377 | for(int i = 0; i <= n; i++) |
---|
[5b2745] | 378 | { |
---|
| 379 | result[i] = 0; |
---|
| 380 | } |
---|
| 381 | result[0] = 1; |
---|
[2024f6a] | 382 | |
---|
[5b2745] | 383 | int degresult = 0; |
---|
[2024f6a] | 384 | |
---|
| 385 | |
---|
[5b2745] | 386 | int i = 0; |
---|
[2024f6a] | 387 | |
---|
[5b2745] | 388 | unsigned long *vec = new unsigned long[n]; |
---|
| 389 | unsigned long *vecnew = new unsigned long[n]; |
---|
[ec9db9] | 390 | |
---|
[5b2745] | 391 | while(i != -1) |
---|
| 392 | { |
---|
[47a616d] | 393 | for(int j = 0; j < n; j++) |
---|
[5b2745] | 394 | { |
---|
| 395 | vec[j] = 0; |
---|
[2024f6a] | 396 | } |
---|
[5b2745] | 397 | vec[i] = 1; |
---|
[2024f6a] | 398 | |
---|
[5b2745] | 399 | lindepmat.resetMatrix (); |
---|
[2024f6a] | 400 | |
---|
[5b2745] | 401 | while(true) |
---|
| 402 | { |
---|
| 403 | bool ld = lindepmat.findLinearDependency (vec, mpvec); |
---|
[2024f6a] | 404 | |
---|
[5b2745] | 405 | if(ld) |
---|
| 406 | { |
---|
| 407 | break; |
---|
| 408 | } |
---|
[2024f6a] | 409 | |
---|
[5b2745] | 410 | vectorMatrixMult (vec, matrix, vecnew, n, p); |
---|
| 411 | unsigned long *swap = vec; |
---|
| 412 | vec = vecnew; |
---|
| 413 | vecnew = swap; |
---|
| 414 | } |
---|
[2024f6a] | 415 | |
---|
| 416 | |
---|
[5b2745] | 417 | unsigned degmpvec = n; |
---|
| 418 | while(mpvec[degmpvec] == 0) |
---|
| 419 | { |
---|
| 420 | degmpvec--; |
---|
[2024f6a] | 421 | } |
---|
| 422 | |
---|
[47a616d] | 423 | // if the dimension is already maximal, i.e., the minimal polynomial of vec has the highest possible degree, |
---|
[5b2745] | 424 | // then we are done. |
---|
| 425 | if(degmpvec == n) |
---|
| 426 | { |
---|
| 427 | unsigned long *swap = result; |
---|
| 428 | result = mpvec; |
---|
| 429 | mpvec = swap; |
---|
| 430 | i = -1; |
---|
| 431 | } |
---|
| 432 | else |
---|
| 433 | { |
---|
| 434 | // otherwise, we have to compute the lcm of mpvec and prior result |
---|
[2024f6a] | 435 | |
---|
[5b2745] | 436 | // tmp = zeropol |
---|
[47a616d] | 437 | for(int j = 0; j <= n; j++) |
---|
[5b2745] | 438 | { |
---|
| 439 | tmp[j] = 0; |
---|
| 440 | } |
---|
| 441 | degresult = lcm (tmp, result, mpvec, p, degresult, degmpvec); |
---|
| 442 | unsigned long *swap = result; |
---|
| 443 | result = tmp; |
---|
| 444 | tmp = swap; |
---|
[2024f6a] | 445 | |
---|
[5b2745] | 446 | if(degresult == n) |
---|
| 447 | { |
---|
| 448 | // minimal polynomial has highest possible degree, so we are done. |
---|
| 449 | i = -1; |
---|
| 450 | } |
---|
| 451 | else |
---|
| 452 | { |
---|
| 453 | newvectormat.insertMatrix (lindepmat); |
---|
| 454 | i = newvectormat.findSmallestNonpivot (); |
---|
| 455 | } |
---|
[2024f6a] | 456 | } |
---|
[5b2745] | 457 | } |
---|
[2024f6a] | 458 | |
---|
[5b2745] | 459 | // TODO: take lcms of the different monomials! |
---|
[2024f6a] | 460 | |
---|
[5b2745] | 461 | delete[]vecnew; |
---|
| 462 | delete[]vec; |
---|
| 463 | delete[]tmp; |
---|
| 464 | delete[]mpvec; |
---|
[2024f6a] | 465 | |
---|
[5b2745] | 466 | return result; |
---|
[2024f6a] | 467 | } |
---|
| 468 | |
---|
| 469 | |
---|
[5b2745] | 470 | void rem (unsigned long *a, unsigned long *q, unsigned long p, int °a, |
---|
| 471 | int degq) |
---|
| 472 | { |
---|
| 473 | while(degq <= dega) |
---|
| 474 | { |
---|
| 475 | unsigned d = dega - degq; |
---|
| 476 | long factor = a[dega] * modularInverse (q[degq], p) % p; |
---|
| 477 | for(int i = degq; i >= 0; i--) |
---|
| 478 | { |
---|
| 479 | long tmp = p - (factor * q[i] % p); |
---|
| 480 | a[d + i] += tmp; |
---|
| 481 | a[d + i] %= p; |
---|
| 482 | } |
---|
[2024f6a] | 483 | |
---|
[5b2745] | 484 | while(a[dega] == 0 && dega >= 0) |
---|
| 485 | { |
---|
| 486 | dega--; |
---|
[2024f6a] | 487 | } |
---|
[5b2745] | 488 | } |
---|
[2024f6a] | 489 | } |
---|
| 490 | |
---|
| 491 | |
---|
[5b2745] | 492 | void quo (unsigned long *a, unsigned long *q, unsigned long p, int °a, |
---|
| 493 | int degq) |
---|
| 494 | { |
---|
| 495 | unsigned degres = dega - degq; |
---|
| 496 | unsigned long *result = new unsigned long[degres + 1]; |
---|
| 497 | |
---|
| 498 | while(degq <= dega) |
---|
| 499 | { |
---|
| 500 | unsigned d = dega - degq; |
---|
| 501 | long inv = modularInverse (q[degq], p); |
---|
| 502 | result[d] = a[dega] * inv % p; |
---|
[47a616d] | 503 | for(int i = degq; i >= 0; i--) |
---|
[5b2745] | 504 | { |
---|
| 505 | long tmp = p - (result[d] * q[i] % p); |
---|
| 506 | a[d + i] += tmp; |
---|
| 507 | a[d + i] %= p; |
---|
| 508 | } |
---|
| 509 | |
---|
| 510 | while(a[dega] == 0 && dega >= 0) |
---|
| 511 | { |
---|
| 512 | dega--; |
---|
| 513 | } |
---|
| 514 | } |
---|
| 515 | |
---|
| 516 | // copy result into a |
---|
[47a616d] | 517 | for(int i = 0; i <= degres; i++) |
---|
[5b2745] | 518 | { |
---|
| 519 | a[i] = result[i]; |
---|
| 520 | } |
---|
| 521 | // set all following entries of a to zero |
---|
[47a616d] | 522 | for(int i = degres + 1; i <= degq + degres; i++) |
---|
[5b2745] | 523 | { |
---|
| 524 | a[i] = 0; |
---|
| 525 | } |
---|
| 526 | |
---|
| 527 | dega = degres; |
---|
| 528 | |
---|
| 529 | delete[]result; |
---|
| 530 | } |
---|
[2024f6a] | 531 | |
---|
| 532 | |
---|
[5b2745] | 533 | void mult (unsigned long *result, unsigned long *a, unsigned long *b, |
---|
| 534 | unsigned long p, int dega, int degb) |
---|
| 535 | { |
---|
| 536 | // NOTE: we assume that every entry in result is preinitialized to zero! |
---|
[2024f6a] | 537 | |
---|
[5b2745] | 538 | for(int i = 0; i <= dega; i++) |
---|
| 539 | { |
---|
| 540 | for(int j = 0; j <= degb; j++) |
---|
| 541 | { |
---|
| 542 | result[i + j] += (a[i] * b[j] % p); |
---|
| 543 | result[i + j] %= p; |
---|
[2024f6a] | 544 | } |
---|
[5b2745] | 545 | } |
---|
[2024f6a] | 546 | } |
---|
| 547 | |
---|
| 548 | |
---|
[5b2745] | 549 | int gcd (unsigned long *g, unsigned long *a, unsigned long *b, |
---|
| 550 | unsigned long p, int dega, int degb) |
---|
| 551 | { |
---|
| 552 | unsigned long *tmp1 = new unsigned long[dega + 1]; |
---|
| 553 | unsigned long *tmp2 = new unsigned long[degb + 1]; |
---|
| 554 | for(int i = 0; i <= dega; i++) |
---|
| 555 | { |
---|
| 556 | tmp1[i] = a[i]; |
---|
| 557 | } |
---|
| 558 | for(int i = 0; i <= degb; i++) |
---|
| 559 | { |
---|
| 560 | tmp2[i] = b[i]; |
---|
| 561 | } |
---|
| 562 | int degtmp1 = dega; |
---|
| 563 | int degtmp2 = degb; |
---|
| 564 | |
---|
| 565 | unsigned long *swappol; |
---|
| 566 | int swapdeg; |
---|
| 567 | |
---|
| 568 | while(degtmp2 >= 0) |
---|
| 569 | { |
---|
| 570 | rem (tmp1, tmp2, p, degtmp1, degtmp2); |
---|
| 571 | swappol = tmp1; |
---|
| 572 | tmp1 = tmp2; |
---|
| 573 | tmp2 = swappol; |
---|
| 574 | |
---|
| 575 | swapdeg = degtmp1; |
---|
| 576 | degtmp1 = degtmp2; |
---|
| 577 | degtmp2 = swapdeg; |
---|
| 578 | } |
---|
| 579 | |
---|
| 580 | for(int i = 0; i <= degtmp1; i++) |
---|
| 581 | { |
---|
| 582 | g[i] = tmp1[i]; |
---|
| 583 | } |
---|
| 584 | |
---|
| 585 | delete[]tmp1; |
---|
| 586 | delete[]tmp2; |
---|
| 587 | |
---|
| 588 | return degtmp1; |
---|
| 589 | } |
---|
[2024f6a] | 590 | |
---|
| 591 | |
---|
[5b2745] | 592 | int lcm (unsigned long *l, unsigned long *a, unsigned long *b, |
---|
| 593 | unsigned long p, int dega, int degb) |
---|
| 594 | { |
---|
| 595 | unsigned long *g = new unsigned long[dega + 1]; |
---|
| 596 | // initialize entries of g to zero |
---|
| 597 | for(int i = 0; i <= dega; i++) |
---|
| 598 | { |
---|
| 599 | g[i] = 0; |
---|
| 600 | } |
---|
| 601 | |
---|
| 602 | int degg = gcd (g, a, b, p, dega, degb); |
---|
| 603 | |
---|
| 604 | if(degg > 0) |
---|
| 605 | { |
---|
| 606 | // non-trivial gcd, so compute a = (a/g) |
---|
| 607 | quo (a, g, p, dega, degg); |
---|
| 608 | } |
---|
| 609 | mult (l, a, b, p, dega, degb); |
---|
| 610 | |
---|
| 611 | // normalize |
---|
| 612 | if(l[dega + degb + 1] != 1) |
---|
| 613 | { |
---|
| 614 | unsigned long inv = modularInverse (l[dega + degb], p); |
---|
| 615 | for(int i = 0; i <= dega + degb; i++) |
---|
| 616 | { |
---|
| 617 | l[i] *= inv; |
---|
| 618 | l[i] %= p; |
---|
| 619 | } |
---|
| 620 | } |
---|
| 621 | |
---|
| 622 | return dega + degb; |
---|
[2024f6a] | 623 | } |
---|
| 624 | |
---|
| 625 | |
---|
[47a616d] | 626 | // computes the gcd and the cofactors of u and v |
---|
| 627 | // gcd(u,v) = u3 = u*u1 + v*u2 |
---|
[5b2745] | 628 | long modularInverse (long x, long p) |
---|
| 629 | { |
---|
| 630 | long u1 = 1; |
---|
| 631 | long u2 = 0; |
---|
| 632 | long u3 = x; |
---|
| 633 | long v1 = 0; |
---|
| 634 | long v2 = 1; |
---|
| 635 | long v3 = p; |
---|
| 636 | |
---|
| 637 | long q, t1, t2, t3; |
---|
| 638 | while(v3 != 0) |
---|
| 639 | { |
---|
| 640 | q = u3 / v3; |
---|
| 641 | t1 = u1 - q * v1; |
---|
| 642 | t2 = u2 - q * v2; |
---|
| 643 | t3 = u3 - q * v3; |
---|
| 644 | u1 = v1; |
---|
| 645 | u2 = v2; |
---|
| 646 | u3 = v3; |
---|
| 647 | v1 = t1; |
---|
| 648 | v2 = t2; |
---|
| 649 | v3 = t3; |
---|
| 650 | } |
---|
| 651 | |
---|
| 652 | if(u1 < 0) |
---|
| 653 | { |
---|
| 654 | u1 += p; |
---|
| 655 | } |
---|
| 656 | |
---|
| 657 | return u1; |
---|
[2024f6a] | 658 | } |
---|