prop_logic 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 37cd959dffbbeeb64bde6b241794bec73c4415a6
4
+ data.tar.gz: 3a836ab88dd8e721b0e10ed4f1d0d7ffdb93fdd1
5
+ SHA512:
6
+ metadata.gz: 50f268b87efd5333fcbffbe2e72a48e13e87c25ed79e12d570f37043e692dae4d5eb02d9e7291e1262ee26e18509e0274dc018a801fb4d62ad60b4f2c214e37f
7
+ data.tar.gz: 1c74a4734264ed6395a0eba5806e03902c138b65f2ddc45551f01e9fd2ad36aa2f6e1ead12006749e4af542c064c015339f40853cf8ac6eefae0b4d46b40660f
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /vendor/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ - 2.2.4
5
+ - 2.1.6
6
+ - 2.0.0
7
+ - rbx-3.9
8
+ - jruby-9.0.1.0
9
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in prop_logic.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Jkr2255
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,140 @@
1
+ # PropLogic
2
+
3
+ [![Build Status](https://travis-ci.org/jkr2255/prop_logic.svg?branch=master)](https://travis-ci.org/jkr2255/prop_logic)
4
+
5
+ PropLogic implements propositional logic in Ruby, usable like normal variables.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'prop_logic'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install prop_logic
22
+
23
+ ### Requirements
24
+ Using with CRuby, Version >= 2.0.0 is required. Doesn't work stably on 1.9.x due to unreliable behaviors on weak reference.
25
+
26
+ In JRuby and Rubinus it should work.
27
+
28
+ ## Usage
29
+ ### Overview
30
+ First, variables can be declared using `PropLogic.new_variable`. Next, it can be calculated using normal Ruby operators
31
+ such as `&`, `|`, `~`, and some methods. Finally, you can test satisfiability of these expressions.
32
+
33
+ ```ruby
34
+ # declartion
35
+ a = PropLogic.new_variable 'a'
36
+ b = PropLogic.new_variable 'b'
37
+ c = PropLogic.new_variable 'c'
38
+
39
+ # calculation
40
+ expr1 = (a & b) | c
41
+ expr2 = ~(a.then(b))
42
+ expr3 = expr1 | expr2
43
+
44
+ # conversion
45
+ nnf = expr3.to_nnf
46
+ cnf = expr3.to_cnf
47
+ sat = expr3.sat?
48
+
49
+ # comparement
50
+ diff = (~a | ~b).equiv?(~(a & b)) # true
51
+
52
+ # assignment
53
+ (a & b).assign_true(a).assign_false(b).reduce # PropLogic::False
54
+ ```
55
+
56
+ ## Restriction
57
+ SAT solver bundled with this gem is brute-force solver (intended only for testing), so it is inappropriate to use for
58
+ real-scale problems.
59
+
60
+ ## References
61
+ `PropLogic::Term` is immutable, meaning that all calculations return new Terms.
62
+ ### `PropLogic::Term` instance methods
63
+ #### `#and(*others)`, `#&(*others)`
64
+ calculate `self & others[0] & others[1] & ...`.
65
+ #### `#or(*others)`, `#|(*others)`
66
+ calculate `self | others[0] | others[1] & ...`.
67
+
68
+ #### Warning for reducing with `&` / `|`
69
+ Because of immutability and internal system of and/or terms, `many_terms.reduce(&:and)` is exteremely slow.
70
+ Use `PropLogic.all_and`/`PropLogic.all_or` or `one_term.and(*others)` to avoid this pitfall.
71
+
72
+ #### `#not()`,`#~()`, `#-@()`
73
+ calculate `Not(self)`. `#!` is not present because it confuses Ruby behavior. (if present, `!term` is always *truthy*)
74
+
75
+ #### `#then(other), #>>(other)`
76
+ caslculate `If self then other`.
77
+
78
+ #### NNF
79
+ NNF doesn't contain following terms:
80
+ - If-then
81
+ - Negation of And/Or
82
+ - Double negation
83
+
84
+ `#nnf?` checks if the term is NNF, and `#to_nnf` returns term converted to NNF.
85
+
86
+ #### Reduction
87
+ Term is regarded as reduced if it is NNF and it contains no constants (`PropLogic::True`/`PropLogic::False`).
88
+
89
+ `#reduced?` checks if the term is reduced, and `#reduce` returns reduced term.
90
+
91
+ #### Reduction
92
+ CNF is one of these:
93
+ 1. Variable and its negation
94
+ 2. Logical sum of multiple 1
95
+ 3. Logical product of multiple (1 or 2)
96
+
97
+ `#cnf?` checks if the term is CNF, and `#to_cnf` returns terms converted to CNF (may use extra variables).
98
+
99
+ #### SAT judgement
100
+ `#sat?` returns:
101
+ - boolean `false` if unsatisfiable
102
+ - `nil` if satisfiability is undetermined
103
+ - One term satisfying original term if satisfiable
104
+
105
+ `#unsat?` returns `true` if unsatisfiable, `false` otherwise.
106
+
107
+ ### `PropLogic` module methods
108
+ #### `PropLogic.new_variable(name = nil)`
109
+ declare new variable with name `name`. if `name` is not supplied, unique name is set.
110
+
111
+ Notice that even if the same `name` as before specified, it returns *different* variable.
112
+
113
+ #### `PropLogic.all_and(*terms)`/`PropLogic.all_or(*terms)`
114
+ calculate all and/or of `terms`. Use this when and/or calculation for many variables.
115
+
116
+ #### `PropLogic.sat_solver`/ PropLogic.sat_solver=`
117
+ set/get SAT solver object. It shoud have `#call(term)` method and return value is described in `Term#sat?`.
118
+
119
+ ### Information
120
+ `PropLogic::Term` has some subclasses, but these classes are subject to change.
121
+ Using subclasses of `PropLogic::Term` directly is not recommended.
122
+
123
+ ## Development
124
+
125
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
126
+
127
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
128
+
129
+ ## Contributing
130
+
131
+ 1. Fork it ( https://github.com/[my-github-username]/prop_logic/fork )
132
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
133
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
134
+ 4. Push to the branch (`git push origin my-new-feature`)
135
+ 5. Create a new Pull Request
136
+
137
+ ## ToDo
138
+
139
+ - Introduce special blocks to build terms inside
140
+ - Add nontrivial SAT solver for practical usage
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ task :default => [:spec]
5
+
6
+ RSpec::Core::RakeTask.new
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "prop_logic"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,77 @@
1
+ module PropLogic
2
+ class AndTerm < Term
3
+ def initialize(*terms)
4
+ @terms = terms.map{|t| t.is_a?(AndTerm) ? t.terms : t}.flatten.freeze
5
+ @is_nnf = @terms.all?(&:nnf?)
6
+ # term with negative terms are no longer terated as reduced
7
+ @is_reduced = @is_nnf && @terms.all? do |term|
8
+ if term.is_a?(Constant) || !term.reduced?
9
+ false
10
+ elsif !(term.is_a?(NotTerm))
11
+ true
12
+ else
13
+ # NotTerm
14
+ term.terms[0].is_a?(Variable)
15
+ end
16
+ end
17
+ return unless @is_reduced
18
+ # check contradicted variables (mark as unreduced)
19
+ # Negated terms (except variables) doesn't come here
20
+ not_terms = @terms.select{ |t| t.is_a?(NotTerm) }
21
+ negated_variales = not_terms.map{|t| t.terms[0]}
22
+ @is_reduced = false unless (negated_variales & @terms).empty?
23
+ end
24
+
25
+ def to_s(in_term = false)
26
+ str = @terms.map(&:to_s_in_term).join(' & ')
27
+ in_term ? "( #{str} )" : str
28
+ end
29
+
30
+ def nnf?
31
+ @is_nnf
32
+ end
33
+
34
+ def reduced?
35
+ @is_reduced
36
+ end
37
+
38
+ def reduce
39
+ return self if reduced?
40
+ reduced_terms = @terms.map(&:reduce)
41
+ reduced_terms.reject!{|term| term.equal?(True)}
42
+ return True if reduced_terms.empty?
43
+ if reduced_terms.any?{|term| term.equal?(False)}
44
+ False
45
+ elsif reduced_terms.length == 1
46
+ reduced_terms[0]
47
+ else
48
+ # detect contradicted terms
49
+ not_terms = reduced_terms.select{|term| term.is_a?(NotTerm)}
50
+ negated_terms = not_terms.map{|term| term.terms[0]}
51
+ return False unless (negated_terms & reduced_terms).empty?
52
+ Term.get self.class, *reduced_terms
53
+ end
54
+ end
55
+
56
+ def cnf?
57
+ return false unless reduced?
58
+ @terms.all?(&:cnf?)
59
+ end
60
+
61
+ def to_cnf
62
+ return super unless reduced?
63
+ return self if cnf?
64
+ pool = []
65
+ without_pools = PropLogic.all_and(*@terms.map{|t| t.tseitin(pool)})
66
+ PropLogic.all_and(without_pools, *pool)
67
+ end
68
+
69
+ def tseitin(pool)
70
+ val = Variable.new
71
+ terms = @terms.map{|t| t.cnf? ? t : t.tseitin(pool)}
72
+ pool.concat terms.map{|t| ~val | t }
73
+ val
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,20 @@
1
+ module PropLogic
2
+ module BruteForceSatSolver
3
+ class << self
4
+ def call(term)
5
+ # obvious value
6
+ return True if term == True
7
+ variables = term.variables
8
+ PropLogic.all_combination(variables) do |trues|
9
+ falses = variables - trues
10
+ next unless term.assign(trues, falses).reduce == True
11
+ # SAT
12
+ negated_falses = falses.map(&:not)
13
+ return PropLogic.all_and(*trues, *negated_falses)
14
+ end
15
+ # UNSAT
16
+ false
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,45 @@
1
+ require 'singleton'
2
+
3
+ module PropLogic
4
+ class Constant < Variable
5
+ def variables
6
+ []
7
+ end
8
+
9
+ def to_cnf
10
+ self
11
+ end
12
+
13
+ end
14
+
15
+ class TrueConstant < Constant
16
+ include Singleton
17
+ def to_s(*)
18
+ 'true'
19
+ end
20
+
21
+ def assign(trues, falses, variables = nil)
22
+ if falses.include?(self)
23
+ raise ArgumentError, 'Contradicted assignment'
24
+ end
25
+ self
26
+ end
27
+
28
+ end
29
+
30
+ class FalseConstant < Constant
31
+ include Singleton
32
+ def to_s(*)
33
+ 'false'
34
+ end
35
+ def assign(trues, falses, variables = nil)
36
+ if trues.include?(self)
37
+ raise ArgumentError, 'Contradicted assignment'
38
+ end
39
+ self
40
+ end
41
+ end
42
+
43
+ True = TrueConstant.instance.freeze
44
+ False = FalseConstant.instance.freeze
45
+ end
@@ -0,0 +1,26 @@
1
+ module PropLogic
2
+ module Functions
3
+ def all_or(*args)
4
+ Term.get OrTerm, *args
5
+ end
6
+
7
+ def all_and(*args)
8
+ Term.get AndTerm, *args
9
+ end
10
+
11
+ def new_variable(*args)
12
+ Variable.new *args
13
+ end
14
+ end
15
+
16
+ extend Functions
17
+
18
+ def all_combination(arr)
19
+ 0.upto(arr.length) do |num|
20
+ arr.combination(num){|c| yield c}
21
+ end
22
+ end
23
+
24
+ module_function :all_combination
25
+
26
+ end
@@ -0,0 +1,68 @@
1
+ module PropLogic
2
+ class NotTerm < Term
3
+ def initialize(term)
4
+ @terms = [term].freeze
5
+ end
6
+
7
+ def to_s(*)
8
+ "~" + @terms[0].to_s(true)
9
+ end
10
+
11
+ def nnf?
12
+ @terms[0].is_a?(Variable)
13
+ end
14
+
15
+ def to_nnf
16
+ term = @terms[0]
17
+ case term
18
+ when NotTerm
19
+ term.terms[0].to_nnf
20
+ when Variable
21
+ self
22
+ when ThenTerm
23
+ (~(term.to_nnf)).to_nnf
24
+ when AndTerm
25
+ PropLogic.all_or(*term.terms.map{|t| (~t).to_nnf})
26
+ when OrTerm
27
+ PropLogic.all_and(*term.terms.map{|t| (~t).to_nnf})
28
+ end
29
+ end
30
+
31
+ def reduced?
32
+ nnf? && ! (@terms[0].is_a?(Constant))
33
+ end
34
+
35
+ def reduce
36
+ return self if reduced?
37
+ reduced_term = @terms[0].reduce
38
+ case reduced_term
39
+ when TrueConstant
40
+ False
41
+ when FalseConstant
42
+ True
43
+ else
44
+ (~reduced_term).to_nnf
45
+ end
46
+ end
47
+
48
+ def to_cnf
49
+ if reduced?
50
+ self
51
+ else
52
+ super
53
+ end
54
+ end
55
+
56
+ def tseitin(pool)
57
+ if nnf?
58
+ self
59
+ elsif @terms[0].is_a?(NotTerm) && @terms[0].terms[0].is_a(Variable)
60
+ @terms[0].terms[0]
61
+ else
62
+ raise 'Non-NNF terms cannot be converted to Tseitin form.' + self.to_s
63
+ end
64
+ end
65
+
66
+ alias_method :cnf?, :reduced?
67
+ end
68
+ end
@@ -0,0 +1,75 @@
1
+ module PropLogic
2
+ class OrTerm < Term
3
+ def initialize(*terms)
4
+ @terms = terms.map{|t| t.is_a?(OrTerm) ? t.terms : t}.flatten.freeze
5
+ @is_nnf = @terms.all?(&:nnf?)
6
+ @is_reduced = @is_nnf && @terms.all? do |term|
7
+ if term.is_a?(Constant) || !(term.reduced?)
8
+ false
9
+ elsif !(term.is_a?(NotTerm))
10
+ true
11
+ else
12
+ # NotTerm
13
+ term.terms[0].is_a?(Variable)
14
+ end
15
+ end
16
+ return unless @is_reduced
17
+ # check obvious variables (mark as unreduced)
18
+ # Negated terms (except variables) doesn't come here
19
+ not_terms = @terms.select{ |t| t.is_a?(NotTerm) }
20
+ negated_variales = not_terms.map{|t| t.terms[0]}
21
+ @is_reduced = false unless (negated_variales & @terms).empty?
22
+ end
23
+
24
+ def to_s(in_term = false)
25
+ str = @terms.map(&:to_s_in_term).join(' | ')
26
+ in_term ? "( #{str} )" : str
27
+ end
28
+
29
+ def nnf?
30
+ @is_nnf
31
+ end
32
+
33
+ def reduced?
34
+ @is_reduced
35
+ end
36
+
37
+ def reduce
38
+ return self if reduced?
39
+ reduced_terms = @terms.map(&:reduce)
40
+ reduced_terms.reject!{|term| term.equal?(False)}
41
+ return False if reduced_terms.empty?
42
+ if reduced_terms.any?{|term| term.equal?(True)}
43
+ True
44
+ elsif reduced_terms.length == 1
45
+ reduced_terms[0]
46
+ else
47
+ not_terms = reduced_terms.select{|term| term.is_a?(NotTerm)}
48
+ negated_terms = not_terms.map{|term| term.terms[0]}
49
+ return True unless (negated_terms & reduced_terms).empty?
50
+ Term.get self.class, *reduced_terms
51
+ end
52
+ end
53
+
54
+ def cnf?
55
+ return false unless reduced?
56
+ ! @terms.any?{ |term| term.is_a?(AndTerm) }
57
+ end
58
+
59
+ def to_cnf
60
+ return super unless reduced?
61
+ return self if cnf?
62
+ pool = []
63
+ without_pools = tseitin(pool)
64
+ PropLogic.all_and(without_pools, *pool)
65
+ end
66
+
67
+ def tseitin(pool)
68
+ val = Variable.new
69
+ terms = @terms.map{|t| t.tseitin(pool)}
70
+ pool << (~val | PropLogic.all_or(*terms))
71
+ val
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,13 @@
1
+ module PropLogic
2
+ #default
3
+ @@sat_solver = PropLogic::BruteForceSatSolver
4
+
5
+ def self.sat_solver
6
+ @@sat_solver
7
+ end
8
+
9
+ def self.sat_solver=(engine)
10
+ raise TypeError unless engine.respond_to?(:call)
11
+ @@sat_solver = engine
12
+ end
13
+ end
@@ -0,0 +1,149 @@
1
+ require 'ref'
2
+
3
+ module PropLogic
4
+ class Term
5
+ def initialize
6
+ raise NotImplementedError, 'Term cannot be initialized'
7
+ end
8
+
9
+ def initialize_copy(*)
10
+ raise TypeError, 'Term cannot be duplicated (immutable, not necessary)'
11
+ end
12
+
13
+ class << self
14
+ protected :new
15
+ end
16
+
17
+ attr_reader :terms
18
+
19
+ def and(*others)
20
+ others.unshift self
21
+ Term.get AndTerm, *others
22
+ end
23
+
24
+ alias_method :&, :and
25
+
26
+ def or(*others)
27
+ others.unshift self
28
+ Term.get OrTerm, *others
29
+ end
30
+
31
+ alias_method :|, :or
32
+
33
+ def not
34
+ Term.get NotTerm, self
35
+ end
36
+
37
+ alias_method :~, :not
38
+ alias_method :-@, :not
39
+
40
+ def then(other)
41
+ Term.get ThenTerm, self, other
42
+ end
43
+
44
+ alias_method :>>, :then
45
+
46
+ def to_s_in_term
47
+ to_s true
48
+ end
49
+
50
+ def to_nnf
51
+ if nnf?
52
+ self
53
+ else
54
+ Term.get self.class, *@terms.map(&:to_nnf)
55
+ end
56
+ end
57
+
58
+ def nnf?
59
+ false
60
+ end
61
+
62
+ def reduce
63
+ if reduced?
64
+ self
65
+ else
66
+ Term.get self.class, *@terms.map(&:reduce)
67
+ end
68
+ end
69
+
70
+ def reduced?
71
+ false
72
+ end
73
+
74
+ def to_cnf
75
+ reduce.to_cnf
76
+ end
77
+
78
+ def self.validate_terms(*terms)
79
+ terms.map do |term|
80
+ case term
81
+ when TrueClass
82
+ True
83
+ when FalseClass
84
+ False
85
+ when Term
86
+ term
87
+ else
88
+ raise TypeError, "#{term.class} cannot be treated as term"
89
+ end
90
+ end
91
+ end
92
+
93
+ def self.get(klass, *terms)
94
+ @table ||= Ref::WeakValueMap.new
95
+ terms = validate_terms(*terms)
96
+ if klass == AndTerm || klass == OrTerm
97
+ terms = terms.map{|t| t.is_a?(klass) ? t.terms : t}.flatten
98
+ end
99
+ key = klass.name + terms.map(&:object_id).join(',')
100
+ return @table[key] if @table[key]
101
+ ret = klass.__send__ :new, *terms
102
+ @table[key] = ret
103
+ ret.freeze
104
+ end
105
+
106
+ def cnf?
107
+ false
108
+ end
109
+
110
+ def variables
111
+ @terms.map(&:variables).flatten.uniq
112
+ end
113
+
114
+ def assign(trues, falses, variables = nil)
115
+ # contradicted assignment
116
+ raise ArgumentError, 'Contradicted assignment' unless (trues & falses).empty?
117
+ variables ||= trues | falses
118
+ assigned_terms = terms.map do |term|
119
+ if (term.variables & variables).empty?
120
+ term
121
+ else
122
+ term.assign(trues, falses, variables)
123
+ end
124
+ end
125
+ Term.get self.class, *assigned_terms
126
+ end
127
+
128
+ def assign_true(*variables)
129
+ assign variables, []
130
+ end
131
+
132
+ def assign_false(*variables)
133
+ assign [], variables
134
+ end
135
+
136
+ def sat?
137
+ PropLogic.sat_solver.call(self)
138
+ end
139
+
140
+ def unsat?
141
+ sat? == false
142
+ end
143
+
144
+ def equiv?(other)
145
+ ((self | other) & (~self | ~other)).unsat?
146
+ end
147
+
148
+ end
149
+ end
@@ -0,0 +1,25 @@
1
+ module PropLogic
2
+ class ThenTerm < Term
3
+ def initialize(term1, term2)
4
+ @terms = [term1, term2].freeze
5
+ end
6
+
7
+ def to_s(in_term = false)
8
+ str = "#{@terms[0].to_s(true)} => #{@terms[1].to_s(true)}"
9
+ in_term ? "( #{str} )" : str
10
+ end
11
+
12
+ def nnf?
13
+ false
14
+ end
15
+
16
+ def to_nnf
17
+ (~@terms[0]).to_nnf | @terms[1].to_nnf
18
+ end
19
+
20
+ def reduce
21
+ to_nnf.reduce
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,49 @@
1
+ module PropLogic
2
+ class Variable < Term
3
+ def initialize(name = nil)
4
+ @name = name || "v_#{object_id}"
5
+ @terms = [].freeze
6
+ freeze
7
+ end
8
+
9
+ public_class_method :new
10
+
11
+ def to_s(*)
12
+ @name
13
+ end
14
+
15
+ def nnf?
16
+ true
17
+ end
18
+
19
+ def reduced?
20
+ true
21
+ end
22
+
23
+ def to_cnf
24
+ self
25
+ end
26
+
27
+ def tseitin(pool)
28
+ self
29
+ end
30
+
31
+ def cnf?
32
+ true
33
+ end
34
+
35
+ def variables
36
+ [self]
37
+ end
38
+
39
+ def assign(trues, falses, variables = nil)
40
+ if trues.include? self
41
+ True
42
+ elsif falses.include? self
43
+ False
44
+ else
45
+ self
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ module PropLogic
2
+ VERSION = "0.1.0"
3
+ end
data/lib/prop_logic.rb ADDED
@@ -0,0 +1,11 @@
1
+ require "prop_logic/version"
2
+ require "prop_logic/term"
3
+ require "prop_logic/and_term"
4
+ require "prop_logic/or_term"
5
+ require "prop_logic/not_term"
6
+ require "prop_logic/then_term"
7
+ require 'prop_logic/variable'
8
+ require 'prop_logic/constants'
9
+ require 'prop_logic/functions'
10
+ require 'prop_logic/brute_force_sat_solver'
11
+ require 'prop_logic/sat_solver'
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'prop_logic/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "prop_logic"
8
+ spec.version = PropLogic::VERSION
9
+ spec.authors = ["Jkr2255"]
10
+ spec.email = ["magnesium.oxide.play@gmail.com"]
11
+
12
+ spec.summary = %q{Propositional logic for Ruby}
13
+ spec.description = %q{Write propositional logic formulae using Ruby DSL.}
14
+ spec.homepage = "https://github.com/jkr2255/prop_logic"
15
+ spec.license = "MIT"
16
+
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_dependency "ref", '~> 2.0'
24
+ spec.required_ruby_version = '>= 2.0.0'
25
+
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.7"
28
+ spec.add_development_dependency "rake", "~> 10.0"
29
+ spec.add_development_dependency "rspec", '~> 3.0'
30
+ # spec.add_development_dependency "pry-byebug", '~> 3.3'
31
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: prop_logic
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jkr2255
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-01-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ref
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ prerelease: false
21
+ type: :runtime
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.7'
34
+ prerelease: false
35
+ type: :development
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ prerelease: false
49
+ type: :development
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ prerelease: false
63
+ type: :development
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: Write propositional logic formulae using Ruby DSL.
70
+ email:
71
+ - magnesium.oxide.play@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - bin/console
84
+ - bin/setup
85
+ - lib/prop_logic.rb
86
+ - lib/prop_logic/and_term.rb
87
+ - lib/prop_logic/brute_force_sat_solver.rb
88
+ - lib/prop_logic/constants.rb
89
+ - lib/prop_logic/functions.rb
90
+ - lib/prop_logic/not_term.rb
91
+ - lib/prop_logic/or_term.rb
92
+ - lib/prop_logic/sat_solver.rb
93
+ - lib/prop_logic/term.rb
94
+ - lib/prop_logic/then_term.rb
95
+ - lib/prop_logic/variable.rb
96
+ - lib/prop_logic/version.rb
97
+ - prop_logic.gemspec
98
+ homepage: https://github.com/jkr2255/prop_logic
99
+ licenses:
100
+ - MIT
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 2.0.0
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project:
118
+ rubygems_version: 2.5.1
119
+ signing_key:
120
+ specification_version: 4
121
+ summary: Propositional logic for Ruby
122
+ test_files: []