congruence_solver 0.3.1 → 0.3.2
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.
- 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
|