congruence_solver 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,73 +13,73 @@ VALUE method_congruence_solver_brute_force(VALUE self, VALUE funcoeffs, VALUE mo
13
13
 
14
14
 
15
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);
16
+ CongruenceSolver = rb_define_module("CongruenceSolver");
17
+
18
+ rb_define_singleton_method(CongruenceSolver, "lift",
19
+ method_congruence_solver_lift, 2);
20
20
 
21
- rb_define_singleton_method(CongruenceSolver, "brute_force",
22
- method_congruence_solver_brute_force, 2);
21
+ rb_define_singleton_method(CongruenceSolver, "brute_force",
22
+ method_congruence_solver_brute_force, 2);
23
23
 
24
- /*rb_define_singleton_method(CongruenceSolver, "solve_system_of_congruences",
25
- method_congruence_solver_solve_system_of_congruence, 3);
26
- */
24
+ /*rb_define_singleton_method(CongruenceSolver, "solve_system_of_congruences",
25
+ method_congruence_solver_solve_system_of_congruence, 3);
26
+ */
27
27
  }
28
28
 
29
29
 
30
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);
31
+ int i;
32
+ int * intSolutions;
33
+ VALUE rbSolutions;
34
+ int intMod = NUM2INT(mod);
35
35
 
36
- int intFuncDegree = RARRAY_LEN(funcCoeffs)-1;
37
- int * intFuncCoeffs = calloc(intFuncDegree+1, sizeof(int));
36
+ int intFuncDegree = RARRAY_LEN(funcCoeffs)-1;
37
+ int * intFuncCoeffs = calloc(intFuncDegree+1, sizeof(int));
38
38
 
39
- for(i = 0; i <= intFuncDegree; i++){
40
- intFuncCoeffs[i] = NUM2INT(rb_ary_entry(funcCoeffs, i));
41
- }
39
+ for(i = 0; i <= intFuncDegree; i++){
40
+ intFuncCoeffs[i] = NUM2INT(rb_ary_entry(funcCoeffs, i));
41
+ }
42
42
 
43
- intSolutions = brute_force_congruence(intFuncDegree, intFuncCoeffs, intMod);
44
- rbSolutions = rb_ary_new2(intSolutions[0]);
43
+ intSolutions = brute_force_congruence(intFuncDegree, intFuncCoeffs, intMod);
44
+ rbSolutions = rb_ary_new2(intSolutions[0]);
45
45
 
46
- for(i=0; i<intSolutions[0]; i++){
47
- rb_ary_store(rbSolutions, i, INT2NUM(intSolutions[i+1]));
48
- }
46
+ for(i=0; i<intSolutions[0]; i++){
47
+ rb_ary_store(rbSolutions, i, INT2NUM(intSolutions[i+1]));
48
+ }
49
49
 
50
50
 
51
- free(intFuncCoeffs);
52
- free(intSolutions);
51
+ free(intFuncCoeffs);
52
+ free(intSolutions);
53
53
 
54
- return rbSolutions;
54
+ return rbSolutions;
55
55
  }
56
56
 
57
57
 
58
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);
59
+ int i;
60
+ int * intSolutions;
61
+ VALUE rbSolutions;
62
+ int intMod = NUM2INT(mod);
63
63
 
64
- int intFuncDegree = RARRAY_LEN(funcCoeffs)-1;
65
- int * intFuncCoeffs = calloc(intFuncDegree+1, sizeof(int));
64
+ int intFuncDegree = RARRAY_LEN(funcCoeffs)-1;
65
+ int * intFuncCoeffs = calloc(intFuncDegree+1, sizeof(int));
66
66
 
67
- for(i=0; i<=intFuncDegree; i++){
68
- intFuncCoeffs[i] = NUM2INT(rb_ary_entry(funcCoeffs, i));
69
- }
67
+ for(i=0; i<=intFuncDegree; i++){
68
+ intFuncCoeffs[i] = NUM2INT(rb_ary_entry(funcCoeffs, i));
69
+ }
70
70
 
71
71
 
72
- intSolutions = solve_congruence(intFuncDegree, intFuncCoeffs, intMod);
73
- rbSolutions = rb_ary_new2(intSolutions[0]);
72
+ intSolutions = solve_congruence(intFuncDegree, intFuncCoeffs, intMod);
73
+ rbSolutions = rb_ary_new2(intSolutions[0]);
74
74
 
75
- for(i=0; i<intSolutions[0]; i++){
76
- rb_ary_store(rbSolutions, i, INT2NUM(intSolutions[i+1]));
77
- }
75
+ for(i=0; i<intSolutions[0]; i++){
76
+ rb_ary_store(rbSolutions, i, INT2NUM(intSolutions[i+1]));
77
+ }
78
78
 
79
79
 
80
- free(intFuncCoeffs);
81
- free(intSolutions);
80
+ free(intFuncCoeffs);
81
+ free(intSolutions);
82
82
 
83
- return rbSolutions;
83
+ return rbSolutions;
84
84
  }
85
85
 
@@ -3,197 +3,225 @@
3
3
  #include <stdlib.h>
4
4
  #include <stdio.h>
5
5
 
6
+ static int * adjust_coeffs_to_mod(int degree, int * coeffs, int mod);
6
7
  static int * solve_prime_power_congruence(int degree, int coeffs[], int prime, int power);
7
8
  static int * solve_system_of_order_1_congruence_sets(int numOfSets, int * lengthsOfSets, int ** sets, int mods[]);
8
9
 
9
10
  int chinese_remainder_solution(int numberOfEquations, int scals[], int mods[]){
10
- int i;
11
- int x = 0;
12
- int m = mods[0];
13
- int modCoeff;
11
+ int i;
12
+ int x = 0;
13
+ int m = mods[0];
14
+ int modCoeff;
14
15
 
15
- for(i=1; i<numberOfEquations; i++){
16
- m *= mods[i];
17
- }
16
+ for(i=1; i<numberOfEquations; i++){
17
+ m *= mods[i];
18
+ }
18
19
 
19
- for(i=0; i<numberOfEquations; i++){
20
- modCoeff = m/mods[i];
21
- x += modCoeff*mod_inv(modCoeff, mods[i])*scals[i];
22
- }
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
+ }
23
24
 
24
- return x % m;
25
+ return x % m;
25
26
  }
26
27
 
27
28
 
28
- int * brute_force_congruence(int degree, int coeffs[], int primeMod){
29
- //assumes a prime modulus. split congruences of composite modulus into systems of congrueneces
30
- //of prime modulus and/or apply the lifting theorem to make use of this function
31
- //solve a0x^n + a1x^n-1... = 0 (mod mod) where n is the order a0, a1, ... are coeffieicients
32
- int * solutionList = calloc(degree+1, sizeof(int));
33
- int * solutions = solutionList+1;
34
- int numberOfSolutions = 0;
35
- int x;
36
-
37
- for(x = 0; x < primeMod && numberOfSolutions <= degree; x++){
38
- if(mod_eval_polynomial(degree, coeffs, primeMod, x) == 0){
39
- solutions[numberOfSolutions++] = x;
40
- }
41
- }
42
-
43
- *solutionList = numberOfSolutions;
44
-
45
- return solutionList;
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;
46
41
  }
47
42
 
48
43
 
49
- static int * solve_prime_power_congruence(int funcDegree, int funcCoeffs[], int prime, int power){
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;
50
54
 
51
- int * baseSolutionList;
52
- int numOfBaseSolutions;
53
- int * baseSolutions;
54
55
 
55
- int * liftedSolutions;
56
- int numOfLiftedSolutions;
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
+ }
57
61
 
58
- int derivDegree;
59
- int * derivCoeffs;
60
- int deriv;
61
- long int divFunc;
62
+ *solutionList = numberOfSolutions;
62
63
 
63
- int j, t;
64
- int currentMod;
64
+ free(adjustedCoeffs);
65
65
 
66
- if(power == 1){
67
- return brute_force_congruence(funcDegree, funcCoeffs, prime);
68
- }
66
+ return solutionList;
67
+ }
69
68
 
70
- baseSolutionList = solve_prime_power_congruence(funcDegree, funcCoeffs, prime, power-1);
71
- numOfBaseSolutions = *baseSolutionList;
72
- baseSolutions = baseSolutionList+1;
73
69
 
74
- liftedSolutions = calloc(prime*numOfBaseSolutions+1, sizeof(int));
75
- numOfLiftedSolutions = 0;
70
+ static int * solve_prime_power_congruence(int funcDegree, int funcCoeffs[], int prime, int power){
76
71
 
77
- derivDegree = funcDegree-1;
78
- derivCoeffs = calloc(derivDegree+1, sizeof(int));
72
+ int * adjustedCoeffs;
79
73
 
80
- currentMod = prime;
81
- for(j = 1; j < power; j++){
82
- currentMod *= prime;
83
- }
74
+ int * baseSolutionList;
75
+ int numOfBaseSolutions;
76
+ int * baseSolutions;
84
77
 
85
- for(j = 0; j <= derivDegree; j++){
86
- derivCoeffs[j] = funcCoeffs[j+1]*(j+1);
87
- }
78
+ int * liftedSolutions;
79
+ int numOfLiftedSolutions;
88
80
 
81
+ int coeff;
89
82
 
90
- for(j = 0; j < numOfBaseSolutions; j++){
91
- deriv = mod_eval_polynomial(derivDegree, derivCoeffs, prime, baseSolutions[j]);
92
- divFunc = (eval_polynomial(funcDegree, funcCoeffs, baseSolutions[j]) / (currentMod/prime)) % prime;
83
+ int derivDegree;
84
+ int * derivCoeffs;
85
+ int deriv;
86
+ long int divFunc;
93
87
 
94
- if(deriv % prime != 0){
95
- t = (-divFunc*mod_inv(deriv, prime) % prime) + prime;
96
- liftedSolutions[++numOfLiftedSolutions] = baseSolutions[j] + t*prime;
97
- }
88
+ int i, j, t;
89
+ int currentMod;
98
90
 
99
- else if(divFunc % prime == 0){
100
- for(t = 1; t <= prime; t++){
101
- liftedSolutions[++numOfLiftedSolutions] = baseSolutions[j] + t*(currentMod/prime);
102
- }
103
- }
104
- }
91
+ if(power == 1){
92
+ baseSolutions = brute_force_congruence(funcDegree, funcCoeffs, prime);
93
+ return baseSolutions;
94
+ }
105
95
 
96
+ baseSolutionList = solve_prime_power_congruence(funcDegree, funcCoeffs, prime, power-1);
97
+ numOfBaseSolutions = *baseSolutionList;
98
+ baseSolutions = baseSolutionList+1;
106
99
 
107
- *liftedSolutions = numOfLiftedSolutions;
100
+ liftedSolutions = calloc(prime*numOfBaseSolutions+1, sizeof(int));
101
+ numOfLiftedSolutions = 0;
108
102
 
109
- free(derivCoeffs);
110
- free(baseSolutionList);
103
+ derivDegree = funcDegree-1;
104
+ derivCoeffs = calloc(derivDegree+1, sizeof(int));
111
105
 
112
- return liftedSolutions;
113
- }
106
+ currentMod = prime;
107
+ for(j = 1; j < power; j++){
108
+ currentMod *= prime;
109
+ }
114
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
+ }
115
118
 
116
- static int * solve_system_of_order_1_congruence_sets(int numOfSets, int * setLengths, int * * sets, int * mods){
117
- //allocate perumtation array
118
- int * divAry = calloc(numOfSets, sizeof(int));
119
- int * scalAry = calloc(numOfSets, sizeof(int));
120
- int i, j;
121
- int numOfSolutions;
122
- int * solutionAry;
123
- int * dest;
124
- int idx;
125
-
126
- for(i = 0, numOfSolutions = 1; i < numOfSets; i++){
127
- divAry[i] = numOfSolutions;
128
- numOfSolutions *= setLengths[i];
129
- }
130
-
131
- solutionAry = calloc(numOfSolutions+1, sizeof(int));
132
- solutionAry[0] = numOfSolutions;
133
- dest = solutionAry+1;
134
-
135
- for(i = 0; i < numOfSolutions; i++){
136
- for(j = 0; j < numOfSets; j++){
137
- idx = (i / divAry[j]) % setLengths[j];
138
- scalAry[j] = sets[j][idx];
139
- }
140
-
141
- *(dest++) = chinese_remainder_solution(numOfSets, scalAry, mods);
142
- }
143
-
144
- return solutionAry;
145
- }
146
119
 
147
- int * solve_congruence(int funcDegree, int funcCoeffs[], int mod){
148
- int * solutionList;
120
+ for(j = 0; j < numOfBaseSolutions; j++){
149
121
 
150
- int * modFactorList = prime_factors(mod);
151
- int numOfModFactors = *modFactorList;
152
- int * modFactors = modFactorList+1;
122
+ deriv = mod_eval_polynomial(derivDegree, derivCoeffs, prime, baseSolutions[j]);
123
+ divFunc = (eval_polynomial(funcDegree, funcCoeffs, baseSolutions[j]) / (currentMod/prime)) % prime;
153
124
 
154
- int * * primePowerSolutions = calloc(numOfModFactors, sizeof(int *));
155
- int * primePowers = calloc(numOfModFactors, sizeof(int));
156
- int * primePowerSolutionLengths = calloc(numOfModFactors, sizeof(int *));
125
+ if(deriv % prime != 0){
126
+ t = (-divFunc*mod_inv(deriv, prime) % prime) + prime;
127
+ liftedSolutions[++numOfLiftedSolutions] = baseSolutions[j] + t*prime;
128
+ }
157
129
 
158
- int power;
159
- int i;
130
+ else if(divFunc % prime == 0){
131
+ for(t = 1; t <= prime; t++){
132
+ liftedSolutions[++numOfLiftedSolutions] = baseSolutions[j] + t*(currentMod/prime);
133
+ }
134
+ }
135
+ }
160
136
 
161
- for(i = 0; i < numOfModFactors; i++){
162
- primePowers[i] = modFactors[i];
163
- power = 1;
164
-
165
- while(mod % (primePowers[i]*modFactors[i]) == 0){
166
- primePowers[i] *= modFactors[i];
167
- power++;
168
- }
169
137
 
170
- primePowerSolutions[i] = solve_prime_power_congruence(funcDegree, funcCoeffs, modFactors[i], power);
171
- primePowerSolutionLengths[i] = *(primePowerSolutions[i]++);
172
- }
138
+ *liftedSolutions = numOfLiftedSolutions;
173
139
 
140
+ free(derivCoeffs);
141
+ free(baseSolutionList);
174
142
 
175
- solutionList = solve_system_of_order_1_congruence_sets(numOfModFactors, primePowerSolutionLengths, primePowerSolutions, primePowers);
143
+ return liftedSolutions;
144
+ }
176
145
 
177
- for(i = 0; i < numOfModFactors; i++){
178
- free(primePowerSolutions[i] - 1);
179
- }
180
- free(primePowerSolutionLengths);
181
- free(primePowerSolutions);
182
- free(primePowers);
183
- free(modFactorList);
184
146
 
185
- return solutionList;
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;
186
216
  }
187
217
 
188
218
  /*
189
219
  int * solve_system_of_congruences(int numOfFuncs, int * funcDegrees, int ** funcCoeffs, int * mods){
190
- int i;
191
- int * * funcSolutionSets = calloc(numOfFuncs, sizeof(int *));
192
-
193
- for(i=0; i<numOfFuncs; i++){
194
- funcSolutionSets[i] = solve_congruence(funcDegrees[i], funcCoeffs[i], mods[i]);
195
- }
196
-
197
- return solve_system_of_congruence_sets(numOfFuncs, funcSolutionSets, mods);
198
- }
199
- */
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
+ */
@@ -13,17 +13,4 @@ EXT_C = %w[
13
13
  prime_gen.c
14
14
  ]
15
15
 
16
-
17
- EXT_H.each do |fname|
18
- unless File::exist? fname
19
- raise "Ext header #{fname} does not exist in #{Dir::pwd}"
20
- end
21
- end
22
-
23
- EXT_C.each do |fname|
24
- unless File::exist? fname
25
- raise "Ext file #{fname} does not exist in #{Dir::pwd}"
26
- end
27
- end
28
-
29
16
  create_makefile "congruence_solver/congruence_solver"