/* Author: Pate Williams (c) 1997 "Algorithm 3.4.2 (Squarefree Factorization). Let A is contained in Fp[X] be a monic polynomial and let A = product(i >= 1, A[i] ^ i) be its square- free factorization, where the A[i] are squarefree and pairwise coprime." -Henri Cohen- See "A Course in Computational Algebraic Number Theory" by Henri Cohen page 126. */ #include #include #include #include "lip.h" #define DEBUG #define POLY_SIZE 256 void error(char *message) { fprintf(stderr, "%s", message); exit(1); } verylong **allocate_very_matrix(long m, long n) { long i; verylong **matrix = calloc(m, sizeof(verylong *)); if (!matrix) error("Failure in allocate_very_matrix."); for (i = 0; i < m; i++) { matrix[i] = calloc(n, sizeof(verylong)); if (!matrix[i]) error("Failure in allocate_very_matrix."); } return matrix; } void free_very_matrix(verylong **zm, long m, long n) { long i, j; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) zfree(&zm[i][j]); free(zm[i]); } free(zm); } void zspow(verylong za, long n, verylong *zb) { int c = zscompare(za, 0l); verylong zc = 0; if (c > 0) zsexp(za, n, zb); else if (c < 0) { zcopy(za, &zc); zabs(&zc); zsexp(zc, n, zb); if (n & 1) znegate(zb); } else zzero(zb); zfree(&zc); } void zpoly_div(long m, long n, verylong *zu, verylong *zv, verylong *zq, verylong *zr, long *p, long *s) { long j, jk, k, nk; verylong za = 0, zb = 0, zvn = 0; zcopy(zv[n], &zvn); for (j = 0; j <= m; j++) zcopy(zu[j], &zr[j]); if (m < n) { *p = 0, *s = m; zzero(&zq[0]); } else { *p = m - n, *s = n - 1; for (k = *p; k >= 0; k--) { nk = n + k; zspow(zvn, k, &za); zmul(zr[nk], za, &zq[k]); for (j = nk - 1; j >= 0; j--) { jk = j - k; if (jk >= 0) { zmul(zvn, zr[j], &za); zmul(zr[nk], zv[jk], &zb); zsub(za, zb, &zr[j]); } else { zcopy(zr[j], &za); zmul(zvn, za, &zr[j]); } } } while (*p > 0 && zscompare(zq[*p], 0l) == 0) *p = *p - 1; while (*s > 0 && zscompare(zr[*s], 0l) == 0) *s = *s - 1; } zfree(&za); zfree(&zb); zfree(&zvn); } void zpoly_gcd(long degreeA, long degreeB, long p, verylong *zA, verylong *zB, verylong *za, long *da) { int nonzero = 0, zero; long db, dq, dr, i; verylong zc = 0, zp = 0; verylong zb[POLY_SIZE], zq[POLY_SIZE], zr[POLY_SIZE]; for (i = 0; i < POLY_SIZE; i++) zb[i] = zq[i] = zr[i] = 0; if (degreeA > degreeB) { *da = degreeA; db = degreeB; for (i = 0; i <= *da; i++) zcopy(zA[i], &za[i]); for (i = 0; i <= db; i++) zcopy(zB[i], &zb[i]); } else { *da = degreeB; db = degreeA; for (i = 0; i <= *da; i++) zcopy(zB[i], &za[i]); for (i = 0; i <= db; i++) zcopy(zA[i], &zb[i]); } for (i = 0; i <= db && !nonzero; i++) nonzero = zscompare(zb[i], 0l) != 0; while (nonzero) { zpoly_div(*da, db, za, zb, zq, zr, &dq, &dr); zintoz(p, &zp); for (i = 0; i <= dr; i++) { zcopy(zr[i], &zc); zmod(zc, zp, &zr[i]); } zero = 1; for (i = dr; i >= 0 && zero; i--) { zero = zscompare(zr[i], 0l) == 0; if (zero && dr > 0) dr--; } for (i = 0; i <= db; i++) zcopy(zb[i], &za[i]); *da = db; for (i = 0; i <= dr; i++) zcopy(zr[i], &zb[i]); db = dr; nonzero = 0; for (i = 0; i <= db && !nonzero; i++) nonzero = zscompare(zb[i], 0l) != 0; } zfree(&zc); zfree(&zp); for (i = 0; i < POLY_SIZE; i++) { zfree(&zb[i]); zfree(&zq[i]); zfree(&zr[i]); } } void zpoly_write(char *label, long dA, verylong *zA) { long i; printf("%s", label); for (i = dA; i >= 0; i--) { zwrite(zA[i]); printf(" "); } printf("\n"); } void monic(long dA, long p, verylong *zA) { long i; verylong za = 0, zi = 0, zp = 0; zintoz(p, &zp); zinvmod(zA[dA], zp, &zi); zone(&zA[dA]); for (i = 0; i < dA; i++) { zmulmod(zA[i], zi, zp, &za); zcopy(za, &zA[i]); } zfree(&za); zfree(&zi); zfree(&zp); } void square_free(long dA, long p, verylong *zA, verylong **zB, long *dB, long *expB, long *count) /* factors A into the matrix B */ { int zero; long dP, dR, dT, dT0, dT0p, dV, dW, e = 1, i, j, k; verylong za = 0; verylong zP[POLY_SIZE], zR[POLY_SIZE]; verylong zT[POLY_SIZE], zV[POLY_SIZE]; verylong zW[POLY_SIZE]; verylong zT0[POLY_SIZE], zT0p[POLY_SIZE]; *count = 0; for (i = 0; i < POLY_SIZE; i++) { zP[i] = zT[i] = zR[i] = zV[i] = zW[i]; zT0[i] = zT0p[i] = 0; } for (i = 0; i <= dA; i++) zcopy(zA[i], &zT0[i]); dT0 = dA; L2: zero = 1; for (i = 1; zero && i <= dT0; i++) zero = zscompare(zT0[i], 0l) == 0; if (zero) { zfree(&za); for (i = 0; i < POLY_SIZE; i++) { zfree(&zP[i]); zfree(&zR[i]); zfree(&zT[i]); zfree(&zV[i]); zfree(&zW[i]); zfree(&zT0[i]); zfree(&zT0p[i]); } return; } /* calculate derivative of T0 */ for (i = 1; i <= dT0; i++) { zsmul(zT0[i], i, &za); zintoz(zsmod(za, p), &zT0p[i - 1]); } dT0p = dT0 - 1; zero = 1; for (i = dT0p; zero && i >= 0; i--) { zero = zscompare(zT0p[i], 0l) == 0; if (zero) dT0p--; } if (dT0p == - 1) dT0p++; zpoly_gcd(dT0, dT0p, p, zT0, zT0p, zT, &dT); zpoly_div(dT0, dT, zT0, zT, zV, zR, &dV, &dR); for (i = 0; i <= dT; i++) zintoz(zsmod(zT[i], p), &zT[i]); k = 0; L3: for (i = 0; i <= dV; i++) zintoz(zsmod(zV[i], p), &zV[i]); #ifdef DEBUG zpoly_write("T0 = ", dT0, zT0); zpoly_write("T0' = ", dT0p, zT0p); zpoly_write("T = ", dT, zT); zpoly_write("V = ", dV, zV); #endif zero = 1; for (i = 1; zero && i <= dV; i++) zero = zscompare(zV[i], 0l) == 0; if (zero) { dT0 = - 1; for (j = 0; j <= dT / p; j++) { if (j % p == 0) { dT0++; zcopy(zT[j], &zT0[j / p]); } } if (dT0 == - 1) dT0++; e *= p; goto L2; } k++; if (k % p == 0) { zpoly_div(dT, dV, zT, zV, zP, zR, &dP, &dR); for (i = 0; i <= dP; i++) zintoz(zsmod(zP[i], p), &zT[i]); dT = dP; k++; } zpoly_gcd(dT, dV, p, zT, zV, zW, &dW); zpoly_div(dV, dW, zV, zW, zB[*count], zR, &dB[*count], &dR); for (i = 0; i <= dB[*count]; i++) zintoz(zsmod(zB[*count][i], p), &zB[*count][i]); zero = 1; for (i = dB[*count]; zero && i >= 0; i--) { zero = zscompare(zB[*count][i], 0l) == 0; if (zero) dB[*count]--; } monic(dB[*count], p, zB[*count]); #ifdef DEBUG zpoly_write("W = ", dW, zW); zpoly_write("A = ", dB[*count], zB[*count]); #endif for (i = 0; i <= dW; i++) zcopy(zW[i], &zV[i]); dV = dW; zpoly_div(dT, dV, zT, zV, zP, zR, &dP, &dR); for (i = 0; i <= dP; i++) zintoz(zsmod(zP[i], p), &zT[i]); dT = dP; if (dB[*count] != dA) { zero = 1; for (i = 1; zero && i <= dB[*count]; i++) zero = zscompare(zB[*count][i], 0l) == 0; if (dB[*count] > 0 && !zero) { expB[*count] = e * k; *count = *count + 1; } } goto L3; } int main(void) { char answer[256]; long count, dA, dB[32], expB[32], i, m = 32, p; verylong zA[POLY_SIZE] = {0}; verylong **zB = allocate_very_matrix(m, POLY_SIZE); do { printf("degree of polynomial = "); scanf("%d", &dA); printf("modulus = "); scanf("%d", &p); for (i = 0; i <= dA; i++) { printf("A[%ld] = ", i); zread(&zA[i]); } square_free(dA, p, zA, zB, dB, expB, &count); for (i = 0; i < count; i++) { printf("exponent = %ld ", expB[i]); zpoly_write("factor = ", dB[i], zB[i]); } printf("another polynomial (n or y)? "); scanf("%s", answer); } while (tolower(answer[0]) == 'y'); for (i = 0; i <= dA; i++) zfree(&zA[i]); free_very_matrix(zB, m, POLY_SIZE); return 0; }