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,146 +1,146 @@
|
|
1
|
-
#include "prime_gen.h"
|
2
|
-
#include <stdlib.h>
|
3
|
-
#include <string.h>
|
4
|
-
#include <stdio.h>
|
5
|
-
#include <math.h>
|
6
|
-
|
7
|
-
#define FIRST_PRIME 2
|
8
|
-
|
9
|
-
static void expand_prime_list_to_length(int length);
|
10
|
-
static void expand_prime_list_past(int max);
|
11
|
-
static int any_divisors(int * div_list, int length, int num);
|
12
|
-
static int least_divisor(int n);
|
13
|
-
|
14
|
-
static int * PRIME_LIST = NULL;
|
15
|
-
static int PRIME_LIST_LENGTH = 0;
|
16
|
-
static int PRIME_LIST_MAX_LENGTH = 0;
|
17
|
-
static int NEXT_INTEGER = FIRST_PRIME;
|
18
|
-
|
19
|
-
|
20
|
-
int * primes(int length){
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
}
|
31
|
-
|
32
|
-
|
33
|
-
int * primes_upto(int max){
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
}
|
50
|
-
|
51
|
-
|
52
|
-
int * prime_factors(int n){
|
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
|
-
static int least_divisor(int n){
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
}
|
93
|
-
|
94
|
-
|
95
|
-
static void expand_prime_list_to_length(int length){
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
}
|
111
|
-
|
112
|
-
|
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
|
-
|
134
|
-
}
|
135
|
-
|
136
|
-
|
137
|
-
static int any_divisors(int * div_list, int length, int num){
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
}
|
1
|
+
#include "prime_gen.h"
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include <string.h>
|
4
|
+
#include <stdio.h>
|
5
|
+
#include <math.h>
|
6
|
+
|
7
|
+
#define FIRST_PRIME 2
|
8
|
+
|
9
|
+
static void expand_prime_list_to_length(int length);
|
10
|
+
static void expand_prime_list_past(int max);
|
11
|
+
static int any_divisors(int * div_list, int length, int num);
|
12
|
+
static int least_divisor(int n);
|
13
|
+
|
14
|
+
static int * PRIME_LIST = NULL;
|
15
|
+
static int PRIME_LIST_LENGTH = 0;
|
16
|
+
static int PRIME_LIST_MAX_LENGTH = 0;
|
17
|
+
static int NEXT_INTEGER = FIRST_PRIME;
|
18
|
+
|
19
|
+
|
20
|
+
int * primes(int length){
|
21
|
+
int * rtrn_list = calloc(length, sizeof(int));
|
22
|
+
|
23
|
+
expand_prime_list_to_length(length);
|
24
|
+
|
25
|
+
if(rtrn_list != NULL){
|
26
|
+
memcpy(rtrn_list, PRIME_LIST, length*sizeof(int));
|
27
|
+
}
|
28
|
+
|
29
|
+
return rtrn_list;
|
30
|
+
}
|
31
|
+
|
32
|
+
|
33
|
+
int * primes_upto(int max){
|
34
|
+
int * rtrn_list;
|
35
|
+
int i;
|
36
|
+
|
37
|
+
expand_prime_list_past(max);
|
38
|
+
|
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
|
+
|
48
|
+
return NULL;
|
49
|
+
}
|
50
|
+
|
51
|
+
|
52
|
+
int * prime_factors(int n){
|
53
|
+
int * rtrn_list = malloc(sizeof(int));
|
54
|
+
int rtrn_list_length = 0;
|
55
|
+
int least_div;
|
56
|
+
|
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
|
+
|
62
|
+
if(least_div == n){
|
63
|
+
break;
|
64
|
+
}
|
65
|
+
|
66
|
+
while(n % least_div == 0){
|
67
|
+
n /= least_div;
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
rtrn_list[0] = rtrn_list_length;
|
72
|
+
|
73
|
+
return rtrn_list;
|
74
|
+
}
|
75
|
+
|
76
|
+
|
77
|
+
static int least_divisor(int n){
|
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
|
+
|
84
|
+
|
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
|
+
|
91
|
+
return n;
|
92
|
+
}
|
93
|
+
|
94
|
+
|
95
|
+
static void expand_prime_list_to_length(int length){
|
96
|
+
|
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
|
+
|
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
|
+
|
107
|
+
NEXT_INTEGER++;
|
108
|
+
}
|
109
|
+
|
110
|
+
}
|
111
|
+
|
112
|
+
|
113
|
+
static void expand_prime_list_past(int max){
|
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
|
+
}
|
135
|
+
|
136
|
+
|
137
|
+
static int any_divisors(int * div_list, int length, int num){
|
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
|
+
}
|
@@ -1,10 +1,10 @@
|
|
1
|
-
#ifndef H_PRIME_GEN
|
2
|
-
#define H_PRIME_GEN
|
3
|
-
int * primes(int n);
|
4
|
-
|
5
|
-
//Generation of primes is currently time-prohibitive when generating up to large maximums.
|
6
|
-
//This should be acceptable for prime factorization because although naive the algorithm is
|
7
|
-
//somewhat optimized to detect relatively large prime factors.
|
8
|
-
int * primes_upto(int max);
|
9
|
-
int * prime_factors(int n);
|
1
|
+
#ifndef H_PRIME_GEN
|
2
|
+
#define H_PRIME_GEN
|
3
|
+
int * primes(int n);
|
4
|
+
|
5
|
+
//Generation of primes is currently time-prohibitive when generating up to large maximums.
|
6
|
+
//This should be acceptable for prime factorization because although naive the algorithm is
|
7
|
+
//somewhat optimized to detect relatively large prime factors.
|
8
|
+
int * primes_upto(int max);
|
9
|
+
int * prime_factors(int n);
|
10
10
|
#endif
|
@@ -1,116 +1,113 @@
|
|
1
|
-
class PolynomialInterpreter
|
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
|
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
|
-
end
|
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
|
-
coeffs[exp]
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
coeffs
|
115
|
-
end
|
116
|
-
end
|
1
|
+
class PolynomialInterpreter
|
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
|
25
|
+
raise Errors::LHS_POLYNOMIAL_INVALID
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
rh_coeffs = read_coeffs(rhs.gsub(" ", ""))
|
30
|
+
rescue ArgumentError
|
31
|
+
raise Errors::RHS_POLYNOMIAL_INVALID
|
32
|
+
end
|
33
|
+
|
34
|
+
if mod !~ /\d+/ or mod.to_i < 2
|
35
|
+
raise Errors::MOD_INVALID
|
36
|
+
end
|
37
|
+
|
38
|
+
0.upto rh_coeffs.length-1 do |idx|
|
39
|
+
unless rh_coeffs[idx].nil?
|
40
|
+
lh_coeffs[idx] ||= 0
|
41
|
+
lh_coeffs[idx] -= rh_coeffs[idx]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
[lh_coeffs, mod.to_i]
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.read_coeffs(input_polynomial)
|
49
|
+
if input_polynomial == ""
|
50
|
+
raise Errors::POLYNOMIAL_INVALID
|
51
|
+
end
|
52
|
+
|
53
|
+
last_var = nil
|
54
|
+
coeffs = Array.new
|
55
|
+
|
56
|
+
unless input_polynomial[0].match /[-+]/
|
57
|
+
input_polynomial = "+" + input_polynomial
|
58
|
+
end
|
59
|
+
|
60
|
+
while input_polynomial.length > 0 do
|
61
|
+
op = input_polynomial.slice!(0)
|
62
|
+
unless op =~ /[-+]/
|
63
|
+
raise Errors::POLYNOMIAL_INVALID
|
64
|
+
end
|
65
|
+
|
66
|
+
input_polynomial.slice!(/^(\d+)\*?/)
|
67
|
+
match_data_coe = Regexp.last_match
|
68
|
+
|
69
|
+
input_polynomial.slice!(/^([a-zA-Z])(?:\^(\d+))?/)
|
70
|
+
match_data_exp = Regexp.last_match
|
71
|
+
|
72
|
+
if match_data_coe.nil? and match_data_exp.nil?
|
73
|
+
raise Errors::POLYNOMIAL_INVALID
|
74
|
+
else
|
75
|
+
if match_data_exp.nil?
|
76
|
+
coe = match_data_coe[1].to_i
|
77
|
+
exp = 0
|
78
|
+
else
|
79
|
+
unless last_var.nil? or last_var == match_data_exp[1]
|
80
|
+
raise Errors::POLYNOMIAL_INVALID
|
81
|
+
end
|
82
|
+
|
83
|
+
last_var = match_data_exp[1]
|
84
|
+
|
85
|
+
if match_data_coe.nil?
|
86
|
+
coe = 1
|
87
|
+
else
|
88
|
+
coe = match_data_coe[1].to_i
|
89
|
+
end
|
90
|
+
|
91
|
+
if match_data_exp[2].nil?
|
92
|
+
exp = 1
|
93
|
+
else
|
94
|
+
exp = match_data_exp[2].to_i
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
coeffs[exp] ||= 0
|
100
|
+
if op == "-"
|
101
|
+
coeffs[exp] -= coe.to_i
|
102
|
+
else
|
103
|
+
coeffs[exp] += coe.to_i
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
0.upto(coeffs.length-1) do |idx|
|
108
|
+
coeffs[idx] ||= 0
|
109
|
+
end
|
110
|
+
|
111
|
+
coeffs
|
112
|
+
end
|
113
|
+
end
|