satre 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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