ext/congruence_solver/congruences.c in congruence_solver-0.3.0 vs ext/congruence_solver/congruences.c in congruence_solver-0.3.1

- old
+ new

@@ -1,199 +1,227 @@ #include "arith_utils.h" #include "prime_gen.h" #include <stdlib.h> #include <stdio.h> +static int * adjust_coeffs_to_mod(int degree, int * coeffs, int mod); static int * solve_prime_power_congruence(int degree, int coeffs[], int prime, int power); static int * solve_system_of_order_1_congruence_sets(int numOfSets, int * lengthsOfSets, int ** sets, int mods[]); int chinese_remainder_solution(int numberOfEquations, int scals[], int mods[]){ - int i; - int x = 0; - int m = mods[0]; - int modCoeff; + int i; + int x = 0; + int m = mods[0]; + int modCoeff; - for(i=1; i<numberOfEquations; i++){ - m *= mods[i]; - } + for(i=1; i<numberOfEquations; i++){ + m *= mods[i]; + } - for(i=0; i<numberOfEquations; i++){ - modCoeff = m/mods[i]; - x += modCoeff*mod_inv(modCoeff, mods[i])*scals[i]; - } + for(i=0; i<numberOfEquations; i++){ + modCoeff = m/mods[i]; + x += modCoeff*mod_inv(modCoeff % mods[i], mods[i])*scals[i]; + } - return x % m; + return x % m; } +int * adjust_coeffs_to_mod(int degree, int * coeffs, int mod){ + int * adjustedCoeffs = calloc(degree+1, sizeof(int)); + int i; + + for(i = 0; i <= degree; i++){ + adjustedCoeffs[i] = coeffs[i] % mod; + if(adjustedCoeffs[i] < 0){ + adjustedCoeffs[i] += mod; + } + } + + return adjustedCoeffs; +} + + int * brute_force_congruence(int degree, int coeffs[], int primeMod){ - //assumes a prime modulus. split congruences of composite modulus into systems of congrueneces - //of prime modulus and/or apply the lifting theorem to make use of this function - //solve a0x^n + a1x^n-1... = 0 (mod mod) where n is the order a0, a1, ... are coeffieicients - int * solutionList = calloc(degree+1, sizeof(int)); - int * solutions = solutionList+1; - int numberOfSolutions = 0; - int x; + //assumes a prime modulus. split congruences of composite modulus into systems of congrueneces + //of prime modulus and/or apply the lifting theorem to make use of this function + //solve a0x^n + a1x^n-1... = 0 (mod mod) where n is the order a0, a1, ... are coeffieicients + //also assumes positive representation of coeffs + int * adjustedCoeffs = adjust_coeffs_to_mod(degree, coeffs, primeMod); + int * solutionList = calloc(degree+1, sizeof(int)); + int * solutions = solutionList+1; + int numberOfSolutions = 0; + int x; - for(x = 0; x < primeMod && numberOfSolutions <= degree; x++){ - if(mod_eval_polynomial(degree, coeffs, primeMod, x) == 0){ - solutions[numberOfSolutions++] = x; - } - } - *solutionList = numberOfSolutions; + for(x = 0; x < primeMod && numberOfSolutions <= degree; x++){ + if(mod_eval_polynomial(degree, adjustedCoeffs, primeMod, x) == 0){ + solutions[numberOfSolutions++] = x; + } + } - return solutionList; + *solutionList = numberOfSolutions; + + free(adjustedCoeffs); + + return solutionList; } static int * solve_prime_power_congruence(int funcDegree, int funcCoeffs[], int prime, int power){ - int * baseSolutionList; - int numOfBaseSolutions; - int * baseSolutions; + int * adjustedCoeffs; - int * liftedSolutions; - int numOfLiftedSolutions; + int * baseSolutionList; + int numOfBaseSolutions; + int * baseSolutions; - int derivDegree; - int * derivCoeffs; - int deriv; - long int divFunc; + int * liftedSolutions; + int numOfLiftedSolutions; - int j, t; - int currentMod; + int coeff; - if(power == 1){ - return brute_force_congruence(funcDegree, funcCoeffs, prime); - } + int derivDegree; + int * derivCoeffs; + int deriv; + long int divFunc; - baseSolutionList = solve_prime_power_congruence(funcDegree, funcCoeffs, prime, power-1); - numOfBaseSolutions = *baseSolutionList; - baseSolutions = baseSolutionList+1; + int i, j, t; + int currentMod; - liftedSolutions = calloc(prime*numOfBaseSolutions+1, sizeof(int)); - numOfLiftedSolutions = 0; + if(power == 1){ + baseSolutions = brute_force_congruence(funcDegree, funcCoeffs, prime); + return baseSolutions; + } - derivDegree = funcDegree-1; - derivCoeffs = calloc(derivDegree+1, sizeof(int)); + baseSolutionList = solve_prime_power_congruence(funcDegree, funcCoeffs, prime, power-1); + numOfBaseSolutions = *baseSolutionList; + baseSolutions = baseSolutionList+1; - currentMod = prime; - for(j = 1; j < power; j++){ - currentMod *= prime; - } + liftedSolutions = calloc(prime*numOfBaseSolutions+1, sizeof(int)); + numOfLiftedSolutions = 0; - for(j = 0; j <= derivDegree; j++){ - derivCoeffs[j] = funcCoeffs[j+1]*(j+1); - } + derivDegree = funcDegree-1; + derivCoeffs = calloc(derivDegree+1, sizeof(int)); + currentMod = prime; + for(j = 1; j < power; j++){ + currentMod *= prime; + } - for(j = 0; j < numOfBaseSolutions; j++){ - deriv = mod_eval_polynomial(derivDegree, derivCoeffs, prime, baseSolutions[j]); - divFunc = (eval_polynomial(funcDegree, funcCoeffs, baseSolutions[j]) / (currentMod/prime)) % prime; + for(j = 0; j <= derivDegree; j++){ + coeff = funcCoeffs[j+1] % prime; + if(coeff < 0){ + coeff += prime; + } + derivCoeffs[j] = mod_product(coeff, j+1, prime); + } - if(deriv % prime != 0){ - t = (-divFunc*mod_inv(deriv, prime) % prime) + prime; - liftedSolutions[++numOfLiftedSolutions] = baseSolutions[j] + t*prime; - } - else if(divFunc % prime == 0){ - for(t = 1; t <= prime; t++){ - liftedSolutions[++numOfLiftedSolutions] = baseSolutions[j] + t*(currentMod/prime); - } - } - } + for(j = 0; j < numOfBaseSolutions; j++){ + deriv = mod_eval_polynomial(derivDegree, derivCoeffs, prime, baseSolutions[j]); + divFunc = (eval_polynomial(funcDegree, funcCoeffs, baseSolutions[j]) / (currentMod/prime)) % prime; - *liftedSolutions = numOfLiftedSolutions; + if(deriv % prime != 0){ + t = (-divFunc*mod_inv(deriv, prime) % prime) + prime; + liftedSolutions[++numOfLiftedSolutions] = baseSolutions[j] + t*prime; + } - free(derivCoeffs); - free(baseSolutionList); + else if(divFunc % prime == 0){ + for(t = 1; t <= prime; t++){ + liftedSolutions[++numOfLiftedSolutions] = baseSolutions[j] + t*(currentMod/prime); + } + } + } - return liftedSolutions; + + *liftedSolutions = numOfLiftedSolutions; + + free(derivCoeffs); + free(baseSolutionList); + + return liftedSolutions; } static int * solve_system_of_order_1_congruence_sets(int numOfSets, int * setLengths, int * * sets, int * mods){ - //allocate perumtation array - int * divAry = calloc(numOfSets, sizeof(int)); - int * scalAry = calloc(numOfSets, sizeof(int)); - int i, j; - int numOfSolutions; - int * solutionAry; - int * dest; - int idx; + //allocate perumtation array + int * divAry = calloc(numOfSets, sizeof(int)); + int * scalAry = calloc(numOfSets, sizeof(int)); + int i, j; + int numOfSolutions; + int * solutionAry; + int * dest; + int idx; - for(i = 0, numOfSolutions = 1; i < numOfSets; i++){ - divAry[i] = numOfSolutions; - numOfSolutions *= setLengths[i]; - } + for(i = 0, numOfSolutions = 1; i < numOfSets; i++){ + divAry[i] = numOfSolutions; + numOfSolutions *= setLengths[i]; + } - solutionAry = calloc(numOfSolutions+1, sizeof(int)); - solutionAry[0] = numOfSolutions; - dest = solutionAry+1; + solutionAry = calloc(numOfSolutions+1, sizeof(int)); + solutionAry[0] = numOfSolutions; + dest = solutionAry+1; - for(i = 0; i < numOfSolutions; i++){ - for(j = 0; j < numOfSets; j++){ - idx = (i / divAry[j]) % setLengths[j]; - scalAry[j] = sets[j][idx]; - } + for(i = 0; i < numOfSolutions; i++){ + for(j = 0; j < numOfSets; j++){ + idx = (i / divAry[j]) % setLengths[j]; + scalAry[j] = sets[j][idx]; + } - *(dest++) = chinese_remainder_solution(numOfSets, scalAry, mods); - } + *(dest++) = chinese_remainder_solution(numOfSets, scalAry, mods); + } - return solutionAry; + return solutionAry; } int * solve_congruence(int funcDegree, int funcCoeffs[], int mod){ - int * solutionList; + int * solutionList; - int * modFactorList = prime_factors(mod); - int numOfModFactors = *modFactorList; - int * modFactors = modFactorList+1; + int * modFactorList = prime_factors(mod); + int numOfModFactors = *modFactorList; + int * modFactors = modFactorList+1; - int * * primePowerSolutions = calloc(numOfModFactors, sizeof(int *)); - int * primePowers = calloc(numOfModFactors, sizeof(int)); - int * primePowerSolutionLengths = calloc(numOfModFactors, sizeof(int *)); + int * * primePowerSolutions = calloc(numOfModFactors, sizeof(int *)); + int * primePowers = calloc(numOfModFactors, sizeof(int)); + int * primePowerSolutionLengths = calloc(numOfModFactors, sizeof(int *)); - int power; - int i; + int power; + int i; - for(i = 0; i < numOfModFactors; i++){ - primePowers[i] = modFactors[i]; - power = 1; - - while(mod % (primePowers[i]*modFactors[i]) == 0){ - primePowers[i] *= modFactors[i]; - power++; - } + for(i = 0; i < numOfModFactors; i++){ + primePowers[i] = modFactors[i]; + power = 1; + + while(mod % (primePowers[i]*modFactors[i]) == 0){ + primePowers[i] *= modFactors[i]; + power++; + } - primePowerSolutions[i] = solve_prime_power_congruence(funcDegree, funcCoeffs, modFactors[i], power); - primePowerSolutionLengths[i] = *(primePowerSolutions[i]++); - } + primePowerSolutions[i] = solve_prime_power_congruence(funcDegree, funcCoeffs, modFactors[i], power); + primePowerSolutionLengths[i] = *(primePowerSolutions[i]++); + } + solutionList = solve_system_of_order_1_congruence_sets(numOfModFactors, primePowerSolutionLengths, primePowerSolutions, primePowers); - solutionList = solve_system_of_order_1_congruence_sets(numOfModFactors, primePowerSolutionLengths, primePowerSolutions, primePowers); + for(i = 0; i < numOfModFactors; i++){ + free(primePowerSolutions[i] - 1); + } + free(primePowerSolutionLengths); + free(primePowerSolutions); + free(primePowers); + free(modFactorList); - for(i = 0; i < numOfModFactors; i++){ - free(primePowerSolutions[i] - 1); - } - free(primePowerSolutionLengths); - free(primePowerSolutions); - free(primePowers); - free(modFactorList); - - return solutionList; + return solutionList; } /* int * solve_system_of_congruences(int numOfFuncs, int * funcDegrees, int ** funcCoeffs, int * mods){ - int i; - int * * funcSolutionSets = calloc(numOfFuncs, sizeof(int *)); - - for(i=0; i<numOfFuncs; i++){ - funcSolutionSets[i] = solve_congruence(funcDegrees[i], funcCoeffs[i], mods[i]); - } - - return solve_system_of_congruence_sets(numOfFuncs, funcSolutionSets, mods); -} -*/ + int i; + int * * funcSolutionSets = calloc(numOfFuncs, sizeof(int *)); + for(i=0; i<numOfFuncs; i++){ + funcSolutionSets[i] = solve_congruence(funcDegrees[i], funcCoeffs[i], mods[i]); + } + return solve_system_of_congruence_sets(numOfFuncs, funcSolutionSets, mods); +} +*/ \ No newline at end of file