congruence_solver 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -2
- data/.gitmodules +3 -2
- data/Gemfile +4 -0
- data/README.md +17 -10
- data/Rakefile +59 -25
- data/bench/bench_tools.rb +26 -26
- data/bench/solve_congruence_bm.rb +35 -35
- data/bin/csolve.rb +21 -21
- data/congruence_solver.gemspec +6 -6
- data/ext/congruence_solver/arith_utils.c +72 -75
- data/ext/congruence_solver/congruence_solver.c +43 -43
- data/ext/congruence_solver/congruences.c +175 -147
- data/ext/congruence_solver/extconf.rb +0 -13
- data/ext/congruence_solver/prime_gen.c +83 -83
- data/ext/congruence_solver/test/arith_utils_test.h +7 -7
- data/ext/congruence_solver/test/congruences_test.c +2 -2
- data/ext/congruence_solver/test/congruences_test.h +36 -1
- data/lib/congruence_solver/version.rb +1 -1
- data/lib/polynomial_interpreter.rb +114 -114
- data/spec/congruence_solver_spec.rb +34 -34
- data/spec/csolve_spec.rb +74 -74
- metadata +18 -3
@@ -18,129 +18,129 @@ static int NEXT_INTEGER = FIRST_PRIME;
|
|
18
18
|
|
19
19
|
|
20
20
|
int * primes(int length){
|
21
|
-
|
21
|
+
int * rtrn_list = calloc(length, sizeof(int));
|
22
22
|
|
23
|
-
|
23
|
+
expand_prime_list_to_length(length);
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
if(rtrn_list != NULL){
|
26
|
+
memcpy(rtrn_list, PRIME_LIST, length*sizeof(int));
|
27
|
+
}
|
28
28
|
|
29
|
-
|
29
|
+
return rtrn_list;
|
30
30
|
}
|
31
31
|
|
32
32
|
|
33
33
|
int * primes_upto(int max){
|
34
|
-
|
35
|
-
|
34
|
+
int * rtrn_list;
|
35
|
+
int i;
|
36
36
|
|
37
|
-
|
37
|
+
expand_prime_list_past(max);
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
for(i = PRIME_LIST_LENGTH; i > 0; i--){
|
40
|
+
if(PRIME_LIST[i-1] <= max){
|
41
|
+
rtrn_list = calloc(i+1, sizeof(int));
|
42
|
+
rtrn_list[0] = i;
|
43
|
+
memcpy(rtrn_list+1, PRIME_LIST, i*sizeof(int));
|
44
|
+
return rtrn_list;
|
45
|
+
}
|
46
|
+
}
|
47
47
|
|
48
|
-
|
48
|
+
return NULL;
|
49
49
|
}
|
50
50
|
|
51
51
|
|
52
52
|
int * prime_factors(int n){
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
int * rtrn_list = malloc(sizeof(int));
|
54
|
+
int rtrn_list_length = 0;
|
55
|
+
int least_div;
|
56
56
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
57
|
+
while(n != 1){
|
58
|
+
least_div = least_divisor(n);
|
59
|
+
rtrn_list = realloc(rtrn_list, (rtrn_list_length+2)*sizeof(int));
|
60
|
+
rtrn_list[++rtrn_list_length] = least_div;
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
|
62
|
+
if(least_div == n){
|
63
|
+
break;
|
64
|
+
}
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
while(n % least_div == 0){
|
67
|
+
n /= least_div;
|
68
|
+
}
|
69
|
+
}
|
70
70
|
|
71
|
-
|
71
|
+
rtrn_list[0] = rtrn_list_length;
|
72
72
|
|
73
|
-
|
73
|
+
return rtrn_list;
|
74
74
|
}
|
75
75
|
|
76
76
|
|
77
77
|
static int least_divisor(int n){
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
78
|
+
//Calculate maximum for least divisor (sqrt)
|
79
|
+
int least_div_max = sqrt(n) + 1;
|
80
|
+
int i;
|
81
|
+
//Expand prime list up to the least divisor
|
82
|
+
expand_prime_list_past(least_div_max);
|
83
83
|
|
84
84
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
85
|
+
for(i = 0; PRIME_LIST[i] < least_div_max; i++){
|
86
|
+
if(n % PRIME_LIST[i] == 0){
|
87
|
+
return PRIME_LIST[i];
|
88
|
+
}
|
89
|
+
}
|
90
90
|
|
91
|
-
|
91
|
+
return n;
|
92
92
|
}
|
93
93
|
|
94
94
|
|
95
95
|
static void expand_prime_list_to_length(int length){
|
96
96
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
97
|
+
if(PRIME_LIST_MAX_LENGTH < length){
|
98
|
+
PRIME_LIST_MAX_LENGTH = 2*length;
|
99
|
+
PRIME_LIST = realloc(PRIME_LIST, PRIME_LIST_MAX_LENGTH*sizeof(int));
|
100
|
+
}
|
101
101
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
102
|
+
while(PRIME_LIST_LENGTH < length){
|
103
|
+
if( !any_divisors(PRIME_LIST, PRIME_LIST_LENGTH, NEXT_INTEGER) ){
|
104
|
+
PRIME_LIST[PRIME_LIST_LENGTH++] = NEXT_INTEGER;
|
105
|
+
}
|
106
106
|
|
107
|
-
|
108
|
-
|
107
|
+
NEXT_INTEGER++;
|
108
|
+
}
|
109
109
|
|
110
110
|
}
|
111
111
|
|
112
112
|
|
113
113
|
static void expand_prime_list_past(int max){
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
114
|
+
if(PRIME_LIST == NULL){
|
115
|
+
//TODO: find better heuristic limit on memory necessary to allocate
|
116
|
+
PRIME_LIST_MAX_LENGTH = (max/2) + 1;
|
117
|
+
PRIME_LIST = calloc(PRIME_LIST_MAX_LENGTH, sizeof(int));
|
118
|
+
PRIME_LIST[0] = NEXT_INTEGER++;
|
119
|
+
PRIME_LIST_LENGTH = 1;
|
120
|
+
}
|
121
|
+
|
122
|
+
while(PRIME_LIST[PRIME_LIST_LENGTH-1] <= max){
|
123
|
+
while(any_divisors(PRIME_LIST, PRIME_LIST_LENGTH, NEXT_INTEGER) ){
|
124
|
+
NEXT_INTEGER++;
|
125
|
+
}
|
126
|
+
|
127
|
+
if( PRIME_LIST_MAX_LENGTH <= PRIME_LIST_LENGTH){
|
128
|
+
PRIME_LIST_MAX_LENGTH *= 2;
|
129
|
+
PRIME_LIST = realloc(PRIME_LIST, PRIME_LIST_MAX_LENGTH*sizeof(int));
|
130
|
+
}
|
131
|
+
|
132
|
+
PRIME_LIST[PRIME_LIST_LENGTH++] = NEXT_INTEGER;
|
133
|
+
}
|
134
134
|
}
|
135
135
|
|
136
136
|
|
137
137
|
static int any_divisors(int * div_list, int length, int num){
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
138
|
+
int i;
|
139
|
+
for(i = 0; i < length; i++){
|
140
|
+
if(num % div_list[i] == 0){
|
141
|
+
return 1;
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
return 0;
|
146
146
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#define NUM_OF_MOD_INV_TESTS 4
|
2
|
-
#define NUM_OF_MOD_PRODUCT_TESTS
|
2
|
+
#define NUM_OF_MOD_PRODUCT_TESTS 3
|
3
3
|
#define NUM_OF_MOD_POWER_TESTS 4
|
4
4
|
#define NUM_OF_COPRIME_TESTS 5
|
5
5
|
#define NUM_OF_TOTIENT_TESTS 6
|
@@ -11,15 +11,15 @@ int TOTIENT_EVALS[NUM_OF_TOTIENT_TESTS] = {1, 1, 2, 40, 100, 3680};
|
|
11
11
|
int COPRIME_NUM_PAIRS[NUM_OF_COPRIME_TESTS][2] = {{3,5}, {9, 28}, {100, 34}, {1000512415, 557825}, {2286144, 1515839}};
|
12
12
|
int COPRIME_EVALS[NUM_OF_COPRIME_TESTS] = {1, 1, 0, 0, 1};
|
13
13
|
|
14
|
-
int MOD_PRODUCT_NUM_PAIRS[NUM_OF_MOD_PRODUCT_TESTS][2] = {{5,6}, {41,3}, {16,
|
15
|
-
int MOD_PRODUCT_MODS[NUM_OF_MOD_PRODUCT_TESTS] = {10, 8, 19
|
16
|
-
int MOD_PRODUCT_PRODUCTS[NUM_OF_MOD_PRODUCT_TESTS] = {0, 3, 10
|
14
|
+
int MOD_PRODUCT_NUM_PAIRS[NUM_OF_MOD_PRODUCT_TESTS][2] = {{5,6}, {41,3}, {16, 3}};
|
15
|
+
int MOD_PRODUCT_MODS[NUM_OF_MOD_PRODUCT_TESTS] = {10, 8, 19};
|
16
|
+
int MOD_PRODUCT_PRODUCTS[NUM_OF_MOD_PRODUCT_TESTS] = {0, 3, 10};
|
17
17
|
|
18
|
-
int MOD_INV_NUMS[NUM_OF_MOD_INV_TESTS] = {5, 4, 53,
|
18
|
+
int MOD_INV_NUMS[NUM_OF_MOD_INV_TESTS] = {5, 4, 53, 3};
|
19
19
|
int MOD_INV_MODS[NUM_OF_MOD_INV_TESTS] = {12, 23, 105, 7};
|
20
20
|
int MOD_INV_INVS[NUM_OF_MOD_INV_TESTS] = {5, 6, 2, 5};
|
21
21
|
|
22
|
-
int MOD_POWER_NUMS[NUM_OF_MOD_POWER_TESTS] = {
|
22
|
+
int MOD_POWER_NUMS[NUM_OF_MOD_POWER_TESTS] = {3, 19, 6, 7};
|
23
23
|
int MOD_POWER_MODS[NUM_OF_MOD_POWER_TESTS] = {4, 23, 7, 33};
|
24
24
|
int MOD_POWER_POWERS[NUM_OF_MOD_POWER_TESTS] = {10, 3, 4, 635};
|
25
|
-
int MOD_POWER_EVALS[NUM_OF_MOD_POWER_TESTS] ={1, 5, 1,
|
25
|
+
int MOD_POWER_EVALS[NUM_OF_MOD_POWER_TESTS] ={1, 5, 1, 10};
|
@@ -13,7 +13,7 @@ int main(){
|
|
13
13
|
failures += solve_congruence_test(POL_3_DEGREE, POL_3_COEFFS, POL_3_MOD, NUM_OF_POL_3_SOLS, POL_3_SOLS);
|
14
14
|
failures += solve_congruence_test(POL_4_DEGREE, POL_4_COEFFS, POL_4_MOD, NUM_OF_POL_4_SOLS, POL_4_SOLS);
|
15
15
|
failures += solve_congruence_test(POL_5_DEGREE, POL_5_COEFFS, POL_5_MOD, NUM_OF_POL_5_SOLS, POL_5_SOLS);
|
16
|
-
|
16
|
+
failures += solve_congruence_test(POL_6_DEGREE, POL_6_COEFFS, POL_6_MOD, NUM_OF_POL_6_SOLS, POL_6_SOLS);
|
17
17
|
|
18
18
|
return failures;
|
19
19
|
}
|
@@ -54,7 +54,7 @@ int solve_congruence_test(int func_degree, int * func_coeffs, int mod, int num_o
|
|
54
54
|
|
55
55
|
print_polynomial_inline(func_degree, func_coeffs);
|
56
56
|
|
57
|
-
printf(" = 0: %d given instead of %d.\n\n", solutions_to_test[i+1], solutions[i]);
|
57
|
+
printf(" = 0 (mod %d): %d given instead of %d.\n\n", mod, solutions_to_test[i+1], solutions[i]);
|
58
58
|
|
59
59
|
return 1;
|
60
60
|
}
|
@@ -105,6 +105,24 @@
|
|
105
105
|
#define POL_5_SOL_7 299584
|
106
106
|
#define POL_5_SOL_8 313399
|
107
107
|
|
108
|
+
#define POL_6_DEGREE 5
|
109
|
+
#define POL_6_COEFF_0 1
|
110
|
+
#define POL_6_COEFF_1 2
|
111
|
+
#define POL_6_COEFF_2 1
|
112
|
+
#define POL_6_COEFF_3 -1
|
113
|
+
#define POL_6_COEFF_4 0
|
114
|
+
#define POL_6_COEFF_5 -3
|
115
|
+
#define POL_6_MOD 49
|
116
|
+
#define NUM_OF_POL_6_SOLS 8
|
117
|
+
#define POL_6_SOL_0 1
|
118
|
+
#define POL_6_SOL_1 8
|
119
|
+
#define POL_6_SOL_2 15
|
120
|
+
#define POL_6_SOL_3 22
|
121
|
+
#define POL_6_SOL_4 26
|
122
|
+
#define POL_6_SOL_5 29
|
123
|
+
#define POL_6_SOL_6 36
|
124
|
+
#define POL_6_SOL_7 43
|
125
|
+
|
108
126
|
|
109
127
|
int POL_1_COEFFS[POL_1_DEGREE+1] = {POL_1_COEFF_0,
|
110
128
|
POL_1_COEFF_1,
|
@@ -201,4 +219,21 @@ int POL_5_SOLS[NUM_OF_POL_5_SOLS] = {POL_5_SOL_0,
|
|
201
219
|
POL_5_SOL_5,
|
202
220
|
POL_5_SOL_6,
|
203
221
|
POL_5_SOL_7,
|
204
|
-
POL_5_SOL_8};
|
222
|
+
POL_5_SOL_8};
|
223
|
+
|
224
|
+
int POL_6_COEFFS[POL_6_DEGREE+1] = {POL_6_COEFF_0,
|
225
|
+
POL_6_COEFF_1,
|
226
|
+
POL_6_COEFF_2,
|
227
|
+
POL_6_COEFF_3,
|
228
|
+
POL_6_COEFF_4,
|
229
|
+
POL_6_COEFF_5
|
230
|
+
};
|
231
|
+
|
232
|
+
int POL_6_SOLS[NUM_OF_POL_6_SOLS] = {POL_6_SOL_0,
|
233
|
+
POL_6_SOL_1,
|
234
|
+
POL_6_SOL_2,
|
235
|
+
POL_6_SOL_3,
|
236
|
+
POL_6_SOL_4,
|
237
|
+
POL_6_SOL_5,
|
238
|
+
POL_6_SOL_6,
|
239
|
+
POL_6_SOL_7};
|
@@ -1,116 +1,116 @@
|
|
1
1
|
class PolynomialInterpreter
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
2
|
+
module Errors
|
3
|
+
POLYNOMIAL_INVALID = ArgumentError.new "polynomial invalid"
|
4
|
+
CONGRUENCE_INVALID = ArgumentError.new "congruence invalid"
|
5
|
+
LHS_POLYNOMIAL_INVALID = ArgumentError.new "lhs polynomial invalid"
|
6
|
+
RHS_POLYNOMIAL_INVALID = ArgumentError.new "rhs polynomial invalid"
|
7
|
+
MOD_INVALID = ArgumentError.new "mod invalid"
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def self.read_congruence(input_congruence)
|
12
|
+
match_data = input_congruence.match(/^(.*)=(.*) +(?:mod +(.*)|\(mod +(.*)\))$/)
|
13
|
+
|
14
|
+
if match_data.nil?
|
15
|
+
raise Errors::CONGRUENCE_INVALID
|
16
|
+
end
|
17
|
+
|
18
|
+
lhs = match_data[1]
|
19
|
+
rhs = match_data[2]
|
20
|
+
mod = match_data[3] || match_data[4]
|
21
|
+
|
22
|
+
begin
|
23
|
+
lh_coeffs = read_coeffs(lhs.gsub(" ", ""))
|
24
|
+
rescue ArgumentError => e
|
25
|
+
if(e == Errors::POLYNOMIAL_INVALID)
|
26
|
+
raise "#{lhs}:#{Errors::RHS_POLYNOMIAL_INVALID}"
|
27
|
+
else
|
28
|
+
raise e
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
begin
|
33
|
+
rh_coeffs = read_coeffs(rhs.gsub(" ", ""))
|
34
|
+
rescue ArgumentError => e
|
35
|
+
if e == Errors::POLYNOMIAL_INVALID
|
36
|
+
raise "#{rhs}:#{Errors::RHS_POLYNOMIAL_INVALID}"
|
37
|
+
else
|
38
|
+
raise e
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
if mod !~ /\d+/ or mod.to_i < 2
|
43
|
+
raise Errors::MOD_INVALID
|
44
|
+
end
|
45
|
+
|
46
|
+
0.upto rh_coeffs.length-1 do |idx|
|
47
|
+
unless rh_coeffs[idx].nil?
|
48
|
+
lh_coeffs[idx] ||= 0
|
49
|
+
lh_coeffs[idx] -= rh_coeffs[idx]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
[lh_coeffs, mod.to_i]
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.read_coeffs(input_polynomial)
|
57
|
+
if input_polynomial == ""
|
58
|
+
raise Errors::POLYNOMIAL_INVALID
|
59
|
+
end
|
60
|
+
|
61
|
+
last_var = nil
|
62
|
+
coeffs = Array.new
|
63
|
+
|
64
|
+
loop do
|
65
|
+
input_polynomial.slice!(/^(\d+)\*?/)
|
66
|
+
match_data_coe = Regexp.last_match
|
67
|
+
|
68
|
+
input_polynomial.slice!(/^([a-zA-Z])(?:\^(\d+))?/)
|
69
|
+
match_data_exp = Regexp.last_match
|
70
|
+
|
71
|
+
if match_data_coe.nil? and match_data_exp.nil?
|
72
|
+
raise Errors::POLYNOMIAL_INVALID
|
73
|
+
else
|
74
|
+
if match_data_exp.nil?
|
75
|
+
coe = match_data_coe[1].to_i
|
76
|
+
exp = 0
|
77
|
+
else
|
78
|
+
unless last_var.nil? or last_var == match_data_exp[1]
|
79
|
+
raise Errors::POLYNOMIAL_INVALID
|
80
|
+
end
|
81
|
+
|
82
|
+
last_var = match_data_exp[1]
|
83
|
+
|
84
|
+
if match_data_coe.nil?
|
85
|
+
coe = 1
|
86
|
+
else
|
87
|
+
coe = match_data_coe[1].to_i
|
88
|
+
end
|
89
|
+
|
90
|
+
if match_data_exp[2].nil?
|
91
|
+
exp = 1
|
92
|
+
else
|
93
|
+
exp = match_data_exp[2].to_i
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
coeffs[exp] ||= 0
|
99
|
+
coeffs[exp] += coe.to_i
|
100
|
+
|
101
|
+
break if input_polynomial.length == 0
|
102
|
+
|
103
|
+
op = input_polynomial.slice!(0)
|
104
|
+
|
105
|
+
unless op.match /[-+]/
|
106
|
+
raise Errors::POLYNOMIAL_INVALID
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
0.upto(coeffs.length-1) do |idx|
|
111
|
+
coeffs[idx] ||= 0
|
112
|
+
end
|
113
|
+
|
114
|
+
coeffs
|
115
|
+
end
|
116
116
|
end
|
@@ -1,38 +1,38 @@
|
|
1
1
|
require "congruence_solver"
|
2
2
|
|
3
3
|
RSpec.describe CongruenceSolver do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
4
|
+
describe "::lift" do
|
5
|
+
it "expects 3 arguments" do
|
6
|
+
expect {CongruenceSolver.lift()}.to raise_error ArgumentError
|
7
|
+
expect {CongruenceSolver.lift(0)}.to raise_error ArgumentError
|
8
|
+
expect {CongruenceSolver.lift([1,2], 3)}.not_to raise_error
|
9
|
+
expect {CongruenceSolver.lift([1], [1], nil)}.to raise_error ArgumentError
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
it "solves individual polynomial congruences defined by their coefficients and mod" do
|
14
|
+
coeffs = [-1, 0, 4]
|
15
|
+
mod = 5
|
16
|
+
expect(CongruenceSolver.lift(coeffs, mod).sort).to eq [2, 3]
|
17
|
+
|
18
|
+
coeffs = [-3, 4, 9]
|
19
|
+
mod = 49
|
20
|
+
expect(CongruenceSolver.lift(coeffs, mod).sort).to eq []
|
21
|
+
|
22
|
+
coeffs = [1, -4, 4]
|
23
|
+
mod = 5104
|
24
|
+
expect(CongruenceSolver.lift(coeffs, mod).sort).to eq []
|
25
|
+
|
26
|
+
coeffs = [4, -4, 1]
|
27
|
+
mod = 5104
|
28
|
+
expect(CongruenceSolver.lift(coeffs, mod).sort).to eq [2, 1278, 2554, 3830]
|
29
|
+
|
30
|
+
coeffs = Array.new(500, 0)
|
31
|
+
coeffs[0] = -1
|
32
|
+
coeffs[500] = 1
|
33
|
+
mod = 15
|
34
|
+
expect(CongruenceSolver.lift(coeffs, mod).sort).to eq [1, 2, 4, 7, 8, 11, 13, 14]
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
38
|
end
|