satre 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.
@@ -0,0 +1,6 @@
1
+ require 'satre/expression/expression'
2
+ require 'satre/expression/add'
3
+ require 'satre/expression/const'
4
+ require 'satre/expression/expression_parser'
5
+ require 'satre/expression/mul'
6
+ require 'satre/expression/var'
@@ -0,0 +1,26 @@
1
+ require 'satre/expression'
2
+
3
+ # A parster for propositional statements
4
+ # and simple mathematical expressions
5
+ module Satre
6
+ class Add < Expression
7
+ attr_reader :p
8
+ attr_reader :q
9
+
10
+ def initialize(p,q)
11
+ fail(ArgumentError, 'p must be a expression') unless p.is_a?(Expression)
12
+ fail(ArgumentError, 'q must be a expression') unless p.is_a?(Expression)
13
+ @p = p.dup.freeze
14
+ @q = q.dup.freeze
15
+ super "Add (#{@p},#{@q})"
16
+ end
17
+
18
+ def eval
19
+ p.eval + q.eval
20
+ end
21
+
22
+ def self.parse(e)
23
+ fail 'not yet implemented'
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ require 'satre/expression'
2
+
3
+ # A parster for propositional statements
4
+ # and simple mathematical expressions
5
+ module Satre
6
+ class Const < Expression
7
+ attr_reader :i
8
+
9
+ def initialize(i)
10
+ ArgumentError 'argument must be an integer' unless i.is_a? Integer
11
+ @i = i
12
+ super "Const #{i}"
13
+ end
14
+
15
+ def eval
16
+ i
17
+ end
18
+
19
+ def self.parse(e)
20
+ fail 'not yet implemented'
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ module Satre
2
+ class Expression
3
+ attr_reader :base
4
+
5
+ def initialize(base)
6
+ fail(ArgumentError, 'argument must be a string') unless base.is_a?(String)
7
+ @base = base.dup.freeze
8
+ end
9
+
10
+ def to_s
11
+ base
12
+ end
13
+
14
+ def eval # abstract method
15
+ fail 'abstract'
16
+ end
17
+
18
+ def simplify
19
+ fail 'not yet implemented'
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,56 @@
1
+ require 'satre/parser'
2
+
3
+ module Satre
4
+ class ExpressionParser < Parser
5
+ class << self
6
+ def parse_expression
7
+ lambda do |inp|
8
+ e1, i1 = parse_product(inp)
9
+ if i1[0] == '+'
10
+ e2, i2 = parse_expression.call(i1.drop(1))
11
+ return Add.new(e1, e2), i2
12
+ end
13
+ return e1, i1
14
+ end
15
+ end
16
+
17
+ def parse_product(inp)
18
+ e1, i1 = parse_atom(inp)
19
+ if i1[0] == '*'
20
+ e2,i2 = parse_expression.call(i1.drop(1))
21
+ return Mul.new(e1, e2), i2
22
+ end
23
+ return e1, i1
24
+ end
25
+
26
+ def parse_atom(inp)
27
+ fail(ArgumentError, 'Expected an expression at end of input') if inp == []
28
+ if inp[0] == '('
29
+ e2, i2 = parse_expression.call(inp.drop(1))
30
+ if i2[0] == ')'
31
+ return e2, i2.drop(1)
32
+ else
33
+ fail(ExpressionError, 'Expected closing bracket')
34
+ end
35
+ else
36
+ if Lexer.numeric?.call(inp[0])
37
+ return Const.new(inp[0].to_i), inp.drop(1)
38
+ else
39
+ return Var.new(inp[0]), inp.drop(1)
40
+ end
41
+ end
42
+ end
43
+
44
+ def parse(inp)
45
+ make_parser.curry.call(parse_expression).call(inp)
46
+ end
47
+ end
48
+
49
+ end
50
+ end
51
+
52
+ class String
53
+ def to_expression
54
+ Satre::ExpressionParser.parse(self)
55
+ end
56
+ end
@@ -0,0 +1,30 @@
1
+ require 'satre/expression'
2
+
3
+ # A parster for propositional statements
4
+ # and simple mathematical expressions
5
+ module Satre
6
+ class Mul < Expression
7
+ attr_reader :p
8
+ attr_reader :q
9
+
10
+ def initialize(p,q)
11
+ fail(ArgumentError, 'p must be a expression') unless p.is_a?(Expression)
12
+ fail(ArgumentError, 'q must be a expression') unless p.is_a?(Expression)
13
+ @p = p.dup.freeze
14
+ @q = q.dup.freeze
15
+ super "Mul(#{@p},#{@q})"
16
+ end
17
+
18
+ def eval
19
+ p.eval * q.eval
20
+ end
21
+
22
+ def self.parse(e)
23
+ e1, i1 = Expression.parse(inp)
24
+ if e1[-1] == '*'
25
+ _e2,i2 = parse_expression(i1)
26
+ return Mul.new(e1,i1), i2
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,14 @@
1
+ require 'satre/expression'
2
+
3
+ module Satre
4
+ class Var < Expression
5
+ def initialize(s)
6
+ fail(ArgumentError, 's must be a string') unless s.is_a?(String)
7
+ super "Var \"#{s}\""
8
+ end
9
+
10
+ def eval(_valudation)
11
+ fail 'not implemented'
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ require 'satre/formula/formula'
2
+ require 'satre/formula/and'
3
+ require 'satre/formula/atom'
4
+ require 'satre/formula/entails'
5
+ require 'satre/formula/false'
6
+ require 'satre/formula/iff'
7
+ require 'satre/formula/imp'
8
+ require 'satre/formula/not'
9
+ require 'satre/formula/or'
10
+ require 'satre/formula/true'
@@ -0,0 +1,26 @@
1
+ require 'satre/formula'
2
+
3
+ module Satre
4
+ class And < Formula
5
+ attr_reader :p
6
+ attr_reader :q
7
+
8
+ def initialize(p,q)
9
+ fail(ArgumentError, 'Argument must be a Formula') unless p.is_a?(Formula)
10
+ fail(ArgumentError, 'Argument must be a Formula') unless q.is_a?(Formula)
11
+ @p = p.dup.freeze
12
+ @q = q.dup.freeze
13
+ super "(#{@p} ∧ #{@q})"
14
+ end
15
+
16
+ def eval(v)
17
+ p.eval(v) && q.eval(v)
18
+ end
19
+
20
+ def atoms
21
+ atoms = p.atoms + q.atoms
22
+ atoms.uniq || []
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ require 'satre/formula'
2
+
3
+ # A parster for propositional statements
4
+ # and simple mathematical expressions
5
+ module Satre
6
+ # A propositional 'atomic' value
7
+ class Atom < Formula
8
+
9
+ attr_reader :base
10
+
11
+ def initialize(base)
12
+ super base
13
+ end
14
+
15
+ def eval(valudation)
16
+ fail(Error, 'valudation must be a hash') unless valudation.is_a?(Hash)
17
+ fail(Error, 'all validations must be booleans') unless valudation.values.all?{|b|!!b == b}
18
+ valudation = valudation.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
19
+ fail(Error, "valudation for Atom #{base} not given") unless valudation.keys.include?(base.to_sym)
20
+ valudation[base.to_sym]
21
+ end
22
+
23
+ def atoms
24
+ [base]
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ require 'satre/formula'
2
+
3
+ # A parster for propositional statements
4
+ # and simple mathematical expressions
5
+ module Satre
6
+ # A propositional logic 'and' value
7
+ class Entails < Formula
8
+ attr_reader :p
9
+ attr_reader :q
10
+
11
+ def initialize(p,q)
12
+ fail(ArgumentError, 'Argument must be a Formula') unless p.is_a?(Formula)
13
+ fail(ArgumentError, 'Argument must be a Formula') unless q.is_a?(Formula)
14
+ @p = p.dup.freeze
15
+ @q = q.dup.freeze
16
+ super "(#{@p} ⊨ #{@q})"
17
+ end
18
+
19
+ def eval(*)
20
+ p.entails?(q)
21
+ end
22
+
23
+ def atoms
24
+ atoms = p.atoms + q.atoms
25
+ atoms.uniq || []
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ require 'satre/formula'
2
+
3
+ module Satre
4
+ class False < Formula
5
+
6
+ def initialize
7
+ super '⊥'
8
+ end
9
+
10
+ def eval(*)
11
+ false
12
+ end
13
+
14
+ def atoms
15
+ []
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,61 @@
1
+ module Satre
2
+ class Formula
3
+ include Comparable
4
+
5
+ def <=>(other)
6
+ base <=> other.base
7
+ end
8
+
9
+ attr_reader :base
10
+
11
+ def initialize(base)
12
+ fail(ArgumentError, 'Argument must be a String') unless base.is_a?(String)
13
+ @base = base.dup.freeze
14
+ end
15
+
16
+ def to_s
17
+ base
18
+ end
19
+
20
+ def atoms
21
+ fail 'abstract'
22
+ end
23
+
24
+ def on_all_valuations?
25
+ valudation = Hash[self.atoms.map { |x| [x, true] }]
26
+ truthtable = [valudation]
27
+ valudation.length.times do |i|
28
+ v = {}
29
+ (valudation.length - i).times do |j|
30
+ v = valudation.dup
31
+ v[v.keys[j]] = ! v[v.keys[j]]
32
+ truthtable << v
33
+ end
34
+ valudation = v
35
+ end
36
+ truthtable.all? { |v| self.eval(v) }
37
+ end
38
+
39
+ def eval(_valudation)
40
+ fail 'abstract'
41
+ end
42
+
43
+ def tautology?
44
+ on_all_valuations?
45
+ end
46
+
47
+ def unsatifiable?
48
+ Not.new(self).tautology?
49
+ end
50
+
51
+ def satifiable?
52
+ not unsatifiable?
53
+ end
54
+
55
+ def entails?(other)
56
+ #Imp.new(self, other).tautology?
57
+ And.new(self, Not.new(other)).unsatifiable?
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,27 @@
1
+ require 'satre/formula'
2
+
3
+ module Satre
4
+ class Iff < Formula
5
+ attr_reader :p
6
+ attr_reader :q
7
+
8
+ def initialize(p,q)
9
+ fail(ArgumentError, 'Argument must be a Formula') unless p.is_a?(Formula)
10
+ fail(ArgumentError, 'Argument must be a Formula') unless q.is_a?(Formula)
11
+ @p = p.dup.freeze
12
+ @q = q.dup.freeze
13
+ super "(#{@p} ⇔ #{@q})"
14
+ end
15
+
16
+ def eval(valudation)
17
+ p.eval(valudation) == q.eval(valudation)
18
+ end
19
+
20
+ def atoms
21
+ atoms = p.atoms + q.atoms
22
+ atoms.uniq || []
23
+ end
24
+
25
+ end
26
+ end
27
+
@@ -0,0 +1,25 @@
1
+ require 'satre/formula'
2
+
3
+ module Satre
4
+ class Imp < Formula
5
+ attr_reader :p
6
+ attr_reader :q
7
+
8
+ def initialize(p,q)
9
+ fail(ArgumentError, "Argument must be a Formula p:#{p}") unless p.is_a?(Formula)
10
+ fail(ArgumentError, "Argument must be a Formula q:#{q}") unless q.is_a?(Formula)
11
+ @p = p.dup.freeze
12
+ @q = q.dup.freeze
13
+ super "(#{@p} → #{@q})"
14
+ end
15
+
16
+ def eval(valudation)
17
+ (! p.eval(valudation)) or (q.eval(valudation))
18
+ end
19
+
20
+ def atoms
21
+ atoms = p.atoms + q.atoms
22
+ atoms.uniq || []
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ require 'satre/formula'
2
+
3
+ module Satre
4
+ class Not < Formula
5
+ attr_reader :p
6
+
7
+ def initialize(p)
8
+ fail(ArgumentError, 'Argument must be a Formula') unless p.is_a?(Formula)
9
+ @p = p.dup.freeze
10
+ super "(¬#{@p})"
11
+ end
12
+
13
+ def eval(valudation)
14
+ ! p.eval(valudation)
15
+ end
16
+
17
+ def atoms
18
+ p.atoms || []
19
+ end
20
+
21
+ end
22
+ end