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