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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d41325020ecfa40cc46d234828df89bc2fb40f49
|
4
|
+
data.tar.gz: acde70a6f821e7ec7952ab6db97a7c0fe4d61484
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd914b02d0bb19bec1f30558d3fde308225eafbebc11029d0d2fe0ef6f1c91f31cfb03896596cdbd8da194a176bb5cad7bcf5cf339f21fed0ba1377afaeeff62
|
7
|
+
data.tar.gz: af76d6607a3acf0c327c1d60e9daf7fbbca921bc1877dde9803928d49a4131bd62975766ac8f7a2f3452153da5a6be4b8c6549de4a55c4292c3edcf0aaac5422
|
data/.gitignore
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
-
Gemfile.lock
|
2
|
-
tmp/
|
3
|
-
todo
|
4
|
-
lib/congruence_solver/congruence_solver.
|
5
|
-
*.gem
|
6
|
-
*.html
|
1
|
+
Gemfile.lock
|
2
|
+
tmp/
|
3
|
+
todo
|
4
|
+
lib/congruence_solver/congruence_solver.bundle
|
5
|
+
*.gem
|
6
|
+
*.html
|
7
|
+
ext/congruence_solver/*
|
8
|
+
!ext/congruence_solver/extconf.rb
|
9
|
+
!ext/congruence_solver/congruence_solver.c
|
data/.gitmodules
CHANGED
data/.rspec
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
--color
|
2
|
-
--require spec_helper
|
1
|
+
--color
|
2
|
+
--require spec_helper
|
data/README.md
CHANGED
@@ -1,64 +1,51 @@
|
|
1
|
-
# CongruenceSolver
|
2
|
-
|
3
|
-
CongruenceSolver is a gem for solving polynomial congruences. Should you ever need to solve polynomial congruences
|
4
|
-
|
5
|
-
## Polynomial Congruences
|
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).
|
8
|
-
|
9
|
-
## Installation
|
10
|
-
|
11
|
-
With [RubyGems](https://rubygems.org/) on your machine, installation is as easy as
|
12
|
-
```shell
|
13
|
-
gem install congruence_solver
|
14
|
-
```
|
15
|
-
|
16
|
-
You may also
|
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
|
-
coeffs = [1, 2, 1, 1, 0, 3]
|
53
|
-
mod = 49
|
54
|
-
CongruenceSolver.solve_congruence(coeffs, mod).sort #=> [1, 8, 15, 22, 26, 29, 36, 43]
|
55
|
-
```
|
56
|
-
|
57
|
-
## Development
|
58
|
-
|
59
|
-
After checking out the repo, run `bundle install` to install dependencies and `bundle exec rake update_ext` to pull and compile the extension. Then, run `bundle exec rake spec` to run the tests, or `bundle exec rake bench` to run the benchmark. To build and install this gem onto your local machine, run `bundle exec rake install`.
|
60
|
-
|
61
|
-
## Contributing
|
62
|
-
|
63
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/laneb/congruence_solver.
|
64
|
-
|
1
|
+
# CongruenceSolver
|
2
|
+
|
3
|
+
CongruenceSolver is a gem for solving polynomial congruences. Should you ever need to solve polynomial congruences, this is the gem for you!
|
4
|
+
|
5
|
+
## Polynomial Congruences
|
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).
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
With [RubyGems](https://rubygems.org/) on your machine, installation is as easy as
|
12
|
+
```shell
|
13
|
+
gem install congruence_solver
|
14
|
+
```
|
15
|
+
|
16
|
+
You may also include this gem in a project with [bundler](http://bundler.io/) or by adding it to your Gemfile.
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
To solve a polynomial congruence at the command line, simply invoke `csolve` and then enter the congruence at the prompt.
|
21
|
+
|
22
|
+
```
|
23
|
+
csolve
|
24
|
+
Congruence to solve:
|
25
|
+
x^2 + 2x + 1 = x^3 + 3x^5 mod 49
|
26
|
+
(0) 1
|
27
|
+
(1) 8
|
28
|
+
(2) 15
|
29
|
+
(3) 22
|
30
|
+
(4) 26
|
31
|
+
(5) 29
|
32
|
+
(6) 36
|
33
|
+
(7) 43
|
34
|
+
```
|
35
|
+
|
36
|
+
To use the CongruenceSolver in a Ruby program, use CongruenceSolve::solve_congruence(coeffs, mod), where coeffs is the ascending list of coefficients of the polynomial (congruent to 0) and mod is the modulus of the congruence.
|
37
|
+
|
38
|
+
```
|
39
|
+
#solve -3x^5 - x^3 + x^2 + 2x + 1 = 0 mod 49
|
40
|
+
coeffs = [1, 2, 1, 1, 0, 3]
|
41
|
+
mod = 49
|
42
|
+
CongruenceSolver.solve_congruence(coeffs, mod).sort #=> [1, 8, 15, 22, 26, 29, 36, 43]
|
43
|
+
```
|
44
|
+
|
45
|
+
## Development
|
46
|
+
|
47
|
+
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`.
|
48
|
+
|
49
|
+
## Contributing
|
50
|
+
|
51
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/laneb/congruence_solver.
|
data/Rakefile
CHANGED
@@ -1,87 +1,107 @@
|
|
1
|
-
#require "bundler/gem_tasks"
|
2
|
-
require "rspec/core/rake_task"
|
3
|
-
require "rake/extensiontask"
|
4
|
-
require "os"
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
task :
|
23
|
-
$LOAD_PATH << "#{Dir.pwd}/lib/"
|
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
|
-
end
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
1
|
+
#require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
require "rake/extensiontask"
|
4
|
+
require "os"
|
5
|
+
|
6
|
+
def verbose_sh_exec(cmd)
|
7
|
+
puts cmd
|
8
|
+
`#{cmd}`
|
9
|
+
end
|
10
|
+
|
11
|
+
def verbose_rm_files(files_to_rm_ary)
|
12
|
+
if OS.windows?
|
13
|
+
rm_cmd = "rm /s /q"
|
14
|
+
else
|
15
|
+
rm_cmd = "rm -rf"
|
16
|
+
end
|
17
|
+
|
18
|
+
files_to_rm_ary.each {|fname| verbose_sh_exec "#{rm_cmd} #{fname}"}
|
19
|
+
end
|
20
|
+
|
21
|
+
# runs the csolve binary
|
22
|
+
task :exe do
|
23
|
+
$LOAD_PATH << "#{Dir.pwd}/lib/"
|
24
|
+
require_relative "bin/csolve.rb"
|
25
|
+
end
|
26
|
+
|
27
|
+
#spec runs all RSpec examples
|
28
|
+
RSpec::Core::RakeTask.new :spec
|
29
|
+
|
30
|
+
# run the tests shipped the extension
|
31
|
+
task :ctest => [:compile_ext] do
|
32
|
+
verbose_sh_exec "(cd ext/congruence_solver && make test)"
|
33
|
+
end
|
34
|
+
|
35
|
+
task :test => [:ctest, :spec]
|
36
|
+
|
37
|
+
# uses task template provided by rake-compiler to run the extension compilation
|
38
|
+
# workflow
|
39
|
+
Rake::ExtensionTask.new 'congruence_solver' do |ext|
|
40
|
+
ext.lib_dir = "lib/congruence_solver"
|
41
|
+
end
|
42
|
+
|
43
|
+
# runs benchmarks
|
44
|
+
task :bench do
|
45
|
+
$LOAD_PATH << "#{Dir.pwd}/lib/"
|
46
|
+
Dir.foreach("bench") do |bm_file|
|
47
|
+
path = "bench/#{bm_file}"
|
48
|
+
if File.file? path and path =~ "_bm.rb^"
|
49
|
+
require_relative path
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# download source files for the extension
|
55
|
+
task :download_ext do
|
56
|
+
congruences_lib_url="https://github.com/laneb/congruences/archive/master.zip"
|
57
|
+
ext_dir = "ext/congruence_solver"
|
58
|
+
verbose_sh_exec "(cd #{ext_dir} && wget #{congruences_lib_url} && unzip master.zip && cp -r congruences-master/* . && rm -rf master.zip congruences-master )"
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# executes compile task defined by RSpec, then cleans up the tmp directory that
|
63
|
+
# rake-compiler for some reason leaves behind
|
64
|
+
task :compile_ext => [:compile] do
|
65
|
+
verbose_rm_files ["./tmp"]
|
66
|
+
end
|
67
|
+
|
68
|
+
# remove all the source files for the extension
|
69
|
+
task :purge_ext do
|
70
|
+
ext_files = `ls ext/congruence_solver`.split("\n").map {|fname| "ext/congruence_solver/" + fname}
|
71
|
+
perm_ext_files = `git ls-files ext/congruence_solver`.split("\n")
|
72
|
+
files_to_rm = ext_files - perm_ext_files
|
73
|
+
|
74
|
+
verbose_rm_files files_to_rm
|
75
|
+
end
|
76
|
+
|
77
|
+
task :update_ext => [:purge_ext, :download_ext, :compile_ext]
|
78
|
+
|
79
|
+
# remove files generated or left behind by build
|
80
|
+
task :clean do
|
81
|
+
files_to_rm = `find ext/congruence_solver/* -not -path "*.[ch]" -not -path *Makefile -not -path *extconf.rb`.split("\n")
|
82
|
+
verbose_rm_files files_to_rm
|
83
|
+
end
|
84
|
+
|
85
|
+
# build Ruby gem
|
86
|
+
task :build => [:compile_ext] do
|
87
|
+
gemspec = "congruence_solver.gemspec"
|
88
|
+
verbose_sh_exec "gem build #{gemspec}"
|
89
|
+
end
|
90
|
+
|
91
|
+
# install gem locally
|
92
|
+
task :install => [:clean, :update_ext, :test, :build] do
|
93
|
+
dot_gem_files = Dir.entries(Dir.pwd).select {|f| f =~ /congruence_solver\-.*\.gem/}
|
94
|
+
if dot_gem_files.empty?
|
95
|
+
STDERR.puts "Failed to build gem. Exiting."
|
96
|
+
elsif dot_gem_files.length > 1
|
97
|
+
STDERR.puts "Error: conflicting .gem files in directory. Exiting."
|
98
|
+
else
|
99
|
+
verbose_sh_exec "gem install #{dot_gem_files.first}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
task :publish => [:clean, :update_ext, :build] do
|
104
|
+
cmd = "gem push *.gem"
|
105
|
+
p cmd
|
106
|
+
system cmd
|
107
|
+
end
|
data/bench/bench_tools.rb
CHANGED
@@ -1,33 +1,33 @@
|
|
1
|
-
|
2
|
-
def polynomial_to_s(coeffs)
|
3
|
-
polynomial = ""
|
4
|
-
is_first_term = true
|
5
|
-
|
6
|
-
coeffs.reverse.each_with_index do |coe, idx|
|
7
|
-
exp = coeffs.length - idx - 1
|
8
|
-
if coe != 0
|
9
|
-
if is_first_term
|
10
|
-
is_first_term = false
|
11
|
-
else
|
12
|
-
if coe < 0
|
13
|
-
polynomial << " - "
|
14
|
-
else
|
15
|
-
polynomial << " + "
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
if coe.abs > 1 or (coe.abs == 1 and exp < 2)
|
20
|
-
polynomial << coe.abs.to_s
|
21
|
-
end
|
22
|
-
|
23
|
-
if exp > 0
|
24
|
-
polynomial << "x"
|
25
|
-
if exp > 1
|
26
|
-
polynomial << "^#{exp}"
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
polynomial
|
1
|
+
|
2
|
+
def polynomial_to_s(coeffs)
|
3
|
+
polynomial = ""
|
4
|
+
is_first_term = true
|
5
|
+
|
6
|
+
coeffs.reverse.each_with_index do |coe, idx|
|
7
|
+
exp = coeffs.length - idx - 1
|
8
|
+
if coe != 0
|
9
|
+
if is_first_term
|
10
|
+
is_first_term = false
|
11
|
+
else
|
12
|
+
if coe < 0
|
13
|
+
polynomial << " - "
|
14
|
+
else
|
15
|
+
polynomial << " + "
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
if coe.abs > 1 or (coe.abs == 1 and exp < 2)
|
20
|
+
polynomial << coe.abs.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
if exp > 0
|
24
|
+
polynomial << "x"
|
25
|
+
if exp > 1
|
26
|
+
polynomial << "^#{exp}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
polynomial
|
33
33
|
end
|
@@ -1,71 +1,71 @@
|
|
1
|
-
require "congruence_solver"
|
2
|
-
require "benchmark"
|
3
|
-
require_relative "./bench_tools.rb"
|
4
|
-
|
5
|
-
|
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)
|
34
|
-
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
|
-
|
49
|
-
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
|
-
bm.report("C/lifting") do
|
59
|
-
CongruenceSolver.lift(coeffs, mod)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
print "\n\n"
|
64
|
-
end
|
65
|
-
|
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
|
1
|
+
require "congruence_solver"
|
2
|
+
require "benchmark"
|
3
|
+
require_relative "./bench_tools.rb"
|
4
|
+
|
5
|
+
|
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)
|
34
|
+
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
|
+
|
49
|
+
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
|
+
bm.report("C/lifting") do
|
59
|
+
CongruenceSolver.lift(coeffs, mod)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
print "\n\n"
|
64
|
+
end
|
65
|
+
|
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
71
|
end
|