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
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
|