ricosat 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,194 @@
1
+ #include <ruby.h>
2
+ #include <ruby/io.h>
3
+ #include <picosat.h>
4
+
5
+ VALUE cRicoSat;
6
+
7
+ static const rb_data_type_t RicoSatType = {
8
+ "RicoStat",
9
+ { 0, (void (*)(void *))picosat_reset, 0 },
10
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
11
+ };
12
+
13
+ static VALUE allocate(VALUE klass) {
14
+ return TypedData_Wrap_Struct(klass, &RicoSatType, picosat_init());
15
+ }
16
+
17
+ static VALUE measure_all_calls(VALUE self) {
18
+ PicoSAT * sat;
19
+
20
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
21
+ picosat_measure_all_calls(sat);
22
+ return self;
23
+ }
24
+
25
+ static VALUE set_verbosity(VALUE self, VALUE verbosity) {
26
+ PicoSAT * sat;
27
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
28
+ picosat_set_verbosity(sat, NUM2INT(verbosity));
29
+ return self;
30
+ }
31
+
32
+ static VALUE set_more_important_lit(VALUE self, VALUE lit) {
33
+ PicoSAT * sat;
34
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
35
+ picosat_set_more_important_lit(sat, NUM2INT(lit));
36
+ return self;
37
+ }
38
+
39
+ static VALUE set_less_important_lit(VALUE self, VALUE lit) {
40
+ PicoSAT * sat;
41
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
42
+ picosat_set_less_important_lit(sat, NUM2INT(lit));
43
+ return self;
44
+ }
45
+
46
+ static VALUE inc_max_var(VALUE self) {
47
+ PicoSAT * sat;
48
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
49
+ return INT2NUM(picosat_inc_max_var(sat));
50
+ }
51
+
52
+ static VALUE add(VALUE self, VALUE lit) {
53
+ PicoSAT * sat;
54
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
55
+ return INT2NUM(picosat_add(sat, NUM2INT(lit)));
56
+ }
57
+
58
+ static VALUE solve(VALUE self, VALUE limit) {
59
+ PicoSAT * sat;
60
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
61
+ return INT2NUM(picosat_sat(sat, NUM2INT(limit)));
62
+ }
63
+
64
+ static VALUE deref(VALUE self, VALUE lit) {
65
+ PicoSAT * sat;
66
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
67
+ switch(picosat_deref(sat, NUM2INT(lit))) {
68
+ case 1:
69
+ return Qtrue;
70
+ case -1:
71
+ return Qfalse;
72
+ case 0:
73
+ return Qnil;
74
+ }
75
+ return Qnil;
76
+ }
77
+
78
+ static VALUE failed_assumptions(VALUE self) {
79
+ PicoSAT * sat;
80
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
81
+
82
+ VALUE failed_list = rb_ary_new();
83
+ const int * failed = picosat_failed_assumptions(sat);
84
+ while(*failed) {
85
+ rb_ary_push(failed_list, INT2NUM(*failed));
86
+ failed++;
87
+ }
88
+ return failed_list;
89
+ }
90
+
91
+ static VALUE failed_assumption(VALUE self, VALUE lit) {
92
+ PicoSAT * sat;
93
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
94
+
95
+ if (picosat_failed_assumption(sat, NUM2INT(lit))) {
96
+ return Qtrue;
97
+ } else {
98
+ return Qfalse;
99
+ }
100
+ }
101
+
102
+ static VALUE assume(VALUE self, VALUE lit) {
103
+ PicoSAT * sat;
104
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
105
+ picosat_assume(sat, NUM2INT(lit));
106
+ return self;
107
+ }
108
+
109
+ static VALUE variables(VALUE self) {
110
+ PicoSAT * sat;
111
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
112
+ return INT2NUM(picosat_variables(sat));
113
+ }
114
+
115
+ static VALUE enable_trace_generation(VALUE self)
116
+ {
117
+ PicoSAT * sat;
118
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
119
+ return INT2NUM(picosat_enable_trace_generation(sat));
120
+ }
121
+
122
+ static VALUE write_extended_trace(VALUE self, VALUE io)
123
+ {
124
+ PicoSAT * sat;
125
+ rb_io_t * out;
126
+
127
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
128
+ GetOpenFile(io, out);
129
+ picosat_write_extended_trace(sat, fdopen(out->fd, "w"));
130
+ return self;
131
+ }
132
+
133
+ static VALUE corelit(VALUE self, VALUE lit)
134
+ {
135
+ PicoSAT * sat;
136
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
137
+ return INT2NUM(picosat_corelit(sat, NUM2INT(lit)));
138
+ }
139
+
140
+ static VALUE coreclause(VALUE self, VALUE i)
141
+ {
142
+ PicoSAT * sat;
143
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
144
+ return INT2NUM(picosat_coreclause(sat, NUM2INT(i)));
145
+ }
146
+
147
+ static VALUE added_original_clauses(VALUE self)
148
+ {
149
+ PicoSAT * sat;
150
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
151
+ return INT2NUM(picosat_added_original_clauses(sat));
152
+ }
153
+
154
+ static VALUE set_global_default_phase(VALUE self, VALUE val)
155
+ {
156
+ PicoSAT * sat;
157
+ TypedData_Get_Struct(self, PicoSAT, &RicoSatType, sat);
158
+ picosat_set_global_default_phase(sat, NUM2INT(val));
159
+ return self;
160
+ }
161
+
162
+ void error_cb(const char *m) {
163
+ rb_raise(rb_eRuntimeError, "%s", m);
164
+ }
165
+
166
+ void Init_ricosat() {
167
+ cRicoSat = rb_define_class("RicoSAT", rb_cObject);
168
+ rb_define_alloc_func(cRicoSat, allocate);
169
+ picosat_set_error_handler(error_cb);
170
+
171
+ rb_define_const(cRicoSat, "UNKNOWN", INT2NUM(PICOSAT_UNKNOWN));
172
+ rb_define_const(cRicoSat, "SATISFIABLE", INT2NUM(PICOSAT_SATISFIABLE));
173
+ rb_define_const(cRicoSat, "UNSATISFIABLE", INT2NUM(PICOSAT_UNSATISFIABLE));
174
+ rb_define_method(cRicoSat, "measure_all_calls", measure_all_calls, 0);
175
+ rb_define_method(cRicoSat, "verbosity=", set_verbosity, 1);
176
+ rb_define_method(cRicoSat, "more_important_lit", set_more_important_lit, 1);
177
+ rb_define_method(cRicoSat, "less_important_lit", set_less_important_lit, 1);
178
+ rb_define_method(cRicoSat, "inc_max_var", inc_max_var, 0);
179
+ rb_define_method(cRicoSat, "add", add, 1);
180
+ rb_define_method(cRicoSat, "solve", solve, 1);
181
+ rb_define_method(cRicoSat, "deref", deref, 1);
182
+ rb_define_method(cRicoSat, "failed_assumptions", failed_assumptions, 0);
183
+ rb_define_method(cRicoSat, "assume", assume, 1);
184
+ rb_define_method(cRicoSat, "variables", variables, 0);
185
+ rb_define_method(cRicoSat, "failed_assumption", failed_assumption, 1);
186
+ rb_define_method(cRicoSat, "enable_trace_generation", enable_trace_generation, 0);
187
+ rb_define_method(cRicoSat, "write_extended_trace", write_extended_trace, 1);
188
+ rb_define_method(cRicoSat, "corelit", corelit, 1);
189
+ rb_define_method(cRicoSat, "coreclause", coreclause, 1);
190
+ rb_define_method(cRicoSat, "added_original_clauses", added_original_clauses, 0);
191
+ rb_define_method(cRicoSat, "global_default_phase=", set_global_default_phase, 1);
192
+ }
193
+
194
+ /* vim: set sws=4 noet: */
Binary file
data/lib/ricosat.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'ricosat.so'
2
+
3
+ class RicoSAT
4
+ VERSION = '1.0.0'
5
+ end
@@ -0,0 +1,140 @@
1
+ require 'minitest/autorun'
2
+ require 'tempfile'
3
+ require 'ricosat'
4
+
5
+ class TestRicosat < MiniTest::Test
6
+ def test_sanity
7
+ assert RicoSAT.new
8
+ end
9
+
10
+ def test_measure_all_calls
11
+ assert RicoSAT.new.measure_all_calls
12
+ end
13
+
14
+ def test_set_verbosity
15
+ sat = RicoSAT.new
16
+ sat.verbosity = 2
17
+ end
18
+
19
+ def test_int_max_var
20
+ sat = RicoSAT.new
21
+ assert_equal 1, sat.inc_max_var
22
+ assert_equal 2, sat.inc_max_var
23
+ assert_equal 3, sat.inc_max_var
24
+ end
25
+
26
+ def test_enable_trace
27
+ sat = RicoSAT.new
28
+ assert sat.enable_trace_generation
29
+ sat.add(1); sat.add(0)
30
+ assert_raises do
31
+ sat.write_extended_trace $stdout
32
+ end
33
+ sat.add(-1); sat.add(0)
34
+ sat.solve(-1)
35
+ f = Tempfile.new('trace')
36
+ assert sat.write_extended_trace File.open(f.path, 'w')
37
+ f.unlink
38
+ end
39
+
40
+ def test_added_original_clauses
41
+ sat = RicoSAT.new
42
+ sat.add(1); sat.add(0)
43
+ assert_equal 1, sat.added_original_clauses
44
+ sat.add(1); sat.add(0)
45
+ assert_equal 2, sat.added_original_clauses
46
+ end
47
+
48
+ def test_add_returns_current_clause
49
+ sat = RicoSAT.new
50
+ assert_equal 0, sat.add(1)
51
+ assert_equal 0, sat.add(0)
52
+ assert_equal 1, sat.add(1)
53
+ assert_equal 1, sat.add(0)
54
+ end
55
+
56
+ # A -> [B, C]
57
+ # B -> [D, =1]
58
+ # C -> [D, =2]
59
+ def test_diamond
60
+ sat = RicoSAT.new
61
+ sat.enable_trace_generation
62
+ sat.add(1); sat.add(0) # A -> [B & C]
63
+ sat.add(2); sat.add(-1); sat.add(0) # B | !A
64
+ sat.add(3); sat.add(-1); sat.add(0) # C | !A
65
+ sat.add(4); sat.add(-2); sat.add(0) # D | !B
66
+ sat.add(4); sat.add(-3); sat.add(0) # D | !C
67
+ sat.add(-4); sat.add(5); sat.add(0) # Dv1 | !D
68
+ sat.add(-4); sat.add(-6); sat.add(0) # Dv1 | !D
69
+ sat.add(-4); sat.add(6); sat.add(0) # Dv2 | !D
70
+ sat.add(-4); sat.add(-5); sat.add(0) # Dv2 | !D
71
+ assert_equal RicoSAT::UNSATISFIABLE, sat.solve(-1)
72
+ end
73
+
74
+ def test_extended_trace
75
+ sat = RicoSAT.new
76
+ sat.enable_trace_generation
77
+ sat.add(1); sat.add(0)
78
+ sat.add(2); sat.add(0)
79
+ sat.add(-1); sat.add(2); sat.add(0)
80
+ sat.add(-1); sat.add(2); sat.add(0)
81
+ sat.add(-2); sat.add(-1); sat.add(0)
82
+ assert_equal RicoSAT::UNSATISFIABLE, sat.solve(-1)
83
+ # find core clauses that couldn't be solved
84
+ x = sat.added_original_clauses.times.find_all do |i|
85
+ sat.coreclause(i) == 1
86
+ end
87
+ assert_equal [0, 1, 4], x
88
+ # sat.write_extended_trace $stdout
89
+ end
90
+
91
+ def test_deref_fail
92
+ sat = RicoSAT.new
93
+ sat.assume 1
94
+ sat.assume 2
95
+ sat.add(-1); sat.add(2); sat.add(0)
96
+ sat.add(-2); sat.add(0)
97
+ assert_equal RicoSAT::UNSATISFIABLE, sat.solve(-1)
98
+ assert sat.failed_assumption 1
99
+ assert_equal [1], sat.failed_assumptions
100
+
101
+ assert_raises do
102
+ sat.deref 1
103
+ end
104
+ end
105
+
106
+ def test_deref_success
107
+ sat = RicoSAT.new
108
+ sat.add(1); sat.add(0)
109
+ sat.add(-1); sat.add(2); sat.add(0)
110
+ assert_equal RicoSAT::SATISFIABLE, sat.solve(-1)
111
+
112
+ assert_equal [true, true], [1, 2].map { |i| sat.deref i }
113
+ end
114
+
115
+ def test_solve
116
+ sat = RicoSAT.new
117
+ sat.add(1); sat.add(0)
118
+ sat.add(-1); sat.add(2); sat.add(0)
119
+ assert_equal RicoSAT::SATISFIABLE, sat.solve(-1)
120
+ end
121
+
122
+ def test_add
123
+ sat = RicoSAT.new
124
+ #sat.add(-2); sat.add(0)
125
+ sat.add(-1); sat.add(-3); sat.add(0)
126
+ sat.add(1); sat.add(2); sat.add(0)
127
+ sat.add(2); sat.add(3); sat.add(0)
128
+ case sat.solve(-1)
129
+ when RicoSAT::SATISFIABLE
130
+ assert sat.deref(2)
131
+ refute sat.deref(-2)
132
+ assert sat.deref(-3)
133
+ assert sat.deref(-1)
134
+ when RicoSAT::UNSATISFIABLE
135
+ flunk "should be satisfiable"
136
+ when RicoSAT::UNKNOWN
137
+ flunk "should be satisfiable"
138
+ end
139
+ end
140
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ricosat
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Aaron Patterson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-02-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.9'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rdoc
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: hoe
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.16'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.16'
55
+ description: |-
56
+ RicoSAT is a wrapper around [PicoSAT](http://fmv.jku.at/picosat/). It lets
57
+ you use the PicoSAT solver from Ruby!
58
+ email:
59
+ - aaron@tenderlovemaking.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files:
63
+ - CHANGELOG.md
64
+ - Manifest.txt
65
+ - README.md
66
+ files:
67
+ - CHANGELOG.md
68
+ - Manifest.txt
69
+ - README.md
70
+ - Rakefile
71
+ - ext/ricosat/extconf.rb
72
+ - ext/ricosat/picosat.c
73
+ - ext/ricosat/picosat.h
74
+ - ext/ricosat/ricosat.c
75
+ - lib/ricosat.bundle
76
+ - lib/ricosat.rb
77
+ - test/test_ricosat.rb
78
+ homepage: https://github.com/tenderlove/ricosat
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options:
84
+ - "--main"
85
+ - README.md
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.6.10
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: RicoSAT is a wrapper around [PicoSAT](http://fmv.jku.at/picosat/)
104
+ test_files: []