congruence_solver 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a5434d225bea224333675e4eba2a96f3642fa326
4
- data.tar.gz: 14f70c00d5674fc1e260add8e9b5787463c29550
3
+ metadata.gz: 3add01a35c88d8001cd82b2548555e8823686167
4
+ data.tar.gz: e703f137d82640832dade1cddc55e327578eda3c
5
5
  SHA512:
6
- metadata.gz: 4c3bf873aa8549385ded3cd7e9504cd36d4613b0645db636c4cda567af541dffdcfa33df756ef86a68723890fe05f0a2ea93fcdd5b5074e4d6289b9da92bb87b
7
- data.tar.gz: bba1bc6e5ea41eb4220511d746e04cd995d094c086cd2594d10b82b399f0e8f1a6cc2a30a14d9efff6a27935e4ed173d45ffb9642bf3c031ba0c5fc524a2c61d
6
+ metadata.gz: d8e31f46ac56d4e4f3303363947078e53f307060c4c31359ac95e7c7b80c951db44cf2b4f81acf734a1beaad371f87d4009fe61bcc8ca196d60058349ded7f80
7
+ data.tar.gz: 07cdad5666f6fb71decfb1bdb304a9fd16cb7b9fe9d0c4ee211959927d98e04f2d41f837fdb7c6c641805a781197a1448f6f6ba00176411bb80d2ebbe4dfb858
data/README.md CHANGED
@@ -4,7 +4,7 @@ CongruenceSolver is a gem for solving polynomial congruences. Should you ever ne
4
4
 
5
5
  ## Polynomial Congruences
6
6
 
7
- Polynomial congruences are the central topic of most elementary number theory and abstract algebra curricula. Similar to an equation, a [congruence](https://en.wikipedia.org/wiki/Modular_equation) is an [equivalence relation](https://en.wikipedia.org/wiki/Equivalence_relation) arising from [modular arithmetic](https://en.wikipedia.org/wiki/Modular_arithmetic) (also knowsn as "clock arithmetic"). For example, the idea "5 hours past 8 is 1" is expressed in the congruence ```8 + 5 = 1 mod 12```. A polynomial congruence is simply a congruence involving a polynomial, like ```x + 5 = 1 mod 12```. The problem of solving a congruence is to find all inputs satisfying the congruence, much like solving an equation (in this case, ```x = 8```). Generally speaking, congruences become more difficult to solve as the degree of the polynomial and the modulus grow. Elementary number theory develops tools like [Hensel Lifting](https://en.wikipedia.org/wiki/Hensel%27s_lemma#Hensel_Lifting) for solving polynomial congruences and the [Chinese Remainder Theorem](https://en.wikipedia.org/wiki/Chinese_remainder_theorem) for solving systems of polynomial congruences. This gem leverages these methods as implemented in C in [congruence_solver_ext](https://github.com/laneb/congruence_solver_ext).
7
+ Polynomial congruences are the central topic of most elementary number theory and abstract algebra curricula. Similar to an equation, a [congruence](https://en.wikipedia.org/wiki/Modular_equation) is an [equivalence relation](https://en.wikipedia.org/wiki/Equivalence_relation) arising from [modular arithmetic](https://en.wikipedia.org/wiki/Modular_arithmetic) (also knowsn as "clock arithmetic"). For example, the idea "5 hours past 8 is 1" is expressed in the congruence ```8 + 5 = 1 mod 12```. A polynomial congruence is simply a congruence involving a polynomial, like ```x + 5 = 1 mod 12```. The problem of solving a congruence is to find all inputs satisfying the congruence, much like solving an equation (in this case, ```x = 8```). Generally speaking, congruences become more difficult to solve as the degree of the polynomial and the modulus grow. Elementary number theory develops tools like [Hensel Lifting](https://en.wikipedia.org/wiki/Hensel%27s_lemma#Hensel_Lifting) for solving polynomial congruences and the [Chinese Remainder Theorem](https://en.wikipedia.org/wiki/Chinese_remainder_theorem) for solving systems of polynomial congruences. This gem leverages these methods as implemented in C in [congruence_solver](https://github.com/laneb/congruence_solver).
8
8
 
9
9
  ## Installation
10
10
 
@@ -42,6 +42,10 @@ mod = 49
42
42
  CongruenceSolver.solve_congruence(coeffs, mod).sort #=> [1, 8, 15, 22, 26, 29, 36, 43]
43
43
  ```
44
44
 
45
+ ## Limitations
46
+
47
+ What are the limitations on the size of the numbers, you ask? CongruenceSolver can solve any congruence with a 16 bit degree that 32 bit coefficients and modulus. Of course, Ruby's Bignum can manage arbitrarily large integers without overflow, but the extension that powers has limitations to maintain speed and simplicity.
48
+
45
49
  ## Development
46
50
 
47
51
  First, install bundler (`gem install bundler`). Then install this project's dependencies with `bundle install`. Use `bundle exec rake update_ext` to pull and compile the extension. Use `bundle exec rake spec` to run the tests and `bundle exec rake bench` to run the benchmark. To build and install this gem locally, run `bundle exec rake install`.
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require "os"
5
5
 
6
6
  def verbose_sh_exec(cmd)
7
7
  puts cmd
8
- `#{cmd}`
8
+ system cmd
9
9
  end
10
10
 
11
11
  def verbose_rm_files(files_to_rm_ary)
@@ -20,14 +20,14 @@ end
20
20
 
21
21
  # runs the csolve binary
22
22
  task :exe do
23
- system "bin/csolve"
23
+ verbose_sh_exec "bin/csolve"
24
24
  end
25
25
 
26
26
  #spec runs all RSpec examples
27
27
  RSpec::Core::RakeTask.new :spec
28
28
 
29
29
  # run the tests shipped the extension
30
- task :ctest => [:compile_ext] do
30
+ task :ctest do
31
31
  verbose_sh_exec "(cd ext/congruence_solver && make test)"
32
32
  end
33
33
 
@@ -37,11 +37,12 @@ task :test => [:ctest, :spec]
37
37
  # workflow
38
38
  Rake::ExtensionTask.new 'congruence_solver' do |ext|
39
39
  ext.lib_dir = "lib/congruence_solver"
40
+ ext.config_options << "--openmp=-fopenmp"
40
41
  end
41
42
 
42
43
  # runs benchmarks
43
44
  task :bench do
44
- system "csolve bench"
45
+ verbose_sh_exec "csolve bench"
45
46
  end
46
47
 
47
48
  # download source files for the extension
@@ -80,25 +81,27 @@ task :clean do
80
81
  end
81
82
 
82
83
  # build Ruby gem
83
- task :build => [:compile_ext] do
84
+ task :build do
84
85
  gemspec = "congruence_solver.gemspec"
85
86
  verbose_sh_exec "gem build #{gemspec}"
86
87
  end
87
88
 
88
- # install gem locally
89
- task :install => [:clean, :update_ext, :test, :build] do
89
+ def gemfile
90
90
  dot_gem_files = Dir.entries(Dir.pwd).select {|f| f =~ /congruence_solver\-.*\.gem/}
91
91
  if dot_gem_files.empty?
92
92
  STDERR.puts "Failed to build gem. Exiting."
93
93
  elsif dot_gem_files.length > 1
94
94
  STDERR.puts "Error: conflicting .gem files in directory. Exiting."
95
95
  else
96
- verbose_sh_exec "gem install #{dot_gem_files.first}"
96
+ dot_gem_files.first
97
97
  end
98
98
  end
99
99
 
100
- task :publish do
101
- cmd = "gem push *.gem"
102
- p cmd
103
- system cmd
100
+ # install gem locally
101
+ task :install => [:compile_ext, :build] do
102
+ verbose_sh_exec "gem install #{gemfile}"
103
+ end
104
+
105
+ task :publish => [:clean, :compile_ext, :test, :build] do
106
+ verbose_sh_exec "gem push #{gemfile}"
104
107
  end
@@ -2,70 +2,20 @@ require "congruence_solver"
2
2
  require "benchmark"
3
3
  require_relative "./bench_tools.rb"
4
4
 
5
+ COEFFS = [-11, 0, 1, 3, 0, 5, 4, 180, 0, 10]
6
+ COMPOSITE_MOD = 4837012493
7
+ PRIME_MOD = 57081391
5
8
 
6
- SMALL_DEG_POLYNOMIAL_COEFFS = [1, -4, 4]
7
- LARGE_DEG_POLYNOMIAL_COEFFS = [-11, 0, 0, 3, 0, 0, 0, 0, 0, 10]
8
- SMALL_MOD = 49
9
- MED_MOD = 5104
10
- LARGE_MOD = 94122
11
- XTRA_LARGE_MOD = 401249
12
- XTRA_LARGE_PRIME_MOD = 306893
13
- SMALL_FACTORED_LARGE_MOD = 510510
14
-
15
-
16
- def solve_congruence_brute_force(coeffs, mod)
17
- solutions = []
18
-
19
- 0.upto(mod) do |x|
20
- sum = 0
21
-
22
- coeffs.each_with_index do |coe, exp|
23
- sum = (sum + coe*x**exp) % mod
24
- end
25
-
26
- if sum == 0 then solutions << x end
27
- end
28
-
29
- solutions
30
- end
31
-
32
-
33
- def bm_solve_congruence(coeffs, mod)
9
+ def bm_solve_congruence(coeffs, mod)
34
10
  puts "Solving #{polynomial_to_s(coeffs)} = 0 mod #{mod}"
35
-
36
- rb_bf_solutions = solve_congruence_brute_force(coeffs, mod).sort
37
- #c_bf_solutions = CongruenceSolver.brute_force(coeffs, mod).sort
38
- c_lifting_solutions = CongruenceSolver.lift(coeffs, mod).sort
39
-
40
- unless rb_bf_solutions == c_lifting_solutions #and c_bf_solutions c_lift_solutions
41
- puts "Solutions do not match:"
42
- puts "Ruby/force solutions #{rb_bf_solutions.inspect}"
43
- #puts "C/force solutions #{c_bf_solutions}"
44
- puts "C/lifting solutions: #{c_lifting_solutions.inspect}"
45
- end
46
-
47
- puts "Time measurements:"
48
-
11
+ puts "Measurements:"
49
12
  Benchmark.bmbm do |bm|
50
- bm.report("Ruby/force") do
51
- solve_congruence_brute_force(coeffs, mod)
52
- end
53
- =begin
54
- bm.report("C/force") do
55
- CongruenceSolver.brute_force(coeffs, mod)
56
- end
57
- =end
58
13
  bm.report("C/lifting") do
59
14
  CongruenceSolver.lift(coeffs, mod)
60
15
  end
61
16
  end
62
-
63
17
  print "\n\n"
64
18
  end
65
19
 
66
-
67
- [SMALL_DEG_POLYNOMIAL_COEFFS, LARGE_DEG_POLYNOMIAL_COEFFS].each do |coeffs|
68
- [SMALL_MOD, MED_MOD, LARGE_MOD, XTRA_LARGE_MOD, XTRA_LARGE_PRIME_MOD, SMALL_FACTORED_LARGE_MOD].each do |mod|
69
- bm_solve_congruence(coeffs, mod)
70
- end
71
- end
20
+ bm_solve_congruence(COEFFS,COMPOSITE_MOD)
21
+ bm_solve_congruence(COEFFS,PRIME_MOD)
@@ -24,9 +24,9 @@ Gem::Specification.new do |spec|
24
24
 
25
25
  spec.extensions << "ext/congruence_solver/extconf.rb"
26
26
 
27
- spec.add_development_dependency "bundler", "~> 1.10"
28
- spec.add_development_dependency "rake", "~> 10.0"
29
- spec.add_development_dependency "rspec", "~> 3.0"
27
+ spec.add_development_dependency "bundler", "~>1.10"
28
+ spec.add_development_dependency "rake", "~>10.0"
29
+ spec.add_development_dependency "rspec", "~>3.0"
30
30
  spec.add_development_dependency "rake-compiler", "~>0.9"
31
31
  spec.add_development_dependency "os", "~>0.9"
32
32
  end
@@ -1,12 +1,13 @@
1
+ CC = gcc-6 -fopenmp -std=c99
1
2
 
2
3
  congruences_test: congruences.c test/congruences_test.c test/congruences_test.h arith_utils.c prime_gen.c
3
- gcc -g prime_gen.c arith_utils.c congruences.c test/congruences_test.c -o congruences_test
4
+ $(CC) -g prime_gen.c arith_utils.c congruences.c test/congruences_test.c -o congruences_test
4
5
 
5
6
  arith_utils_test: arith_utils.c test/arith_utils_test.c test/arith_utils_test.h prime_gen.c
6
- gcc -g prime_gen.c arith_utils.c test/arith_utils_test.c -o arith_utils_test
7
+ $(CC) -g prime_gen.c arith_utils.c test/arith_utils_test.c -o arith_utils_test
7
8
 
8
9
  prime_gen_test: prime_gen.c test/prime_gen_test.c test/prime_gen_test.h
9
- gcc -g prime_gen.c test/prime_gen_test.c -o prime_gen_test
10
+ $(CC) -g prime_gen.c test/prime_gen_test.c -o prime_gen_test
10
11
 
11
12
  test: prime_gen_test arith_utils_test congruences_test
12
13
  ./prime_gen_test
@@ -4,7 +4,7 @@
4
4
  #include "arith_utils.h"
5
5
 
6
6
  //Expects 0 <= x,y < mod
7
- int mod_sum(int x, int y, int mod){
7
+ long mod_sum(long x, long y, long mod){
8
8
  if(y >= mod - x){
9
9
  return y - (mod - x);
10
10
  }
@@ -15,8 +15,8 @@ int mod_sum(int x, int y, int mod){
15
15
  }
16
16
 
17
17
 
18
- int mod_inv(int n, int mod){
19
- int y, a;
18
+ long mod_inv(long n, long mod){
19
+ long y, a;
20
20
 
21
21
  if(n!=0){
22
22
 
@@ -37,30 +37,9 @@ int mod_inv(int n, int mod){
37
37
  }
38
38
 
39
39
 
40
- int coprime(int n1, int n2){
41
- //naive algorithm but efficient when n1 has already been factorized
42
- int * n1Factors = prime_factors(n1);
43
- int numOfFactors = *n1Factors;
44
- int * factors = n1Factors+1;
45
- int shareFactor = 0;
46
- int i;
47
-
48
- for(i=0; i<numOfFactors; i++){
49
- if(n2 % factors[i] == 0){
50
- shareFactor = 1;
51
- break;
52
- }
53
- }
54
-
55
- free(n1Factors);
56
-
57
- return !shareFactor;
58
- }
59
-
60
-
61
- int mod_product(int num1, int num2, int mod){
62
- int prod = 0;
63
- int i;
40
+ long mod_product(long num1, long num2, long mod){
41
+ long prod = 0;
42
+ long i;
64
43
 
65
44
  for(i = 0; i < num1; i++){
66
45
  prod = mod_sum(prod, num2, mod);
@@ -69,68 +48,15 @@ int mod_product(int num1, int num2, int mod){
69
48
  return prod;
70
49
  }
71
50
 
72
- //expects 0 <= n < mod
73
- int mod_power(int n, int power, int mod){
74
- int product = n;
75
- int i;
76
-
77
- for(i = 1; i < power; i++){
78
- product = mod_product(product, n, mod);
79
- }
80
-
81
- return product;
82
- }
83
-
84
-
85
- int totient(int n){
86
- int * divisorList = prime_factors(n);
87
- int listLength = divisorList[0];
88
- int * divisors = divisorList+1;
89
- int i;
90
-
91
- for(i = 0; i < listLength; i++){
92
- n *= (divisors[i] - 1);
93
- n /= divisors[i];
94
- }
95
-
96
- free(divisorList);
97
-
98
- return n;
99
- }
100
-
101
51
 
102
-
103
-
104
- int mod_eval_polynomial(int degree, int coeffs[], int mod, int x){
105
- long tot = coeffs[degree];
52
+ long mod_eval_polynomial(int degree, long coeffs[], long mod, long x){
53
+ long long tot = coeffs[degree];
106
54
  int i;
107
55
 
108
56
  for(i = degree - 1; i >= 0; i--){
109
- tot = (x*tot) % mod;
110
- tot = (tot + coeffs[i]) % mod;
57
+ tot = ( (long long) tot*x ) % mod;
58
+ tot = ( (long long) tot + coeffs[i] ) % mod;
111
59
  }
112
60
 
113
- return (int) tot;
61
+ return (long) tot;
114
62
  }
115
-
116
-
117
- long eval_polynomial(int degree, int coeffs[], int x){
118
- long int sum = coeffs[0];
119
- long int powx;
120
- int i;
121
-
122
- for(i = 1, powx = x; i <= degree; i++, powx*=x){
123
- sum += powx*coeffs[i];
124
- }
125
-
126
- return sum;
127
- }
128
-
129
-
130
-
131
-
132
- /*
133
- int * linear_diophantine_solution(int order, int coeffs[], int scal){
134
-
135
- *=}
136
- */
@@ -1,10 +1,6 @@
1
1
  #ifndef H_ARITH_UTILS
2
2
  #define H_ARITH_UTILS
3
- int mod_inv(int n, int mod);
4
- int mod_product(int n1, int n2, int mod);
5
- int mod_power(int n, int power, int mod);
6
- int mod_eval_polynomial(int degree, int coeffs[], int mod, int x);
7
- long eval_polynomial(int degree, int coeffs[], int x);
8
- int coprime(int n1, int n2);
9
- int totient(int n);
10
- #endif
3
+ long mod_inv(long n, long mod);
4
+ long mod_product(long n1, long n2, long mod);
5
+ long mod_eval_polynomial(int degree, long coeffs[], long mod, long x);
6
+ #endif
@@ -9,77 +9,70 @@ VALUE CongruenceSolver = Qnil;
9
9
  void Init_congruence_solver();
10
10
  VALUE method_congruence_solver_lift(VALUE self, VALUE funcCoeffs, VALUE mod);
11
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
12
 
15
13
  void Init_congruence_solver(){
16
14
  CongruenceSolver = rb_define_module("CongruenceSolver");
17
-
15
+
18
16
  rb_define_singleton_method(CongruenceSolver, "lift",
19
17
  method_congruence_solver_lift, 2);
20
18
 
21
- rb_define_singleton_method(CongruenceSolver, "brute_force",
19
+ rb_define_singleton_method(CongruenceSolver, "brute_force",
22
20
  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
21
  }
28
22
 
29
23
 
30
24
  VALUE method_congruence_solver_brute_force(VALUE self, VALUE funcCoeffs, VALUE mod){
31
25
  int i;
32
- int * intSolutions;
26
+ long * longSolutions;
33
27
  VALUE rbSolutions;
34
- int intMod = NUM2INT(mod);
28
+ long longMod = NUM2LONG(mod);
35
29
 
36
30
  int intFuncDegree = RARRAY_LEN(funcCoeffs)-1;
37
- int * intFuncCoeffs = calloc(intFuncDegree+1, sizeof(int));
31
+ long * longFuncCoeffs = calloc(intFuncDegree+1, sizeof(long));
38
32
 
39
33
  for(i = 0; i <= intFuncDegree; i++){
40
- intFuncCoeffs[i] = NUM2INT(rb_ary_entry(funcCoeffs, i));
34
+ longFuncCoeffs[i] = NUM2LONG(rb_ary_entry(funcCoeffs, i));
41
35
  }
42
36
 
43
- intSolutions = brute_force_congruence(intFuncDegree, intFuncCoeffs, intMod);
44
- rbSolutions = rb_ary_new2(intSolutions[0]);
37
+ longSolutions = brute_force_congruence(intFuncDegree, longFuncCoeffs, longMod);
38
+ rbSolutions = rb_ary_new2(longSolutions[0]);
45
39
 
46
- for(i=0; i<intSolutions[0]; i++){
47
- rb_ary_store(rbSolutions, i, INT2NUM(intSolutions[i+1]));
40
+ for(i=0; i<longSolutions[0]; i++){
41
+ rb_ary_store(rbSolutions, i, LONG2NUM(longSolutions[i+1]));
48
42
  }
49
43
 
50
44
 
51
- free(intFuncCoeffs);
52
- free(intSolutions);
45
+ free(longFuncCoeffs);
46
+ free(longSolutions);
53
47
 
54
48
  return rbSolutions;
55
49
  }
56
-
50
+
57
51
 
58
52
  VALUE method_congruence_solver_lift(VALUE self, VALUE funcCoeffs, VALUE mod){
59
53
  int i;
60
- int * intSolutions;
54
+ long * longSolutions;
61
55
  VALUE rbSolutions;
62
- int intMod = NUM2INT(mod);
56
+ long longMod = NUM2LONG(mod);
63
57
 
64
58
  int intFuncDegree = RARRAY_LEN(funcCoeffs)-1;
65
- int * intFuncCoeffs = calloc(intFuncDegree+1, sizeof(int));
59
+ long * longFuncCoeffs = calloc(intFuncDegree+1, sizeof(long));
66
60
 
67
61
  for(i=0; i<=intFuncDegree; i++){
68
- intFuncCoeffs[i] = NUM2INT(rb_ary_entry(funcCoeffs, i));
62
+ longFuncCoeffs[i] = NUM2LONG(rb_ary_entry(funcCoeffs, i));
69
63
  }
70
64
 
65
+ longSolutions = solve_congruence(intFuncDegree, longFuncCoeffs, longMod);
71
66
 
72
- intSolutions = solve_congruence(intFuncDegree, intFuncCoeffs, intMod);
73
- rbSolutions = rb_ary_new2(intSolutions[0]);
67
+ rbSolutions = rb_ary_new2(longSolutions[0]);
74
68
 
75
- for(i=0; i<intSolutions[0]; i++){
76
- rb_ary_store(rbSolutions, i, INT2NUM(intSolutions[i+1]));
69
+ for(i=0; i<longSolutions[0]; i++){
70
+ rb_ary_store(rbSolutions, i, LONG2NUM(longSolutions[i+1]));
77
71
  }
78
72
 
79
73
 
80
- free(intFuncCoeffs);
81
- free(intSolutions);
74
+ free(longFuncCoeffs);
75
+ free(longSolutions);
82
76
 
83
77
  return rbSolutions;
84
78
  }
85
-
@@ -3,15 +3,15 @@
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);
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[]);
6
+ static long * adjust_coeffs_to_mod(int degree, long * coeffs, long mod);
7
+ static long * solve_prime_power_congruence(int degree, long coeffs[], long prime, int power);
8
+ static long * solve_system_of_order_1_congruence_sets(int numOfSets, int * lengthsOfSets, long ** sets, long mods[]);
9
9
 
10
- int chinese_remainder_solution(int numberOfEquations, int scals[], int mods[]){
10
+ long chinese_remainder_solution(int numberOfEquations, long scals[], long mods[]){
11
11
  int i;
12
- int x = 0;
13
- int m = mods[0];
14
- int modCoeff;
12
+ long long x = 0;
13
+ long m = mods[0];
14
+ long modCoeff;
15
15
 
16
16
  for(i=1; i<numberOfEquations; i++){
17
17
  m *= mods[i];
@@ -19,15 +19,16 @@ int chinese_remainder_solution(int numberOfEquations, int scals[], int mods[]){
19
19
 
20
20
  for(i=0; i<numberOfEquations; i++){
21
21
  modCoeff = m/mods[i];
22
- x += modCoeff*mod_inv(modCoeff % mods[i], mods[i])*scals[i];
22
+ x += (long long) modCoeff*mod_inv(modCoeff % mods[i], mods[i])*scals[i] % m;
23
+ x %= m;
23
24
  }
24
25
 
25
26
  return x % m;
26
27
  }
27
28
 
28
29
 
29
- int * adjust_coeffs_to_mod(int degree, int * coeffs, int mod){
30
- int * adjustedCoeffs = calloc(degree+1, sizeof(int));
30
+ long * adjust_coeffs_to_mod(int degree, long * coeffs, long mod){
31
+ long * adjustedCoeffs = calloc(degree+1, sizeof(long));
31
32
  int i;
32
33
 
33
34
  for(i = 0; i <= degree; i++){
@@ -41,19 +42,19 @@ int * adjust_coeffs_to_mod(int degree, int * coeffs, int mod){
41
42
  }
42
43
 
43
44
 
44
- int * brute_force_congruence(int degree, int coeffs[], int primeMod){
45
+ long * brute_force_congruence(int degree, long coeffs[], long primeMod){
45
46
  //assumes a prime modulus. split congruences of composite modulus into systems of congrueneces
46
47
  //of prime modulus and/or apply the lifting theorem to make use of this function
47
48
  //solve a0x^n + a1x^n-1... = 0 (mod mod) where n is the order a0, a1, ... are coeffieicients
48
49
  //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;
50
+ long * adjustedCoeffs = adjust_coeffs_to_mod(degree, coeffs, primeMod);
51
+ long * solutionList = calloc(degree+1, sizeof(long));
52
+ long * solutions = solutionList+1;
52
53
  int numberOfSolutions = 0;
53
- int x;
54
+ long x;
54
55
 
55
-
56
- for(x = 0; x < primeMod && numberOfSolutions <= degree; x++){
56
+ #pragma omp parallel for
57
+ for(x = 0; x < primeMod; x++){
57
58
  if(mod_eval_polynomial(degree, adjustedCoeffs, primeMod, x) == 0){
58
59
  solutions[numberOfSolutions++] = x;
59
60
  }
@@ -67,26 +68,23 @@ int * brute_force_congruence(int degree, int coeffs[], int primeMod){
67
68
  }
68
69
 
69
70
 
70
- static int * solve_prime_power_congruence(int funcDegree, int funcCoeffs[], int prime, int power){
71
-
72
- int * adjustedCoeffs;
73
-
74
- int * baseSolutionList;
71
+ static long * solve_prime_power_congruence(int funcDegree, long funcCoeffs[], long prime, int power){
72
+ long * baseSolutionList;
75
73
  int numOfBaseSolutions;
76
- int * baseSolutions;
74
+ long * baseSolutions;
77
75
 
78
- int * liftedSolutions;
76
+ long * liftedSolutions;
79
77
  int numOfLiftedSolutions;
80
78
 
81
- int coeff;
79
+ long coeff;
82
80
 
83
81
  int derivDegree;
84
- int * derivCoeffs;
85
- int deriv;
86
- long int divFunc;
82
+ long * derivCoeffs;
83
+ long deriv;
84
+ long func;
87
85
 
88
86
  int i, j, t;
89
- int currentMod;
87
+ long currentMod;
90
88
 
91
89
  if(power == 1){
92
90
  baseSolutions = brute_force_congruence(funcDegree, funcCoeffs, prime);
@@ -97,11 +95,11 @@ static int * solve_prime_power_congruence(int funcDegree, int funcCoeffs[], int
97
95
  numOfBaseSolutions = *baseSolutionList;
98
96
  baseSolutions = baseSolutionList+1;
99
97
 
100
- liftedSolutions = calloc(prime*numOfBaseSolutions+1, sizeof(int));
98
+ liftedSolutions = calloc(prime*numOfBaseSolutions+1, sizeof(long));
101
99
  numOfLiftedSolutions = 0;
102
100
 
103
101
  derivDegree = funcDegree-1;
104
- derivCoeffs = calloc(derivDegree+1, sizeof(int));
102
+ derivCoeffs = calloc(derivDegree+1, sizeof(long));
105
103
 
106
104
  currentMod = prime;
107
105
  for(j = 1; j < power; j++){
@@ -120,14 +118,14 @@ static int * solve_prime_power_congruence(int funcDegree, int funcCoeffs[], int
120
118
  for(j = 0; j < numOfBaseSolutions; j++){
121
119
 
122
120
  deriv = mod_eval_polynomial(derivDegree, derivCoeffs, prime, baseSolutions[j]);
123
- divFunc = (eval_polynomial(funcDegree, funcCoeffs, baseSolutions[j]) / (currentMod/prime)) % prime;
121
+ func = mod_eval_polynomial(funcDegree, funcCoeffs, currentMod, baseSolutions[j]);
124
122
 
125
123
  if(deriv % prime != 0){
126
- t = (-divFunc*mod_inv(deriv, prime) % prime) + prime;
124
+ t = ((-func / (currentMod/prime))*mod_inv(deriv, currentMod) % prime) + prime;
127
125
  liftedSolutions[++numOfLiftedSolutions] = baseSolutions[j] + t*prime;
128
126
  }
129
127
 
130
- else if(divFunc % prime == 0){
128
+ else if(func == 0){
131
129
  for(t = 1; t <= prime; t++){
132
130
  liftedSolutions[++numOfLiftedSolutions] = baseSolutions[j] + t*(currentMod/prime);
133
131
  }
@@ -144,14 +142,14 @@ static int * solve_prime_power_congruence(int funcDegree, int funcCoeffs[], int
144
142
  }
145
143
 
146
144
 
147
- static int * solve_system_of_order_1_congruence_sets(int numOfSets, int * setLengths, int * * sets, int * mods){
145
+ static long * solve_system_of_order_1_congruence_sets(int numOfSets, int * setLengths, long * * sets, long * mods){
148
146
  //allocate perumtation array
149
- int * divAry = calloc(numOfSets, sizeof(int));
150
- int * scalAry = calloc(numOfSets, sizeof(int));
147
+ long * divAry = calloc(numOfSets, sizeof(long));
148
+ long * scalAry = calloc(numOfSets, sizeof(long));
151
149
  int i, j;
152
150
  int numOfSolutions;
153
- int * solutionAry;
154
- int * dest;
151
+ long * solutionAry;
152
+ long * dest;
155
153
  int idx;
156
154
 
157
155
  for(i = 0, numOfSolutions = 1; i < numOfSets; i++){
@@ -159,7 +157,7 @@ static int * solve_system_of_order_1_congruence_sets(int numOfSets, int * setLen
159
157
  numOfSolutions *= setLengths[i];
160
158
  }
161
159
 
162
- solutionAry = calloc(numOfSolutions+1, sizeof(int));
160
+ solutionAry = calloc(numOfSolutions+1, sizeof(long));
163
161
  solutionAry[0] = numOfSolutions;
164
162
  dest = solutionAry+1;
165
163
 
@@ -175,24 +173,24 @@ static int * solve_system_of_order_1_congruence_sets(int numOfSets, int * setLen
175
173
  return solutionAry;
176
174
  }
177
175
 
178
- int * solve_congruence(int funcDegree, int funcCoeffs[], int mod){
179
- int * solutionList;
176
+ long * solve_congruence(int funcDegree, long funcCoeffs[], long mod){
177
+ long * solutionList;
180
178
 
181
- int * modFactorList = prime_factors(mod);
182
- int numOfModFactors = *modFactorList;
183
- int * modFactors = modFactorList+1;
179
+ long * modFactorList = prime_factors(mod);
180
+ long numOfModFactors = *modFactorList;
181
+ long * modFactors = modFactorList+1;
184
182
 
185
- int * * primePowerSolutions = calloc(numOfModFactors, sizeof(int *));
186
- int * primePowers = calloc(numOfModFactors, sizeof(int));
183
+ long * * primePowerSolutions = calloc(numOfModFactors, sizeof(long *));
184
+ long * primePowers = calloc(numOfModFactors, sizeof(long));
187
185
  int * primePowerSolutionLengths = calloc(numOfModFactors, sizeof(int *));
188
186
 
189
187
  int power;
190
- int i;
188
+ int i,j,k;
191
189
 
192
190
  for(i = 0; i < numOfModFactors; i++){
193
- primePowers[i] = modFactors[i];
191
+ primePowers[i] = modFactors[i];
194
192
  power = 1;
195
-
193
+
196
194
  while(mod % (primePowers[i]*modFactors[i]) == 0){
197
195
  primePowers[i] *= modFactors[i];
198
196
  power++;
@@ -214,14 +212,3 @@ int * solve_congruence(int funcDegree, int funcCoeffs[], int mod){
214
212
 
215
213
  return solutionList;
216
214
  }
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
- */
@@ -1,7 +1,6 @@
1
1
  #ifndef H_CONGRUENCES
2
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
- #endif
3
+ long chinese_remainder_solution(int numOfEquations, int long[], long mods[]);
4
+ long * solve_congruence(int funcDegree, long funcCoeffs[], long mod);
5
+ long * brute_force_congruence(int degree, long coeffs[], long primeMod);
6
+ #endif
@@ -13,4 +13,14 @@ EXT_C = %w[
13
13
  prime_gen.c
14
14
  ]
15
15
 
16
- create_makefile "congruence_solver/congruence_solver"
16
+ omp_opt = arg_config("--openmp")
17
+ if omp_opt
18
+ if have_header("omp.h")
19
+ $CFLAGS += " " + omp_opt
20
+ $DLDFLAGS += " " + omp_opt
21
+ else
22
+ raise "OpenMP unsupported by this compiler"
23
+ end
24
+ end
25
+
26
+ create_makefile "congruence_solver/congruence_solver"
@@ -7,40 +7,40 @@
7
7
  #define FIRST_PRIME 2
8
8
 
9
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);
10
+ static void expand_prime_list_past(long max);
11
+ static int any_divisors(long * div_list, int length, long num);
12
+ static long least_divisor(long n);
13
13
 
14
- static int * PRIME_LIST = NULL;
14
+ static long * PRIME_LIST = NULL;
15
15
  static int PRIME_LIST_LENGTH = 0;
16
16
  static int PRIME_LIST_MAX_LENGTH = 0;
17
- static int NEXT_INTEGER = FIRST_PRIME;
17
+ static long NEXT_INTEGER = FIRST_PRIME;
18
18
 
19
19
 
20
- int * primes(int length){
21
- int * rtrn_list = calloc(length, sizeof(int));
20
+ long * primes(int length){
21
+ long * rtrn_list = calloc(length, sizeof(long));
22
22
 
23
23
  expand_prime_list_to_length(length);
24
24
 
25
25
  if(rtrn_list != NULL){
26
- memcpy(rtrn_list, PRIME_LIST, length*sizeof(int));
26
+ memcpy(rtrn_list, PRIME_LIST, length*sizeof(long));
27
27
  }
28
28
 
29
29
  return rtrn_list;
30
30
  }
31
31
 
32
32
 
33
- int * primes_upto(int max){
34
- int * rtrn_list;
33
+ long * primes_upto(long max){
34
+ long * rtrn_list;
35
35
  int i;
36
36
 
37
37
  expand_prime_list_past(max);
38
38
 
39
39
  for(i = PRIME_LIST_LENGTH; i > 0; i--){
40
40
  if(PRIME_LIST[i-1] <= max){
41
- rtrn_list = calloc(i+1, sizeof(int));
41
+ rtrn_list = calloc(i+1, sizeof(long));
42
42
  rtrn_list[0] = i;
43
- memcpy(rtrn_list+1, PRIME_LIST, i*sizeof(int));
43
+ memcpy(rtrn_list+1, PRIME_LIST, i*sizeof(long));
44
44
  return rtrn_list;
45
45
  }
46
46
  }
@@ -49,14 +49,14 @@ int * primes_upto(int max){
49
49
  }
50
50
 
51
51
 
52
- int * prime_factors(int n){
53
- int * rtrn_list = malloc(sizeof(int));
52
+ long * prime_factors(long n){
53
+ long * rtrn_list = malloc(sizeof(long));
54
54
  int rtrn_list_length = 0;
55
- int least_div;
55
+ long least_div;
56
56
 
57
57
  while(n != 1){
58
58
  least_div = least_divisor(n);
59
- rtrn_list = realloc(rtrn_list, (rtrn_list_length+2)*sizeof(int));
59
+ rtrn_list = realloc(rtrn_list, (rtrn_list_length+2)*sizeof(long));
60
60
  rtrn_list[++rtrn_list_length] = least_div;
61
61
 
62
62
  if(least_div == n){
@@ -74,9 +74,9 @@ int * prime_factors(int n){
74
74
  }
75
75
 
76
76
 
77
- static int least_divisor(int n){
77
+ static long least_divisor(long n){
78
78
  //Calculate maximum for least divisor (sqrt)
79
- int least_div_max = sqrt(n) + 1;
79
+ long least_div_max = sqrt(n) + 1;
80
80
  int i;
81
81
  //Expand prime list up to the least divisor
82
82
  expand_prime_list_past(least_div_max);
@@ -96,7 +96,7 @@ static void expand_prime_list_to_length(int length){
96
96
 
97
97
  if(PRIME_LIST_MAX_LENGTH < length){
98
98
  PRIME_LIST_MAX_LENGTH = 2*length;
99
- PRIME_LIST = realloc(PRIME_LIST, PRIME_LIST_MAX_LENGTH*sizeof(int));
99
+ PRIME_LIST = realloc(PRIME_LIST, PRIME_LIST_MAX_LENGTH*sizeof(long));
100
100
  }
101
101
 
102
102
  while(PRIME_LIST_LENGTH < length){
@@ -110,15 +110,15 @@ static void expand_prime_list_to_length(int length){
110
110
  }
111
111
 
112
112
 
113
- static void expand_prime_list_past(int max){
113
+ static void expand_prime_list_past(long max){
114
114
  if(PRIME_LIST == NULL){
115
115
  //TODO: find better heuristic limit on memory necessary to allocate
116
116
  PRIME_LIST_MAX_LENGTH = (max/2) + 1;
117
- PRIME_LIST = calloc(PRIME_LIST_MAX_LENGTH, sizeof(int));
117
+ PRIME_LIST = calloc(PRIME_LIST_MAX_LENGTH, sizeof(long));
118
118
  PRIME_LIST[0] = NEXT_INTEGER++;
119
119
  PRIME_LIST_LENGTH = 1;
120
120
  }
121
-
121
+
122
122
  while(PRIME_LIST[PRIME_LIST_LENGTH-1] <= max){
123
123
  while(any_divisors(PRIME_LIST, PRIME_LIST_LENGTH, NEXT_INTEGER) ){
124
124
  NEXT_INTEGER++;
@@ -126,7 +126,7 @@ static void expand_prime_list_past(int max){
126
126
 
127
127
  if( PRIME_LIST_MAX_LENGTH <= PRIME_LIST_LENGTH){
128
128
  PRIME_LIST_MAX_LENGTH *= 2;
129
- PRIME_LIST = realloc(PRIME_LIST, PRIME_LIST_MAX_LENGTH*sizeof(int));
129
+ PRIME_LIST = realloc(PRIME_LIST, PRIME_LIST_MAX_LENGTH*sizeof(long));
130
130
  }
131
131
 
132
132
  PRIME_LIST[PRIME_LIST_LENGTH++] = NEXT_INTEGER;
@@ -134,7 +134,7 @@ static void expand_prime_list_past(int max){
134
134
  }
135
135
 
136
136
 
137
- static int any_divisors(int * div_list, int length, int num){
137
+ static int any_divisors(long * div_list, int length, long num){
138
138
  int i;
139
139
  for(i = 0; i < length; i++){
140
140
  if(num % div_list[i] == 0){
@@ -1,10 +1,10 @@
1
1
  #ifndef H_PRIME_GEN
2
2
  #define H_PRIME_GEN
3
- int * primes(int n);
3
+ long * primes(int length);
4
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
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
7
  //somewhat optimized to detect relatively large prime factors.
8
- int * primes_upto(int max);
9
- int * prime_factors(int n);
10
- #endif
8
+ long * primes_upto(long max);
9
+ long * prime_factors(long n);
10
+ #endif
@@ -1,3 +1,3 @@
1
1
  module CongruenceSolver
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: congruence_solver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - lane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-26 00:00:00.000000000 Z
11
+ date: 2017-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler