ricosat 1.0.0

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.
@@ -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: []