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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +6 -0
- data/Manifest.txt +11 -0
- data/README.md +92 -0
- data/Rakefile +23 -0
- data/ext/ricosat/extconf.rb +3 -0
- data/ext/ricosat/picosat.c +8513 -0
- data/ext/ricosat/picosat.h +665 -0
- data/ext/ricosat/ricosat.c +194 -0
- data/lib/ricosat.bundle +0 -0
- data/lib/ricosat.rb +5 -0
- data/test/test_ricosat.rb +140 -0
- metadata +104 -0
@@ -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: */
|
data/lib/ricosat.bundle
ADDED
Binary file
|
data/lib/ricosat.rb
ADDED
@@ -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: []
|