ruby-minisat 1.14.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/.gitignore +24 -0
  2. data/LICENSE +21 -0
  3. data/README.rdoc +56 -0
  4. data/Rakefile +48 -0
  5. data/VERSION +1 -0
  6. data/examples/compat18.rb +65 -0
  7. data/examples/example.rb +26 -0
  8. data/examples/example2.rb +60 -0
  9. data/examples/kakuro.rb +178 -0
  10. data/examples/kakuro.sample +13 -0
  11. data/examples/lonely7.rb +302 -0
  12. data/examples/nonogram.rb +254 -0
  13. data/examples/nonogram.sample +26 -0
  14. data/examples/numberlink.rb +489 -0
  15. data/examples/numberlink.sample +11 -0
  16. data/examples/shikaku.rb +190 -0
  17. data/examples/shikaku.sample +11 -0
  18. data/examples/slitherlink.rb +279 -0
  19. data/examples/slitherlink.sample +11 -0
  20. data/examples/sudoku.rb +216 -0
  21. data/examples/sudoku.sample +11 -0
  22. data/ext/minisat/extconf.rb +9 -0
  23. data/ext/minisat/minisat-wrap.cpp +88 -0
  24. data/ext/minisat/minisat.c +497 -0
  25. data/ext/minisat/minisat.h +53 -0
  26. data/minisat/MiniSat_v1.14.2006-Aug-29.src.zip +0 -0
  27. data/minisat/MiniSat_v1.14/Global.h +274 -0
  28. data/minisat/MiniSat_v1.14/Heap.h +100 -0
  29. data/minisat/MiniSat_v1.14/LICENSE +20 -0
  30. data/minisat/MiniSat_v1.14/Main.C +244 -0
  31. data/minisat/MiniSat_v1.14/Makefile +88 -0
  32. data/minisat/MiniSat_v1.14/README +30 -0
  33. data/minisat/MiniSat_v1.14/Solver.C +781 -0
  34. data/minisat/MiniSat_v1.14/Solver.h +206 -0
  35. data/minisat/MiniSat_v1.14/Solver.o +0 -0
  36. data/minisat/MiniSat_v1.14/SolverTypes.h +130 -0
  37. data/minisat/MiniSat_v1.14/Sort.h +131 -0
  38. data/minisat/MiniSat_v1.14/TODO +73 -0
  39. data/minisat/MiniSat_v1.14/VarOrder.h +96 -0
  40. data/test/test_minisat.rb +143 -0
  41. metadata +114 -0
data/.gitignore ADDED
@@ -0,0 +1,24 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ lib
23
+ *.gemspec
24
+ tmp
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson
2
+ ruby-minisat -- Copyright (c) 2007,2010 Yusuke Endoh
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a
5
+ copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included
13
+ in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,56 @@
1
+ = ruby-minisat
2
+
3
+ ruby-minisat is ruby binding for MiniSat, which is an open-source SAT solver.
4
+
5
+ == Installation
6
+
7
+ $ gem install ruby-minisat
8
+
9
+ == How to Use
10
+
11
+ A brief example that solves a simple SAT problem:
12
+
13
+ # solve (a or b) and (not a or b) and (a or not b)
14
+
15
+ require "minisat"
16
+ solver = MiniSat::Solver.new
17
+
18
+ a = solver.new_var
19
+ b = solver.new_var
20
+
21
+ solver << [a, b] << [-a, b] << [a, -b]
22
+
23
+ p solver.solve #=> true (satisfiable)
24
+
25
+ p solver[a] #=> true
26
+ p solver[b] #=> true
27
+
28
+ For more examples, see the examples directory in the distribution.
29
+
30
+ == Copyright
31
+
32
+ ruby-minisat is covered under the MIT License.
33
+ This package includes MiniSat in the directory minisat/*, which is also
34
+ distributed under the MIT License.
35
+
36
+
37
+ MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson
38
+ ruby-minisat -- Copyright (c) 2007,2010 Yusuke Endoh
39
+
40
+ Permission is hereby granted, free of charge, to any person obtaining a copy
41
+ of this software and associated documentation files (the "Software"), to deal
42
+ in the Software without restriction, including without limitation the rights
43
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
44
+ copies of the Software, and to permit persons to whom the Software is
45
+ furnished to do so, subject to the following conditions:
46
+
47
+ The above copyright notice and this permission notice shall be included in
48
+ all copies or substantial portions of the Software.
49
+
50
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
51
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
52
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
53
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
54
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
55
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
56
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ jeweler_tasks = Jeweler::Tasks.new do |gem|
7
+ gem.name = "ruby-minisat"
8
+ gem.summary = %Q{ruby binding for MiniSat, which is an open-source SAT solver}
9
+ gem.description = gem.summary
10
+ gem.email = "mame@tsg.ne.jp"
11
+ gem.homepage = "http://github.com/mame/ruby-minisat"
12
+ gem.authors = ["Yusuke Endoh"]
13
+ gem.extensions = FileList['ext/**/extconf.rb']
14
+ gem.files.include FileList['ext/**/*', 'minisat/**/*/**']
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/test_*.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ task :test => :check_dependencies
29
+
30
+ task :default => :test
31
+
32
+ require 'rake/rdoctask'
33
+ Rake::RDocTask.new do |rdoc|
34
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
35
+
36
+ rdoc.rdoc_dir = 'rdoc'
37
+ rdoc.title = "ruby-minisat #{version}"
38
+ rdoc.rdoc_files.include('README*')
39
+ rdoc.rdoc_files.include('ext/**/*.c')
40
+ end
41
+
42
+ begin
43
+ require 'rake/extensiontask'
44
+ require 'rake/extensiontesttask'
45
+
46
+ Rake::ExtensionTask.new('minisat', jeweler_tasks.gemspec)
47
+ rescue LoadError
48
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.14.2
@@ -0,0 +1,65 @@
1
+ if RUBY_VERSION < "1.9.0"
2
+ require "enumerator"
3
+ class Array
4
+ def permutation(n = nil, ary = [])
5
+ n = size unless n
6
+ if n == 0
7
+ yield ary
8
+ else
9
+ each_with_index do |x, i|
10
+ (self[0 ... i] + self[i + 1 .. -1]).
11
+ permutation(n - 1, ary + [x]) {|r| yield r }
12
+ end
13
+ end
14
+ end
15
+ def combination(n)
16
+ if n == 0
17
+ yield []
18
+ else
19
+ (0 .. size - n).each do |i|
20
+ self[i + 1 ... size].combination(n - 1) do |ary|
21
+ yield [self[i]] + ary
22
+ end
23
+ end
24
+ end
25
+ end
26
+ def product(ary)
27
+ result = []
28
+ self.each do |i|
29
+ ary.each do |j|
30
+ result << [i, j]
31
+ end
32
+ end
33
+ result
34
+ end
35
+ alias flatten_org flatten
36
+ def flatten(i = nil)
37
+ if i
38
+ a = self
39
+ i.times do
40
+ r = []
41
+ a.each do |x|
42
+ x.is_a?(Array) ? r += x : r << x
43
+ end
44
+ a = r
45
+ end
46
+ a
47
+ else
48
+ flatten_org
49
+ end
50
+ end
51
+ end
52
+
53
+ class Range
54
+ alias step_org step
55
+ def step(s)
56
+ if block_given?
57
+ step_org(s) {|x| yield x }
58
+ else
59
+ a = []
60
+ step_org(s) {|x| a << x }
61
+ a
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # ruby-minisat example -- example.rb
4
+
5
+ require "minisat"
6
+
7
+ # initialize solver
8
+ solver = MiniSat::Solver.new
9
+
10
+ # make variable
11
+ a = solver.new_var
12
+ b = solver.new_var
13
+
14
+ # input CNF to solver: (a or b) and (not a or b) and (a or not b)
15
+ solver << [a, b] << [-a, b] << [a, -b]
16
+
17
+ # solve SAT (return true if solvable)
18
+ puts "solve: (a or b) and (not a or b) and (a or not b)"
19
+ solver.solve
20
+
21
+ # output results
22
+ puts("result: " + (solver.satisfied? ? "SAT" : "UNSAT")) #=> SAT
23
+ if solver.satisfied?
24
+ puts "a = #{ solver[a].inspect }" #=> a = true
25
+ puts "b = #{ solver[b].inspect }" #=> a = false
26
+ end
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # ruby-minisat example -- example2.rb
4
+
5
+ require "minisat"
6
+
7
+ # initialize solver
8
+ solver = MiniSat::Solver.new
9
+
10
+ # make variable
11
+ a = solver.new_var
12
+ b = solver.new_var
13
+
14
+ # input CNF to solver: (a or b) and (not a or b) and (a or not b)
15
+ solver << [a, b] << [-a, b] << [a, -b]
16
+
17
+ # solve SAT (return true if solvable)
18
+ p solver
19
+ puts "solve: (a or b) and (not a or b) and (a or not b)"
20
+ solver.solve
21
+ p solver
22
+
23
+ # output results
24
+ puts("result: " + (solver.satisfied? ? "SAT" : "UNSAT")) #=> SAT
25
+ if solver.satisfied?
26
+ puts "a = #{ solver[a].inspect }" #=> a = true
27
+ puts "b = #{ solver[b].inspect }" #=> a = false
28
+ end
29
+ puts
30
+
31
+
32
+ # solve SAT with assumption
33
+ puts "solve: (a or b) and (not a or b) and (a or not b)"
34
+ puts "assumption: a = false"
35
+ solver.solve(-a) #=> false
36
+ p solver
37
+
38
+ # output results
39
+ puts("result: " + (solver.satisfied? ? "SAT" : "UNSAT")) #=> UNSAT
40
+ if solver.satisfied?
41
+ puts "a = #{ solver[a].inspect }"
42
+ puts "b = #{ solver[b].inspect }"
43
+ end
44
+ puts
45
+
46
+
47
+ # input additonal CNF to solver: ... and (not a or not b)
48
+ solver << [-a, -b]
49
+ p solver #=> trivially unsatisfiable
50
+
51
+ # solve SAT (return true if solvable)
52
+ puts "solve: (a or b) and (not a or b) and (a or not b) and (not a or not b)"
53
+ solver.solve
54
+
55
+ # output results
56
+ puts("result: " + (solver.satisfied? ? "SAT" : "UNSAT")) #=> UNSAT
57
+ if solver.satisfied?
58
+ puts "a = #{ solver[a].inspect }"
59
+ puts "b = #{ solver[b].inspect }"
60
+ end
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # ruby-minisat example -- kakuro.rb
4
+ # ref: http://en.wikipedia.org/wiki/Kakuro
5
+
6
+ ##
7
+ ## SAT configuration:
8
+ ## - Variables: 9 variables for number to each blank cell
9
+ ## - Clauses: sum of each entry is specified
10
+ ##
11
+
12
+ require "minisat"
13
+ require File.dirname($0) + "/compat18" if RUBY_VERSION < "1.9.0"
14
+
15
+
16
+ def error(msg)
17
+ $stderr.puts msg
18
+ exit 1
19
+ end
20
+
21
+
22
+ def parse_file(file)
23
+ width = nil
24
+ field = []
25
+ File.read(file).split(/\n/).each do |line|
26
+ next if line[/^\s*#/]
27
+ field << (line + " ").
28
+ scan(/\G(?:(\*\*|\d+)\\(\*\*|\d+)|(\.))(?:\s+|$)/).
29
+ map {|v, h, b| b ? nil : [v.to_i, h.to_i] }
30
+ end
31
+ field
32
+ end
33
+
34
+
35
+ def define_sat(solver, field)
36
+ # define variables
37
+ vars = field.map do |line|
38
+ line.map do |c|
39
+ next if c
40
+ vs = (1..9).map { solver.new_var }
41
+ solver << vs
42
+ vs.combination(2) {|v1, v2| solver << [-v1, -v2] }
43
+ vs
44
+ end
45
+ end
46
+
47
+ # define clauses
48
+ define_entries(solver, field , vars ) {|c| c.last }
49
+ define_entries(solver, field.transpose, vars.transpose) {|c| c.first }
50
+
51
+ vars
52
+ end
53
+
54
+ def define_entries(solver, field, vars)
55
+ field.zip(vars) do |fline, vline|
56
+ num = nil
57
+ ary = []
58
+ fline.zip(vline) do |c, vs|
59
+ if c
60
+ define_entry(solver, num, ary)
61
+ num, ary = (yield c), []
62
+ else
63
+ ary << vs
64
+ end
65
+ end
66
+ define_entry(solver, num, ary)
67
+ end
68
+ end
69
+
70
+ # define constraints for entry
71
+ def define_entry(solver, num, ary)
72
+ return unless num && !ary.empty?
73
+ h = {}
74
+ enum_entry(num, ary.size, 1, []) do |is|
75
+ (0 ... is.size).each do |n|
76
+ h[is[0...n]] ||= []
77
+ h[is[0...n]] |= [is[n]]
78
+ end
79
+ end
80
+ error "bad field" if h.empty?
81
+ h.each do |bs, as|
82
+ a = bs.zip(ary).map {|i, vs| -vs[i - 1] }
83
+ a += as.map {|i| ary[bs.size][i - 1] }
84
+ solver << a
85
+ end
86
+ end
87
+
88
+ # enumerate possible numbers for entry
89
+ # enum_entry(8, 2) -> [1, 7], [2, 6], [3, 5] and these permutations
90
+ # enum_entry(9, 3) -> [1, 2, 6], [1, 3, 5], [2, 3, 4] and these permutations
91
+ def enum_entry(num, count, start = 1, ary = [])
92
+ if count == 0
93
+ ary.permutation {|r| yield r } if num == 0
94
+ else
95
+ (start .. 9).each do |x|
96
+ break if num < x
97
+ enum_entry(num - x, count - 1, x + 1, ary + [x]) {|r| yield r }
98
+ end
99
+ end
100
+ end
101
+
102
+
103
+ def solve_sat(solver)
104
+ start = Time.now
105
+ result = solver.solve
106
+ eplise = Time.now - start
107
+ puts "time: %.6f sec." % eplise
108
+ result
109
+ end
110
+
111
+
112
+ def make_solution(solver, vars)
113
+ vars.map {|line| line.map {|vs| (1..9).find {|i| solver[vs[i - 1]]} if vs } }
114
+ end
115
+
116
+
117
+ def add_constraint(solver, vars)
118
+ solver << vars.flatten.compact.map {|v| solver[v] ? -v : v }
119
+ end
120
+
121
+
122
+ def output_field(solution, field)
123
+ field.zip(solution) do |fline, sline|
124
+ line = fline.zip(sline).map do |c, s|
125
+ if c
126
+ f = c.first == 0 ? "##" : "%02d" % c.first
127
+ s = c.last == 0 ? "##" : "%02d" % c.last
128
+ f + "\\" + s
129
+ else
130
+ s.to_s.center(5)
131
+ end
132
+ end.join(" ")
133
+ puts line
134
+ end
135
+ end
136
+
137
+
138
+
139
+ error "usage: kakuro.rb kakuro.sample" if ARGV.empty?
140
+
141
+ ARGV.each do |file|
142
+ field = parse_file(file)
143
+
144
+ solver = MiniSat::Solver.new
145
+
146
+ puts "defining SAT..."
147
+ vars = define_sat(solver, field)
148
+ puts "variables : #{ solver.var_size }"
149
+ puts "clauses : #{ solver.clause_size }"
150
+ puts
151
+
152
+ puts "solving SAT..."
153
+ result = solve_sat(solver)
154
+ puts "result: " + (result ? "solvable" : "unsolvable")
155
+ puts
156
+ next unless result
157
+
158
+ puts "translating model into solution..."
159
+ solution = make_solution(solver, vars)
160
+ puts "solution found:"
161
+ output_field(solution, field)
162
+ puts
163
+
164
+ puts "checking different solution..."
165
+ add_constraint(solver, vars)
166
+ result = solve_sat(solver)
167
+ puts "result: " +
168
+ (result ? "different solution found" : "different solution not found")
169
+ puts
170
+ next unless result
171
+
172
+ puts "translating model into solution..."
173
+ solution = make_solution(solver, vars)
174
+ puts "different solution:"
175
+ output_field(solution, field)
176
+ puts
177
+ puts
178
+ end