congruence_solver 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +9 -6
- data/.gitmodules +0 -4
- data/.rspec +2 -2
- data/README.md +51 -64
- data/Rakefile +107 -87
- data/bench/bench_tools.rb +32 -32
- data/bench/solve_congruence_bm.rb +70 -70
- data/bin/{csolve.rb → csolve} +53 -53
- data/bin/setup +0 -0
- data/congruence_solver.gemspec +32 -38
- data/ext/congruence_solver/Makefile +17 -17
- data/ext/congruence_solver/arith_utils.c +135 -135
- data/ext/congruence_solver/arith_utils.h +9 -9
- data/ext/congruence_solver/congruence_solver.c +85 -85
- data/ext/congruence_solver/congruences.c +226 -226
- data/ext/congruence_solver/congruences.h +6 -6
- data/ext/congruence_solver/extconf.rb +15 -15
- data/ext/congruence_solver/prime_gen.c +146 -146
- data/ext/congruence_solver/prime_gen.h +9 -9
- data/lib/congruence_solver/version.rb +1 -1
- data/lib/polynomial_interpreter.rb +113 -116
- data/license.txt +201 -0
- data/spec/congruence_solver_spec.rb +41 -38
- data/spec/csolve_spec.rb +99 -89
- data/spec/spec_helper.rb +96 -96
- metadata +14 -19
- data/ext/congruence_solver/.gitignore +0 -2
- data/ext/congruence_solver/test/arith_utils_test.c +0 -106
- data/ext/congruence_solver/test/arith_utils_test.h +0 -25
- data/ext/congruence_solver/test/congruences_test.c +0 -78
- data/ext/congruence_solver/test/congruences_test.h +0 -239
- data/ext/congruence_solver/test/prime_gen_test.c +0 -83
- data/ext/congruence_solver/test/prime_gen_test.h +0 -141
@@ -1,85 +1,85 @@
|
|
1
|
-
#include <ruby.h>
|
2
|
-
#include "congruences.h"
|
3
|
-
#include "arith_utils.h"
|
4
|
-
#include "prime_gen.h"
|
5
|
-
|
6
|
-
|
7
|
-
VALUE CongruenceSolver = Qnil;
|
8
|
-
|
9
|
-
void Init_congruence_solver();
|
10
|
-
VALUE method_congruence_solver_lift(VALUE self, VALUE funcCoeffs, VALUE mod);
|
11
|
-
VALUE method_congruence_solver_brute_force(VALUE self, VALUE funcoeffs, VALUE mod);
|
12
|
-
//VALUE method_congruence_solver_solve_system_of_congruences(VALUE self, VALUE funcDegreeAry, VALUE aryOfFuncCoeffArys, VALUE modAry);
|
13
|
-
|
14
|
-
|
15
|
-
void Init_congruence_solver(){
|
16
|
-
CongruenceSolver = rb_define_module("CongruenceSolver");
|
17
|
-
|
18
|
-
rb_define_singleton_method(CongruenceSolver, "lift",
|
19
|
-
method_congruence_solver_lift, 2);
|
20
|
-
|
21
|
-
rb_define_singleton_method(CongruenceSolver, "brute_force",
|
22
|
-
method_congruence_solver_brute_force, 2);
|
23
|
-
|
24
|
-
/*rb_define_singleton_method(CongruenceSolver, "solve_system_of_congruences",
|
25
|
-
method_congruence_solver_solve_system_of_congruence, 3);
|
26
|
-
*/
|
27
|
-
}
|
28
|
-
|
29
|
-
|
30
|
-
VALUE method_congruence_solver_brute_force(VALUE self, VALUE funcCoeffs, VALUE mod){
|
31
|
-
int i;
|
32
|
-
int * intSolutions;
|
33
|
-
VALUE rbSolutions;
|
34
|
-
int intMod = NUM2INT(mod);
|
35
|
-
|
36
|
-
int intFuncDegree = RARRAY_LEN(funcCoeffs)-1;
|
37
|
-
int * intFuncCoeffs = calloc(intFuncDegree+1, sizeof(int));
|
38
|
-
|
39
|
-
for(i = 0; i <= intFuncDegree; i++){
|
40
|
-
intFuncCoeffs[i] = NUM2INT(rb_ary_entry(funcCoeffs, i));
|
41
|
-
}
|
42
|
-
|
43
|
-
intSolutions = brute_force_congruence(intFuncDegree, intFuncCoeffs, intMod);
|
44
|
-
rbSolutions = rb_ary_new2(intSolutions[0]);
|
45
|
-
|
46
|
-
for(i=0; i<intSolutions[0]; i++){
|
47
|
-
rb_ary_store(rbSolutions, i, INT2NUM(intSolutions[i+1]));
|
48
|
-
}
|
49
|
-
|
50
|
-
|
51
|
-
free(intFuncCoeffs);
|
52
|
-
free(intSolutions);
|
53
|
-
|
54
|
-
return rbSolutions;
|
55
|
-
}
|
56
|
-
|
57
|
-
|
58
|
-
VALUE method_congruence_solver_lift(VALUE self, VALUE funcCoeffs, VALUE mod){
|
59
|
-
int i;
|
60
|
-
int * intSolutions;
|
61
|
-
VALUE rbSolutions;
|
62
|
-
int intMod = NUM2INT(mod);
|
63
|
-
|
64
|
-
int intFuncDegree = RARRAY_LEN(funcCoeffs)-1;
|
65
|
-
int * intFuncCoeffs = calloc(intFuncDegree+1, sizeof(int));
|
66
|
-
|
67
|
-
for(i=0; i<=intFuncDegree; i++){
|
68
|
-
intFuncCoeffs[i] = NUM2INT(rb_ary_entry(funcCoeffs, i));
|
69
|
-
}
|
70
|
-
|
71
|
-
|
72
|
-
intSolutions = solve_congruence(intFuncDegree, intFuncCoeffs, intMod);
|
73
|
-
rbSolutions = rb_ary_new2(intSolutions[0]);
|
74
|
-
|
75
|
-
for(i=0; i<intSolutions[0]; i++){
|
76
|
-
rb_ary_store(rbSolutions, i, INT2NUM(intSolutions[i+1]));
|
77
|
-
}
|
78
|
-
|
79
|
-
|
80
|
-
free(intFuncCoeffs);
|
81
|
-
free(intSolutions);
|
82
|
-
|
83
|
-
return rbSolutions;
|
84
|
-
}
|
85
|
-
|
1
|
+
#include <ruby.h>
|
2
|
+
#include "congruences.h"
|
3
|
+
#include "arith_utils.h"
|
4
|
+
#include "prime_gen.h"
|
5
|
+
|
6
|
+
|
7
|
+
VALUE CongruenceSolver = Qnil;
|
8
|
+
|
9
|
+
void Init_congruence_solver();
|
10
|
+
VALUE method_congruence_solver_lift(VALUE self, VALUE funcCoeffs, VALUE mod);
|
11
|
+
VALUE method_congruence_solver_brute_force(VALUE self, VALUE funcoeffs, VALUE mod);
|
12
|
+
//VALUE method_congruence_solver_solve_system_of_congruences(VALUE self, VALUE funcDegreeAry, VALUE aryOfFuncCoeffArys, VALUE modAry);
|
13
|
+
|
14
|
+
|
15
|
+
void Init_congruence_solver(){
|
16
|
+
CongruenceSolver = rb_define_module("CongruenceSolver");
|
17
|
+
|
18
|
+
rb_define_singleton_method(CongruenceSolver, "lift",
|
19
|
+
method_congruence_solver_lift, 2);
|
20
|
+
|
21
|
+
rb_define_singleton_method(CongruenceSolver, "brute_force",
|
22
|
+
method_congruence_solver_brute_force, 2);
|
23
|
+
|
24
|
+
/*rb_define_singleton_method(CongruenceSolver, "solve_system_of_congruences",
|
25
|
+
method_congruence_solver_solve_system_of_congruence, 3);
|
26
|
+
*/
|
27
|
+
}
|
28
|
+
|
29
|
+
|
30
|
+
VALUE method_congruence_solver_brute_force(VALUE self, VALUE funcCoeffs, VALUE mod){
|
31
|
+
int i;
|
32
|
+
int * intSolutions;
|
33
|
+
VALUE rbSolutions;
|
34
|
+
int intMod = NUM2INT(mod);
|
35
|
+
|
36
|
+
int intFuncDegree = RARRAY_LEN(funcCoeffs)-1;
|
37
|
+
int * intFuncCoeffs = calloc(intFuncDegree+1, sizeof(int));
|
38
|
+
|
39
|
+
for(i = 0; i <= intFuncDegree; i++){
|
40
|
+
intFuncCoeffs[i] = NUM2INT(rb_ary_entry(funcCoeffs, i));
|
41
|
+
}
|
42
|
+
|
43
|
+
intSolutions = brute_force_congruence(intFuncDegree, intFuncCoeffs, intMod);
|
44
|
+
rbSolutions = rb_ary_new2(intSolutions[0]);
|
45
|
+
|
46
|
+
for(i=0; i<intSolutions[0]; i++){
|
47
|
+
rb_ary_store(rbSolutions, i, INT2NUM(intSolutions[i+1]));
|
48
|
+
}
|
49
|
+
|
50
|
+
|
51
|
+
free(intFuncCoeffs);
|
52
|
+
free(intSolutions);
|
53
|
+
|
54
|
+
return rbSolutions;
|
55
|
+
}
|
56
|
+
|
57
|
+
|
58
|
+
VALUE method_congruence_solver_lift(VALUE self, VALUE funcCoeffs, VALUE mod){
|
59
|
+
int i;
|
60
|
+
int * intSolutions;
|
61
|
+
VALUE rbSolutions;
|
62
|
+
int intMod = NUM2INT(mod);
|
63
|
+
|
64
|
+
int intFuncDegree = RARRAY_LEN(funcCoeffs)-1;
|
65
|
+
int * intFuncCoeffs = calloc(intFuncDegree+1, sizeof(int));
|
66
|
+
|
67
|
+
for(i=0; i<=intFuncDegree; i++){
|
68
|
+
intFuncCoeffs[i] = NUM2INT(rb_ary_entry(funcCoeffs, i));
|
69
|
+
}
|
70
|
+
|
71
|
+
|
72
|
+
intSolutions = solve_congruence(intFuncDegree, intFuncCoeffs, intMod);
|
73
|
+
rbSolutions = rb_ary_new2(intSolutions[0]);
|
74
|
+
|
75
|
+
for(i=0; i<intSolutions[0]; i++){
|
76
|
+
rb_ary_store(rbSolutions, i, INT2NUM(intSolutions[i+1]));
|
77
|
+
}
|
78
|
+
|
79
|
+
|
80
|
+
free(intFuncCoeffs);
|
81
|
+
free(intSolutions);
|
82
|
+
|
83
|
+
return rbSolutions;
|
84
|
+
}
|
85
|
+
|
@@ -1,227 +1,227 @@
|
|
1
|
-
#include "arith_utils.h"
|
2
|
-
#include "prime_gen.h"
|
3
|
-
#include <stdlib.h>
|
4
|
-
#include <stdio.h>
|
5
|
-
|
6
|
-
static int * adjust_coeffs_to_mod(int degree, int * coeffs, int mod);
|
7
|
-
static int * solve_prime_power_congruence(int degree, int coeffs[], int prime, int power);
|
8
|
-
static int * solve_system_of_order_1_congruence_sets(int numOfSets, int * lengthsOfSets, int ** sets, int mods[]);
|
9
|
-
|
10
|
-
int chinese_remainder_solution(int numberOfEquations, int scals[], int mods[]){
|
11
|
-
int i;
|
12
|
-
int x = 0;
|
13
|
-
int m = mods[0];
|
14
|
-
int modCoeff;
|
15
|
-
|
16
|
-
for(i=1; i<numberOfEquations; i++){
|
17
|
-
m *= mods[i];
|
18
|
-
}
|
19
|
-
|
20
|
-
for(i=0; i<numberOfEquations; i++){
|
21
|
-
modCoeff = m/mods[i];
|
22
|
-
x += modCoeff*mod_inv(modCoeff % mods[i], mods[i])*scals[i];
|
23
|
-
}
|
24
|
-
|
25
|
-
return x % m;
|
26
|
-
}
|
27
|
-
|
28
|
-
|
29
|
-
int * adjust_coeffs_to_mod(int degree, int * coeffs, int mod){
|
30
|
-
int * adjustedCoeffs = calloc(degree+1, sizeof(int));
|
31
|
-
int i;
|
32
|
-
|
33
|
-
for(i = 0; i <= degree; i++){
|
34
|
-
adjustedCoeffs[i] = coeffs[i] % mod;
|
35
|
-
if(adjustedCoeffs[i] < 0){
|
36
|
-
adjustedCoeffs[i] += mod;
|
37
|
-
}
|
38
|
-
}
|
39
|
-
|
40
|
-
return adjustedCoeffs;
|
41
|
-
}
|
42
|
-
|
43
|
-
|
44
|
-
int * brute_force_congruence(int degree, int coeffs[], int primeMod){
|
45
|
-
//assumes a prime modulus. split congruences of composite modulus into systems of congrueneces
|
46
|
-
//of prime modulus and/or apply the lifting theorem to make use of this function
|
47
|
-
//solve a0x^n + a1x^n-1... = 0 (mod mod) where n is the order a0, a1, ... are coeffieicients
|
48
|
-
//also assumes positive representation of coeffs
|
49
|
-
int * adjustedCoeffs = adjust_coeffs_to_mod(degree, coeffs, primeMod);
|
50
|
-
int * solutionList = calloc(degree+1, sizeof(int));
|
51
|
-
int * solutions = solutionList+1;
|
52
|
-
int numberOfSolutions = 0;
|
53
|
-
int x;
|
54
|
-
|
55
|
-
|
56
|
-
for(x = 0; x < primeMod && numberOfSolutions <= degree; x++){
|
57
|
-
if(mod_eval_polynomial(degree, adjustedCoeffs, primeMod, x) == 0){
|
58
|
-
solutions[numberOfSolutions++] = x;
|
59
|
-
}
|
60
|
-
}
|
61
|
-
|
62
|
-
*solutionList = numberOfSolutions;
|
63
|
-
|
64
|
-
free(adjustedCoeffs);
|
65
|
-
|
66
|
-
return solutionList;
|
67
|
-
}
|
68
|
-
|
69
|
-
|
70
|
-
static int * solve_prime_power_congruence(int funcDegree, int funcCoeffs[], int prime, int power){
|
71
|
-
|
72
|
-
int * adjustedCoeffs;
|
73
|
-
|
74
|
-
int * baseSolutionList;
|
75
|
-
int numOfBaseSolutions;
|
76
|
-
int * baseSolutions;
|
77
|
-
|
78
|
-
int * liftedSolutions;
|
79
|
-
int numOfLiftedSolutions;
|
80
|
-
|
81
|
-
int coeff;
|
82
|
-
|
83
|
-
int derivDegree;
|
84
|
-
int * derivCoeffs;
|
85
|
-
int deriv;
|
86
|
-
long int divFunc;
|
87
|
-
|
88
|
-
int i, j, t;
|
89
|
-
int currentMod;
|
90
|
-
|
91
|
-
if(power == 1){
|
92
|
-
baseSolutions = brute_force_congruence(funcDegree, funcCoeffs, prime);
|
93
|
-
return baseSolutions;
|
94
|
-
}
|
95
|
-
|
96
|
-
baseSolutionList = solve_prime_power_congruence(funcDegree, funcCoeffs, prime, power-1);
|
97
|
-
numOfBaseSolutions = *baseSolutionList;
|
98
|
-
baseSolutions = baseSolutionList+1;
|
99
|
-
|
100
|
-
liftedSolutions = calloc(prime*numOfBaseSolutions+1, sizeof(int));
|
101
|
-
numOfLiftedSolutions = 0;
|
102
|
-
|
103
|
-
derivDegree = funcDegree-1;
|
104
|
-
derivCoeffs = calloc(derivDegree+1, sizeof(int));
|
105
|
-
|
106
|
-
currentMod = prime;
|
107
|
-
for(j = 1; j < power; j++){
|
108
|
-
currentMod *= prime;
|
109
|
-
}
|
110
|
-
|
111
|
-
for(j = 0; j <= derivDegree; j++){
|
112
|
-
coeff = funcCoeffs[j+1] % prime;
|
113
|
-
if(coeff < 0){
|
114
|
-
coeff += prime;
|
115
|
-
}
|
116
|
-
derivCoeffs[j] = mod_product(coeff, j+1, prime);
|
117
|
-
}
|
118
|
-
|
119
|
-
|
120
|
-
for(j = 0; j < numOfBaseSolutions; j++){
|
121
|
-
|
122
|
-
deriv = mod_eval_polynomial(derivDegree, derivCoeffs, prime, baseSolutions[j]);
|
123
|
-
divFunc = (eval_polynomial(funcDegree, funcCoeffs, baseSolutions[j]) / (currentMod/prime)) % prime;
|
124
|
-
|
125
|
-
if(deriv % prime != 0){
|
126
|
-
t = (-divFunc*mod_inv(deriv, prime) % prime) + prime;
|
127
|
-
liftedSolutions[++numOfLiftedSolutions] = baseSolutions[j] + t*prime;
|
128
|
-
}
|
129
|
-
|
130
|
-
else if(divFunc % prime == 0){
|
131
|
-
for(t = 1; t <= prime; t++){
|
132
|
-
liftedSolutions[++numOfLiftedSolutions] = baseSolutions[j] + t*(currentMod/prime);
|
133
|
-
}
|
134
|
-
}
|
135
|
-
}
|
136
|
-
|
137
|
-
|
138
|
-
*liftedSolutions = numOfLiftedSolutions;
|
139
|
-
|
140
|
-
free(derivCoeffs);
|
141
|
-
free(baseSolutionList);
|
142
|
-
|
143
|
-
return liftedSolutions;
|
144
|
-
}
|
145
|
-
|
146
|
-
|
147
|
-
static int * solve_system_of_order_1_congruence_sets(int numOfSets, int * setLengths, int * * sets, int * mods){
|
148
|
-
//allocate perumtation array
|
149
|
-
int * divAry = calloc(numOfSets, sizeof(int));
|
150
|
-
int * scalAry = calloc(numOfSets, sizeof(int));
|
151
|
-
int i, j;
|
152
|
-
int numOfSolutions;
|
153
|
-
int * solutionAry;
|
154
|
-
int * dest;
|
155
|
-
int idx;
|
156
|
-
|
157
|
-
for(i = 0, numOfSolutions = 1; i < numOfSets; i++){
|
158
|
-
divAry[i] = numOfSolutions;
|
159
|
-
numOfSolutions *= setLengths[i];
|
160
|
-
}
|
161
|
-
|
162
|
-
solutionAry = calloc(numOfSolutions+1, sizeof(int));
|
163
|
-
solutionAry[0] = numOfSolutions;
|
164
|
-
dest = solutionAry+1;
|
165
|
-
|
166
|
-
for(i = 0; i < numOfSolutions; i++){
|
167
|
-
for(j = 0; j < numOfSets; j++){
|
168
|
-
idx = (i / divAry[j]) % setLengths[j];
|
169
|
-
scalAry[j] = sets[j][idx];
|
170
|
-
}
|
171
|
-
|
172
|
-
*(dest++) = chinese_remainder_solution(numOfSets, scalAry, mods);
|
173
|
-
}
|
174
|
-
|
175
|
-
return solutionAry;
|
176
|
-
}
|
177
|
-
|
178
|
-
int * solve_congruence(int funcDegree, int funcCoeffs[], int mod){
|
179
|
-
int * solutionList;
|
180
|
-
|
181
|
-
int * modFactorList = prime_factors(mod);
|
182
|
-
int numOfModFactors = *modFactorList;
|
183
|
-
int * modFactors = modFactorList+1;
|
184
|
-
|
185
|
-
int * * primePowerSolutions = calloc(numOfModFactors, sizeof(int *));
|
186
|
-
int * primePowers = calloc(numOfModFactors, sizeof(int));
|
187
|
-
int * primePowerSolutionLengths = calloc(numOfModFactors, sizeof(int *));
|
188
|
-
|
189
|
-
int power;
|
190
|
-
int i;
|
191
|
-
|
192
|
-
for(i = 0; i < numOfModFactors; i++){
|
193
|
-
primePowers[i] = modFactors[i];
|
194
|
-
power = 1;
|
195
|
-
|
196
|
-
while(mod % (primePowers[i]*modFactors[i]) == 0){
|
197
|
-
primePowers[i] *= modFactors[i];
|
198
|
-
power++;
|
199
|
-
}
|
200
|
-
|
201
|
-
primePowerSolutions[i] = solve_prime_power_congruence(funcDegree, funcCoeffs, modFactors[i], power);
|
202
|
-
primePowerSolutionLengths[i] = *(primePowerSolutions[i]++);
|
203
|
-
}
|
204
|
-
|
205
|
-
solutionList = solve_system_of_order_1_congruence_sets(numOfModFactors, primePowerSolutionLengths, primePowerSolutions, primePowers);
|
206
|
-
|
207
|
-
for(i = 0; i < numOfModFactors; i++){
|
208
|
-
free(primePowerSolutions[i] - 1);
|
209
|
-
}
|
210
|
-
free(primePowerSolutionLengths);
|
211
|
-
free(primePowerSolutions);
|
212
|
-
free(primePowers);
|
213
|
-
free(modFactorList);
|
214
|
-
|
215
|
-
return solutionList;
|
216
|
-
}
|
217
|
-
|
218
|
-
/*
|
219
|
-
int * solve_system_of_congruences(int numOfFuncs, int * funcDegrees, int ** funcCoeffs, int * mods){
|
220
|
-
int i;
|
221
|
-
int * * funcSolutionSets = calloc(numOfFuncs, sizeof(int *));
|
222
|
-
for(i=0; i<numOfFuncs; i++){
|
223
|
-
funcSolutionSets[i] = solve_congruence(funcDegrees[i], funcCoeffs[i], mods[i]);
|
224
|
-
}
|
225
|
-
return solve_system_of_congruence_sets(numOfFuncs, funcSolutionSets, mods);
|
226
|
-
}
|
1
|
+
#include "arith_utils.h"
|
2
|
+
#include "prime_gen.h"
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include <stdio.h>
|
5
|
+
|
6
|
+
static int * adjust_coeffs_to_mod(int degree, int * coeffs, int mod);
|
7
|
+
static int * solve_prime_power_congruence(int degree, int coeffs[], int prime, int power);
|
8
|
+
static int * solve_system_of_order_1_congruence_sets(int numOfSets, int * lengthsOfSets, int ** sets, int mods[]);
|
9
|
+
|
10
|
+
int chinese_remainder_solution(int numberOfEquations, int scals[], int mods[]){
|
11
|
+
int i;
|
12
|
+
int x = 0;
|
13
|
+
int m = mods[0];
|
14
|
+
int modCoeff;
|
15
|
+
|
16
|
+
for(i=1; i<numberOfEquations; i++){
|
17
|
+
m *= mods[i];
|
18
|
+
}
|
19
|
+
|
20
|
+
for(i=0; i<numberOfEquations; i++){
|
21
|
+
modCoeff = m/mods[i];
|
22
|
+
x += modCoeff*mod_inv(modCoeff % mods[i], mods[i])*scals[i];
|
23
|
+
}
|
24
|
+
|
25
|
+
return x % m;
|
26
|
+
}
|
27
|
+
|
28
|
+
|
29
|
+
int * adjust_coeffs_to_mod(int degree, int * coeffs, int mod){
|
30
|
+
int * adjustedCoeffs = calloc(degree+1, sizeof(int));
|
31
|
+
int i;
|
32
|
+
|
33
|
+
for(i = 0; i <= degree; i++){
|
34
|
+
adjustedCoeffs[i] = coeffs[i] % mod;
|
35
|
+
if(adjustedCoeffs[i] < 0){
|
36
|
+
adjustedCoeffs[i] += mod;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
return adjustedCoeffs;
|
41
|
+
}
|
42
|
+
|
43
|
+
|
44
|
+
int * brute_force_congruence(int degree, int coeffs[], int primeMod){
|
45
|
+
//assumes a prime modulus. split congruences of composite modulus into systems of congrueneces
|
46
|
+
//of prime modulus and/or apply the lifting theorem to make use of this function
|
47
|
+
//solve a0x^n + a1x^n-1... = 0 (mod mod) where n is the order a0, a1, ... are coeffieicients
|
48
|
+
//also assumes positive representation of coeffs
|
49
|
+
int * adjustedCoeffs = adjust_coeffs_to_mod(degree, coeffs, primeMod);
|
50
|
+
int * solutionList = calloc(degree+1, sizeof(int));
|
51
|
+
int * solutions = solutionList+1;
|
52
|
+
int numberOfSolutions = 0;
|
53
|
+
int x;
|
54
|
+
|
55
|
+
|
56
|
+
for(x = 0; x < primeMod && numberOfSolutions <= degree; x++){
|
57
|
+
if(mod_eval_polynomial(degree, adjustedCoeffs, primeMod, x) == 0){
|
58
|
+
solutions[numberOfSolutions++] = x;
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
*solutionList = numberOfSolutions;
|
63
|
+
|
64
|
+
free(adjustedCoeffs);
|
65
|
+
|
66
|
+
return solutionList;
|
67
|
+
}
|
68
|
+
|
69
|
+
|
70
|
+
static int * solve_prime_power_congruence(int funcDegree, int funcCoeffs[], int prime, int power){
|
71
|
+
|
72
|
+
int * adjustedCoeffs;
|
73
|
+
|
74
|
+
int * baseSolutionList;
|
75
|
+
int numOfBaseSolutions;
|
76
|
+
int * baseSolutions;
|
77
|
+
|
78
|
+
int * liftedSolutions;
|
79
|
+
int numOfLiftedSolutions;
|
80
|
+
|
81
|
+
int coeff;
|
82
|
+
|
83
|
+
int derivDegree;
|
84
|
+
int * derivCoeffs;
|
85
|
+
int deriv;
|
86
|
+
long int divFunc;
|
87
|
+
|
88
|
+
int i, j, t;
|
89
|
+
int currentMod;
|
90
|
+
|
91
|
+
if(power == 1){
|
92
|
+
baseSolutions = brute_force_congruence(funcDegree, funcCoeffs, prime);
|
93
|
+
return baseSolutions;
|
94
|
+
}
|
95
|
+
|
96
|
+
baseSolutionList = solve_prime_power_congruence(funcDegree, funcCoeffs, prime, power-1);
|
97
|
+
numOfBaseSolutions = *baseSolutionList;
|
98
|
+
baseSolutions = baseSolutionList+1;
|
99
|
+
|
100
|
+
liftedSolutions = calloc(prime*numOfBaseSolutions+1, sizeof(int));
|
101
|
+
numOfLiftedSolutions = 0;
|
102
|
+
|
103
|
+
derivDegree = funcDegree-1;
|
104
|
+
derivCoeffs = calloc(derivDegree+1, sizeof(int));
|
105
|
+
|
106
|
+
currentMod = prime;
|
107
|
+
for(j = 1; j < power; j++){
|
108
|
+
currentMod *= prime;
|
109
|
+
}
|
110
|
+
|
111
|
+
for(j = 0; j <= derivDegree; j++){
|
112
|
+
coeff = funcCoeffs[j+1] % prime;
|
113
|
+
if(coeff < 0){
|
114
|
+
coeff += prime;
|
115
|
+
}
|
116
|
+
derivCoeffs[j] = mod_product(coeff, j+1, prime);
|
117
|
+
}
|
118
|
+
|
119
|
+
|
120
|
+
for(j = 0; j < numOfBaseSolutions; j++){
|
121
|
+
|
122
|
+
deriv = mod_eval_polynomial(derivDegree, derivCoeffs, prime, baseSolutions[j]);
|
123
|
+
divFunc = (eval_polynomial(funcDegree, funcCoeffs, baseSolutions[j]) / (currentMod/prime)) % prime;
|
124
|
+
|
125
|
+
if(deriv % prime != 0){
|
126
|
+
t = (-divFunc*mod_inv(deriv, prime) % prime) + prime;
|
127
|
+
liftedSolutions[++numOfLiftedSolutions] = baseSolutions[j] + t*prime;
|
128
|
+
}
|
129
|
+
|
130
|
+
else if(divFunc % prime == 0){
|
131
|
+
for(t = 1; t <= prime; t++){
|
132
|
+
liftedSolutions[++numOfLiftedSolutions] = baseSolutions[j] + t*(currentMod/prime);
|
133
|
+
}
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
|
138
|
+
*liftedSolutions = numOfLiftedSolutions;
|
139
|
+
|
140
|
+
free(derivCoeffs);
|
141
|
+
free(baseSolutionList);
|
142
|
+
|
143
|
+
return liftedSolutions;
|
144
|
+
}
|
145
|
+
|
146
|
+
|
147
|
+
static int * solve_system_of_order_1_congruence_sets(int numOfSets, int * setLengths, int * * sets, int * mods){
|
148
|
+
//allocate perumtation array
|
149
|
+
int * divAry = calloc(numOfSets, sizeof(int));
|
150
|
+
int * scalAry = calloc(numOfSets, sizeof(int));
|
151
|
+
int i, j;
|
152
|
+
int numOfSolutions;
|
153
|
+
int * solutionAry;
|
154
|
+
int * dest;
|
155
|
+
int idx;
|
156
|
+
|
157
|
+
for(i = 0, numOfSolutions = 1; i < numOfSets; i++){
|
158
|
+
divAry[i] = numOfSolutions;
|
159
|
+
numOfSolutions *= setLengths[i];
|
160
|
+
}
|
161
|
+
|
162
|
+
solutionAry = calloc(numOfSolutions+1, sizeof(int));
|
163
|
+
solutionAry[0] = numOfSolutions;
|
164
|
+
dest = solutionAry+1;
|
165
|
+
|
166
|
+
for(i = 0; i < numOfSolutions; i++){
|
167
|
+
for(j = 0; j < numOfSets; j++){
|
168
|
+
idx = (i / divAry[j]) % setLengths[j];
|
169
|
+
scalAry[j] = sets[j][idx];
|
170
|
+
}
|
171
|
+
|
172
|
+
*(dest++) = chinese_remainder_solution(numOfSets, scalAry, mods);
|
173
|
+
}
|
174
|
+
|
175
|
+
return solutionAry;
|
176
|
+
}
|
177
|
+
|
178
|
+
int * solve_congruence(int funcDegree, int funcCoeffs[], int mod){
|
179
|
+
int * solutionList;
|
180
|
+
|
181
|
+
int * modFactorList = prime_factors(mod);
|
182
|
+
int numOfModFactors = *modFactorList;
|
183
|
+
int * modFactors = modFactorList+1;
|
184
|
+
|
185
|
+
int * * primePowerSolutions = calloc(numOfModFactors, sizeof(int *));
|
186
|
+
int * primePowers = calloc(numOfModFactors, sizeof(int));
|
187
|
+
int * primePowerSolutionLengths = calloc(numOfModFactors, sizeof(int *));
|
188
|
+
|
189
|
+
int power;
|
190
|
+
int i;
|
191
|
+
|
192
|
+
for(i = 0; i < numOfModFactors; i++){
|
193
|
+
primePowers[i] = modFactors[i];
|
194
|
+
power = 1;
|
195
|
+
|
196
|
+
while(mod % (primePowers[i]*modFactors[i]) == 0){
|
197
|
+
primePowers[i] *= modFactors[i];
|
198
|
+
power++;
|
199
|
+
}
|
200
|
+
|
201
|
+
primePowerSolutions[i] = solve_prime_power_congruence(funcDegree, funcCoeffs, modFactors[i], power);
|
202
|
+
primePowerSolutionLengths[i] = *(primePowerSolutions[i]++);
|
203
|
+
}
|
204
|
+
|
205
|
+
solutionList = solve_system_of_order_1_congruence_sets(numOfModFactors, primePowerSolutionLengths, primePowerSolutions, primePowers);
|
206
|
+
|
207
|
+
for(i = 0; i < numOfModFactors; i++){
|
208
|
+
free(primePowerSolutions[i] - 1);
|
209
|
+
}
|
210
|
+
free(primePowerSolutionLengths);
|
211
|
+
free(primePowerSolutions);
|
212
|
+
free(primePowers);
|
213
|
+
free(modFactorList);
|
214
|
+
|
215
|
+
return solutionList;
|
216
|
+
}
|
217
|
+
|
218
|
+
/*
|
219
|
+
int * solve_system_of_congruences(int numOfFuncs, int * funcDegrees, int ** funcCoeffs, int * mods){
|
220
|
+
int i;
|
221
|
+
int * * funcSolutionSets = calloc(numOfFuncs, sizeof(int *));
|
222
|
+
for(i=0; i<numOfFuncs; i++){
|
223
|
+
funcSolutionSets[i] = solve_congruence(funcDegrees[i], funcCoeffs[i], mods[i]);
|
224
|
+
}
|
225
|
+
return solve_system_of_congruence_sets(numOfFuncs, funcSolutionSets, mods);
|
226
|
+
}
|
227
227
|
*/
|
@@ -1,7 +1,7 @@
|
|
1
|
-
#ifndef H_CONGRUENCES
|
2
|
-
#define H_CONGRUENCES
|
3
|
-
int chinese_remainder_solution(int numOfEquations, int scals[], int mods[]);
|
4
|
-
int * solve_congruence(int funcDegree, int funcCoeffs[], int mod);
|
5
|
-
int * brute_force_congruence(int degree, int coeffs[], int primeMod);
|
6
|
-
//int * solve_system_of_congruences(int numOfFuncs, int * funcDegrees, int ** funcCoeffs, int * mods);
|
1
|
+
#ifndef H_CONGRUENCES
|
2
|
+
#define H_CONGRUENCES
|
3
|
+
int chinese_remainder_solution(int numOfEquations, int scals[], int mods[]);
|
4
|
+
int * solve_congruence(int funcDegree, int funcCoeffs[], int mod);
|
5
|
+
int * brute_force_congruence(int degree, int coeffs[], int primeMod);
|
6
|
+
//int * solve_system_of_congruences(int numOfFuncs, int * funcDegrees, int ** funcCoeffs, int * mods);
|
7
7
|
#endif
|
@@ -1,16 +1,16 @@
|
|
1
|
-
require "mkmf"
|
2
|
-
|
3
|
-
EXT_H = %w[
|
4
|
-
arith_utils.h
|
5
|
-
congruences.h
|
6
|
-
prime_gen.h
|
7
|
-
]
|
8
|
-
|
9
|
-
EXT_C = %w[
|
10
|
-
arith_utils.c
|
11
|
-
congruence_solver.c
|
12
|
-
congruences.c
|
13
|
-
prime_gen.c
|
14
|
-
]
|
15
|
-
|
1
|
+
require "mkmf"
|
2
|
+
|
3
|
+
EXT_H = %w[
|
4
|
+
arith_utils.h
|
5
|
+
congruences.h
|
6
|
+
prime_gen.h
|
7
|
+
]
|
8
|
+
|
9
|
+
EXT_C = %w[
|
10
|
+
arith_utils.c
|
11
|
+
congruence_solver.c
|
12
|
+
congruences.c
|
13
|
+
prime_gen.c
|
14
|
+
]
|
15
|
+
|
16
16
|
create_makefile "congruence_solver/congruence_solver"
|