ravensat 0.1.1 → 0.2.1
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/Gemfile.lock +1 -1
- data/README.md +7 -6
- data/example/magic_square_3x3.rb +48 -0
- data/lib/ravensat/ast/and_node.rb +4 -0
- data/lib/ravensat/ast/node.rb +51 -0
- data/lib/ravensat/ast/not_node.rb +4 -0
- data/lib/ravensat/ast/opr_node.rb +7 -0
- data/lib/ravensat/ast/or_node.rb +8 -0
- data/lib/ravensat/ast/var_node.rb +17 -0
- data/lib/ravensat/dimacs_decoder.rb +24 -0
- data/lib/ravensat/dimacs_encoder.rb +32 -0
- data/lib/ravensat/solver.rb +4 -12
- data/lib/ravensat/version.rb +1 -1
- data/lib/ravensat.rb +10 -2
- metadata +11 -4
- data/lib/ravensat/prop_logic.rb +0 -92
- data/lib/ravensat/prop_var.rb +0 -45
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 76d71945818d257f977fde25685896cc7e8c7da0d290f329525beb5d7e5c2ca2
|
4
|
+
data.tar.gz: 2c201e0b4815822e40f7b15fe8b1492a532c6665bc456a87c8c6f42227468f38
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a25a24ca9553e5ea66737f21d5cf9942b9202f106f3c0063d3a4fa84816b665797a761ac2399ef0de374e36bfa29a23c5dccaf7f78f0adfa73cd9e45558e591
|
7
|
+
data.tar.gz: 74baa2d28e39e50dca6d280a411cc0fd5727f15dca74ada2ec94eb4a1c1c7d785e686293de0202d0e249c03a78685be3c823917519936d79438740c0bd861b90
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# Ravensat
|
2
2
|
|
3
|
-
|
3
|
+
Ravensat is an interface to SAT Solver .
|
4
|
+
In order to use Ravensat, you need to install SAT Solver and specify the name of the Solver .
|
5
|
+
(If you do not specify SAT Solver, it will use the one bundled in the gem .)
|
4
6
|
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
6
7
|
|
7
|
-
## Installation
|
8
|
+
## Installation
|
8
9
|
|
9
10
|
Add this line to your application's Gemfile:
|
10
11
|
|
@@ -25,8 +26,8 @@ Or install it yourself as:
|
|
25
26
|
```ruby
|
26
27
|
require 'ravensat'
|
27
28
|
|
28
|
-
a = Ravensat::
|
29
|
-
b = Ravensat::
|
29
|
+
a = Ravensat::VarNode.new
|
30
|
+
b = Ravensat::VarNode.new
|
30
31
|
|
31
32
|
a.value #=> nil
|
32
33
|
b.value #=> nil
|
@@ -40,7 +41,7 @@ a.value #=> true
|
|
40
41
|
b.value #=> true
|
41
42
|
```
|
42
43
|
|
43
|
-
## Development
|
44
|
+
## Development
|
44
45
|
|
45
46
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
46
47
|
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'ravensat'
|
3
|
+
require 'pry'
|
4
|
+
|
5
|
+
# | ---- | ---- | ---- |
|
6
|
+
# | X1 | X2 | X3 |
|
7
|
+
# | X4 | X5 | X6 |
|
8
|
+
# | X7 | X8 | X9 |
|
9
|
+
# | ---- | ---- | ---- |
|
10
|
+
|
11
|
+
x1 = Array.new(9){ Ravensat::VarNode.new }
|
12
|
+
x2 = Array.new(9){ Ravensat::VarNode.new }
|
13
|
+
x3 = Array.new(9){ Ravensat::VarNode.new }
|
14
|
+
x4 = Array.new(9){ Ravensat::VarNode.new }
|
15
|
+
x5 = Array.new(9){ Ravensat::VarNode.new }
|
16
|
+
x6 = Array.new(9){ Ravensat::VarNode.new }
|
17
|
+
x7 = Array.new(9){ Ravensat::VarNode.new }
|
18
|
+
x8 = Array.new(9){ Ravensat::VarNode.new }
|
19
|
+
x9 = Array.new(9){ Ravensat::VarNode.new }
|
20
|
+
x = [x1, x2, x3, x4, x5, x6, x7, x8, x9]
|
21
|
+
|
22
|
+
logic = x1[4]
|
23
|
+
|
24
|
+
# one square, one number
|
25
|
+
9.times do |i|
|
26
|
+
logic &= Ravensat::RavenClaw.alo [x[i][0], x[i][1], x[i][2], x[i][3], x[i][4], x[i][5], x[i][6], x[i][7], x[i][8]]
|
27
|
+
logic &= Ravensat::RavenClaw.amo [x[i][0], x[i][1], x[i][2], x[i][3], x[i][4], x[i][5], x[i][6], x[i][7], x[i][8]]
|
28
|
+
end
|
29
|
+
|
30
|
+
# x1 ~ x9 are all different numbers
|
31
|
+
9.times do |i|
|
32
|
+
logic &= Ravensat::RavenClaw.alo [x[0][i], x[1][i], x[2][i], x[3][i], x[4][i], x[5][i], x[6][i], x[7][i], x[8][i]]
|
33
|
+
logic &= Ravensat::RavenClaw.amo [x[0][i], x[1][i], x[2][i], x[3][i], x[4][i], x[5][i], x[6][i], x[7][i], x[8][i]]
|
34
|
+
end
|
35
|
+
|
36
|
+
# TODO: generate constraint that sum to 15 in a row
|
37
|
+
# sum to 15 in a row
|
38
|
+
|
39
|
+
solver = Ravensat::Solver.new
|
40
|
+
solver.solve logic
|
41
|
+
|
42
|
+
puts <<~"MAGIC_SQUARE"
|
43
|
+
| --- | --- | --- |
|
44
|
+
| #{x1.index{|x| x.value} + 1} | #{x2.index{|x| x.value} + 1} | #{x3.index{|x| x.value} + 1} |
|
45
|
+
| #{x4.index{|x| x.value} + 1} | #{x5.index{|x| x.value} + 1} | #{x6.index{|x| x.value} + 1} |
|
46
|
+
| #{x7.index{|x| x.value} + 1} | #{x8.index{|x| x.value} + 1} | #{x9.index{|x| x.value} + 1} |
|
47
|
+
| --- | --- | --- |
|
48
|
+
MAGIC_SQUARE
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Ravensat
|
2
|
+
class Node
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_reader :children
|
6
|
+
def initialize
|
7
|
+
@children = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def each
|
11
|
+
yield(self)
|
12
|
+
@children.each do |child|
|
13
|
+
child.each {|c| yield(c)}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def &(object)
|
18
|
+
AndNode.new(self, object)
|
19
|
+
end
|
20
|
+
|
21
|
+
def |(object)
|
22
|
+
OrNode.new(self, object)
|
23
|
+
end
|
24
|
+
|
25
|
+
# def tree_text
|
26
|
+
# self.each do |child|
|
27
|
+
# child.to_s
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
self.class.name
|
33
|
+
end
|
34
|
+
|
35
|
+
def cnf?
|
36
|
+
@children.map(&:cnf?).reduce(:&)
|
37
|
+
end
|
38
|
+
|
39
|
+
def vars
|
40
|
+
self.select{|node| node.is_a? VarNode}.uniq
|
41
|
+
end
|
42
|
+
|
43
|
+
def vars_size
|
44
|
+
self.vars.size
|
45
|
+
end
|
46
|
+
|
47
|
+
def clauses_size
|
48
|
+
self.count{|node| node.is_a? AndNode} + 1
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Ravensat
|
2
|
+
class DimacsDecoder
|
3
|
+
def decode(model, name_table)
|
4
|
+
inverted_name_table = name_table.invert
|
5
|
+
case model.first
|
6
|
+
when "SAT"
|
7
|
+
model.last.split.each do |e|
|
8
|
+
if e == '0'
|
9
|
+
next
|
10
|
+
elsif e[0] == "-"
|
11
|
+
index = e.slice(1..-1)
|
12
|
+
inverted_name_table[index].value = false
|
13
|
+
else
|
14
|
+
index = e
|
15
|
+
inverted_name_table[index].value = true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
true
|
19
|
+
when "UNSAT"
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Ravensat
|
2
|
+
class DimacsEncoder
|
3
|
+
attr_reader :name_table
|
4
|
+
def initialize
|
5
|
+
@name_table = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_dimacs(formula)
|
9
|
+
return nil unless formula.cnf?
|
10
|
+
|
11
|
+
dimacs_header = "p cnf #{formula.vars_size} #{formula.clauses_size}"
|
12
|
+
dimacs_body = ""
|
13
|
+
create_table(formula)
|
14
|
+
formula.each do |node|
|
15
|
+
case node
|
16
|
+
when AndNode
|
17
|
+
when OrNode then dimacs_body << "\n"
|
18
|
+
when NotNode then dimacs_body << "-"
|
19
|
+
when VarNode then dimacs_body << @name_table[node] << " "
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
dimacs_body.gsub!(/\n{2,}/, "\n").gsub!(/\n/, "0\n") << '0'
|
24
|
+
|
25
|
+
dimacs_header + dimacs_body
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_table(formula)
|
29
|
+
@name_table = formula.vars.zip((1..formula.vars.size).map(&:to_s)).to_h
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/ravensat/solver.rb
CHANGED
@@ -15,10 +15,11 @@ module Ravensat
|
|
15
15
|
# end
|
16
16
|
|
17
17
|
def solve( cnf )
|
18
|
+
encoder = DimacsEncoder.new
|
18
19
|
@input_file = Tempfile.open(["ravensat",".cnf"])
|
19
20
|
@output_file = Tempfile.open(["ravensat",".mdl"])
|
20
21
|
|
21
|
-
@input_file.write
|
22
|
+
@input_file.write encoder.to_dimacs(cnf)
|
22
23
|
@input_file.flush
|
23
24
|
|
24
25
|
case @name
|
@@ -28,18 +29,9 @@ module Ravensat
|
|
28
29
|
system("#{@name} #{@input_file.to_path} #{@output_file.to_path}")
|
29
30
|
end
|
30
31
|
|
32
|
+
decoder = DimacsDecoder.new
|
31
33
|
model = @output_file.read.split("\n")
|
32
|
-
|
33
|
-
case model.first
|
34
|
-
when "SAT"
|
35
|
-
model.last.split.each do |e|
|
36
|
-
next if e == '0'
|
37
|
-
cnf.name_table.find{|key,value| value == e.to_i.abs.to_s}.first.value = !e.start_with?('-')
|
38
|
-
end
|
39
|
-
Arcteryx::SAT
|
40
|
-
when "UNSAT"
|
41
|
-
Arcteryx::UNSAT
|
42
|
-
end
|
34
|
+
decoder.decode(model, encoder.name_table)
|
43
35
|
end
|
44
36
|
|
45
37
|
end
|
data/lib/ravensat/version.rb
CHANGED
data/lib/ravensat.rb
CHANGED
@@ -4,12 +4,20 @@ require_relative "ravensat/version"
|
|
4
4
|
|
5
5
|
module Ravensat
|
6
6
|
ravensat = File.dirname(__FILE__) + '/ravensat'
|
7
|
+
ast = File.dirname(__FILE__) + '/ravensat/ast'
|
7
8
|
arcteryx = File.dirname(__FILE__) + '/arcteryx'
|
8
9
|
|
9
10
|
autoload :Solver, ravensat + '/solver.rb'
|
10
|
-
autoload :
|
11
|
-
autoload :
|
11
|
+
autoload :DimacsEncoder, ravensat + '/dimacs_encoder.rb'
|
12
|
+
autoload :DimacsDecoder, ravensat + '/dimacs_decoder.rb'
|
12
13
|
autoload :RavenClaw, ravensat + '/ravenclaw.rb'
|
13
14
|
|
15
|
+
autoload :Node, ast + '/node.rb'
|
16
|
+
autoload :VarNode, ast + '/var_node.rb'
|
17
|
+
autoload :OprNode, ast + '/opr_node.rb'
|
18
|
+
autoload :AndNode, ast + '/and_node.rb'
|
19
|
+
autoload :OrNode, ast + '/or_node.rb'
|
20
|
+
autoload :NotNode, ast + '/not_node.rb'
|
21
|
+
|
14
22
|
autoload :Arcteryx, arcteryx + '/arcteryx.rb'
|
15
23
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ravensat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- rikuto matsuda
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-05-16 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -27,11 +27,18 @@ files:
|
|
27
27
|
- Rakefile
|
28
28
|
- bin/console
|
29
29
|
- bin/setup
|
30
|
+
- example/magic_square_3x3.rb
|
30
31
|
- lib/arcteryx/arcteryx.rb
|
31
32
|
- lib/arcteryx/cnf.rb
|
32
33
|
- lib/ravensat.rb
|
33
|
-
- lib/ravensat/
|
34
|
-
- lib/ravensat/
|
34
|
+
- lib/ravensat/ast/and_node.rb
|
35
|
+
- lib/ravensat/ast/node.rb
|
36
|
+
- lib/ravensat/ast/not_node.rb
|
37
|
+
- lib/ravensat/ast/opr_node.rb
|
38
|
+
- lib/ravensat/ast/or_node.rb
|
39
|
+
- lib/ravensat/ast/var_node.rb
|
40
|
+
- lib/ravensat/dimacs_decoder.rb
|
41
|
+
- lib/ravensat/dimacs_encoder.rb
|
35
42
|
- lib/ravensat/ravenclaw.rb
|
36
43
|
- lib/ravensat/solver.rb
|
37
44
|
- lib/ravensat/version.rb
|
data/lib/ravensat/prop_logic.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
module Ravensat
|
2
|
-
class PropLogic
|
3
|
-
attr_reader :formula
|
4
|
-
attr_reader :name_table
|
5
|
-
|
6
|
-
def initialize( init_formula )
|
7
|
-
@formula = init_formula
|
8
|
-
# (a | b) & (~a | b) & (a | ~b) & (~a | ~b)
|
9
|
-
|
10
|
-
# [:and,
|
11
|
-
# [:or, a, b],
|
12
|
-
# [:or, [:not, a], b],
|
13
|
-
# [:or, a, [:not, b]],
|
14
|
-
# [:or, [:not, a], [:not, b]]
|
15
|
-
# ]
|
16
|
-
end
|
17
|
-
|
18
|
-
def to_cnf
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
def to_dimacs
|
23
|
-
cnf_text = String.new
|
24
|
-
tmp_name_table = @formula.flatten.uniq.reject{|e| e.class == Symbol}
|
25
|
-
@name_table = tmp_name_table.zip((1..tmp_name_table.size).to_a.map{|e| e.to_s}).to_h
|
26
|
-
|
27
|
-
nr_vars = tmp_name_table.size
|
28
|
-
nr_clses = @formula.size - 1
|
29
|
-
cnf_header = 'p cnf ' << nr_vars.to_s << ' ' << nr_clses.to_s << "\n"
|
30
|
-
# @formula.is_cnf?
|
31
|
-
@formula.each do |clause|
|
32
|
-
# next if clause.first != :and
|
33
|
-
case clause
|
34
|
-
when Symbol
|
35
|
-
next
|
36
|
-
when Array
|
37
|
-
case clause.first
|
38
|
-
when :or
|
39
|
-
clause.each do |literal|
|
40
|
-
case literal
|
41
|
-
when Symbol
|
42
|
-
next
|
43
|
-
when Ravensat::PropVar
|
44
|
-
cnf_text << @name_table[literal] << ' '
|
45
|
-
when Array #&& literal.first == :not
|
46
|
-
cnf_text << '-' << @name_table[literal.last] << ' '
|
47
|
-
end
|
48
|
-
end
|
49
|
-
when :not
|
50
|
-
cnf_text << '-' << @name_table[clause.last] << ' '
|
51
|
-
end
|
52
|
-
when Ravensat::PropVar
|
53
|
-
cnf_text << @name_table[clause] << ' '
|
54
|
-
end
|
55
|
-
cnf_text << '0' << "\n"
|
56
|
-
end
|
57
|
-
cnf_header + cnf_text
|
58
|
-
end
|
59
|
-
|
60
|
-
def &( object )
|
61
|
-
if @formula.first == :and
|
62
|
-
@formula.append object.formula
|
63
|
-
else
|
64
|
-
@formula = [:and, @formula, object.formula]
|
65
|
-
end
|
66
|
-
self
|
67
|
-
# Ravensat::PropLogic.new [:and, @formula, object]
|
68
|
-
# formulaがcnfである前提の実装
|
69
|
-
# @formula & other_formula
|
70
|
-
end
|
71
|
-
|
72
|
-
def |( object )
|
73
|
-
if @formula.first == :or
|
74
|
-
@formula.append object.formula
|
75
|
-
else
|
76
|
-
@formula = [:or, @formula, object.formula]
|
77
|
-
end
|
78
|
-
self
|
79
|
-
# Ravensat::PropLogic.new [:or, @formula, object]
|
80
|
-
# 木構造に落とすのが難しそう,実装見送り
|
81
|
-
# @formula | other_formula
|
82
|
-
end
|
83
|
-
|
84
|
-
# def to_a
|
85
|
-
# @formula.each do |f|
|
86
|
-
# if f.class == PropLogic
|
87
|
-
# f = f.to_a
|
88
|
-
# end
|
89
|
-
# end
|
90
|
-
# end
|
91
|
-
end
|
92
|
-
end
|
data/lib/ravensat/prop_var.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
module Ravensat
|
2
|
-
class PropVar
|
3
|
-
attr_accessor :value
|
4
|
-
|
5
|
-
def initialize
|
6
|
-
@value # => true | false | undef
|
7
|
-
end
|
8
|
-
|
9
|
-
# def +@
|
10
|
-
# # unuse?
|
11
|
-
# # return PropLogic object
|
12
|
-
# 'this is +@ method'
|
13
|
-
# end
|
14
|
-
|
15
|
-
# def -@
|
16
|
-
# # return PropLogic object
|
17
|
-
# 'this is -@ method'
|
18
|
-
# end
|
19
|
-
|
20
|
-
def ~@
|
21
|
-
Ravensat::PropLogic.new [:not, self]
|
22
|
-
# return PropLogic object
|
23
|
-
end
|
24
|
-
|
25
|
-
def &( object )
|
26
|
-
Ravensat::PropLogic.new [:and, self, object.formula]
|
27
|
-
# return PropLogic object
|
28
|
-
end
|
29
|
-
|
30
|
-
def |( object )
|
31
|
-
Ravensat::PropLogic.new [:or, self, object.formula]
|
32
|
-
# return PropLogic object
|
33
|
-
end
|
34
|
-
|
35
|
-
def formula
|
36
|
-
# $BIU$1>F?O%a%=%C%I(B
|
37
|
-
self
|
38
|
-
end
|
39
|
-
|
40
|
-
# def self
|
41
|
-
# 'this is self method'
|
42
|
-
# end
|
43
|
-
|
44
|
-
end
|
45
|
-
end
|