satre 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -1
- data/README.md +9 -7
- data/bin/exercise +64 -8
- data/lib/satre.rb +1 -3
- data/lib/satre/errors.rb +3 -0
- data/lib/satre/errors/argument_error.rb +2 -0
- data/lib/satre/errors/expression_error.rb +2 -0
- data/lib/satre/errors/parser_error.rb +2 -0
- data/lib/satre/formula.rb +3 -9
- data/lib/satre/formula/first_order_logic.rb +4 -0
- data/lib/satre/formula/first_order_logic/exists.rb +32 -0
- data/lib/satre/formula/first_order_logic/fol_formula.rb +35 -0
- data/lib/satre/formula/first_order_logic/forall.rb +32 -0
- data/lib/satre/formula/first_order_logic/relation.rb +38 -0
- data/lib/satre/formula/formula.rb +1 -13
- data/lib/satre/formula/propositional_logic.rb +9 -0
- data/lib/satre/formula/propositional_logic/and.rb +37 -0
- data/lib/satre/formula/propositional_logic/atom.rb +44 -0
- data/lib/satre/formula/propositional_logic/entails.rb +42 -0
- data/lib/satre/formula/{false.rb → propositional_logic/false.rb} +9 -2
- data/lib/satre/formula/propositional_logic/iff.rb +38 -0
- data/lib/satre/formula/propositional_logic/imp.rb +38 -0
- data/lib/satre/formula/propositional_logic/not.rb +34 -0
- data/lib/satre/formula/propositional_logic/or.rb +37 -0
- data/lib/satre/formula/{true.rb → propositional_logic/true.rb} +11 -2
- data/lib/satre/formula/term.rb +3 -0
- data/lib/satre/formula/term/function.rb +33 -0
- data/lib/satre/formula/term/term.rb +6 -0
- data/lib/satre/formula/term/variable.rb +24 -0
- data/lib/satre/parser.rb +4 -15
- data/lib/satre/parser/formula_parser.rb +74 -0
- data/lib/satre/parser/lexer.rb +55 -0
- data/lib/satre/parser/parser.rb +80 -0
- data/lib/satre/parser/term_parser.rb +85 -0
- data/lib/satre/version.rb +1 -1
- data/satre.gemspec +1 -0
- metadata +43 -20
- data/lib/satre/expression.rb +0 -6
- data/lib/satre/expression/add.rb +0 -26
- data/lib/satre/expression/const.rb +0 -23
- data/lib/satre/expression/expression.rb +0 -22
- data/lib/satre/expression/expression_parser.rb +0 -56
- data/lib/satre/expression/mul.rb +0 -30
- data/lib/satre/expression/var.rb +0 -14
- data/lib/satre/formula/and.rb +0 -26
- data/lib/satre/formula/atom.rb +0 -28
- data/lib/satre/formula/entails.rb +0 -29
- data/lib/satre/formula/iff.rb +0 -27
- data/lib/satre/formula/imp.rb +0 -25
- data/lib/satre/formula/not.rb +0 -22
- data/lib/satre/formula/or.rb +0 -25
- data/lib/satre/formula_parser.rb +0 -92
- data/lib/satre/lexer.rb +0 -47
data/lib/satre/expression/mul.rb
DELETED
@@ -1,30 +0,0 @@
|
|
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
|
data/lib/satre/expression/var.rb
DELETED
@@ -1,14 +0,0 @@
|
|
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
|
data/lib/satre/formula/and.rb
DELETED
@@ -1,26 +0,0 @@
|
|
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
|
data/lib/satre/formula/atom.rb
DELETED
@@ -1,28 +0,0 @@
|
|
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
|
@@ -1,29 +0,0 @@
|
|
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
|
data/lib/satre/formula/iff.rb
DELETED
@@ -1,27 +0,0 @@
|
|
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
|
-
|
data/lib/satre/formula/imp.rb
DELETED
@@ -1,25 +0,0 @@
|
|
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
|
data/lib/satre/formula/not.rb
DELETED
@@ -1,22 +0,0 @@
|
|
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
|
data/lib/satre/formula/or.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'satre/formula'
|
2
|
-
|
3
|
-
module Satre
|
4
|
-
class Or < 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) 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
|
data/lib/satre/formula_parser.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
require 'satre/formula'
|
2
|
-
|
3
|
-
module Satre
|
4
|
-
class FormulaParser < Parser
|
5
|
-
class << self
|
6
|
-
|
7
|
-
def parse_formula
|
8
|
-
lambda do |inp|
|
9
|
-
e1, i1 = parse_imp(inp)
|
10
|
-
if i1[0] == '|='
|
11
|
-
e2, i2 = parse_formula.call(i1.drop(1))
|
12
|
-
return Entails.new(e1,e2), i2
|
13
|
-
end
|
14
|
-
return e1, i1
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def parse_imp(inp)
|
19
|
-
e1, i1 = parse_iff(inp)
|
20
|
-
if i1[0] == '=>'
|
21
|
-
e2, i2 = parse_formula.call(i1.drop(1))
|
22
|
-
return Imp.new(e1,e2), i2
|
23
|
-
end
|
24
|
-
return e1, i1
|
25
|
-
end
|
26
|
-
|
27
|
-
def parse_not(inp)
|
28
|
-
if inp.first == '~'
|
29
|
-
e1, i1 = parse_atom(inp.drop(1))
|
30
|
-
return Not.new(e1), i1
|
31
|
-
else
|
32
|
-
e1, i1 = parse_atom(inp)
|
33
|
-
return e1, i1
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def parse_and(inp)
|
38
|
-
e1, i1 = parse_or(inp)
|
39
|
-
if i1[0] == '/\\'
|
40
|
-
e2, i2 = parse_formula.call(i1.drop(1))
|
41
|
-
return And.new(e1,e2), i2
|
42
|
-
end
|
43
|
-
return e1, i1
|
44
|
-
end
|
45
|
-
|
46
|
-
def parse_or(inp)
|
47
|
-
e1, i1 = parse_not(inp)
|
48
|
-
if i1[0] == '\\/'
|
49
|
-
e2, i2 = parse_formula.call(i1.drop(1))
|
50
|
-
return Or.new(e1, e2), i2
|
51
|
-
end
|
52
|
-
return e1, i1
|
53
|
-
end
|
54
|
-
|
55
|
-
def parse_iff(inp)
|
56
|
-
e1, i1 = parse_and(inp)
|
57
|
-
if i1[0] == '<=>'
|
58
|
-
e2, i2 = parse_formula.call(i1.drop(1))
|
59
|
-
return Iff.new(e1, e2), i2
|
60
|
-
end
|
61
|
-
return e1, i1
|
62
|
-
end
|
63
|
-
|
64
|
-
def parse_atom(inp)
|
65
|
-
fail(ArgumentError, 'Expected an expression at end of input') if inp == []
|
66
|
-
if inp[0] == '('
|
67
|
-
e2, i2 = parse_formula.call(inp.drop(1))
|
68
|
-
if i2[0] == ')'
|
69
|
-
return e2, i2.drop(1)
|
70
|
-
else
|
71
|
-
fail(ExpressionError, 'Expected closing bracket')
|
72
|
-
end
|
73
|
-
else
|
74
|
-
return False.new, inp.drop(1) if inp[0] == "False"
|
75
|
-
return True.new, inp.drop(1) if inp[0] == "True"
|
76
|
-
return Atom.new(inp[0]), inp.drop(1)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def parse(inp)
|
81
|
-
make_parser.curry.call(parse_formula).call(inp)
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
class String
|
89
|
-
def to_formula
|
90
|
-
Satre::FormulaParser.parse(self)
|
91
|
-
end
|
92
|
-
end
|
data/lib/satre/lexer.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
module Satre
|
2
|
-
class Lexer
|
3
|
-
class << self
|
4
|
-
def matches
|
5
|
-
lambda { |pattern, str| str.split("").all? { |c| pattern.include? c } }
|
6
|
-
end
|
7
|
-
|
8
|
-
def space?
|
9
|
-
self.matches.curry.call(" \t\n\r").dup.freeze
|
10
|
-
end
|
11
|
-
|
12
|
-
def punctuation?
|
13
|
-
self.matches.curry.call("()[]{}").dup.freeze
|
14
|
-
end
|
15
|
-
|
16
|
-
def symbolic?
|
17
|
-
self.matches.curry.call("~`!@#%$^&*-+<=>\\/|").dup.freeze
|
18
|
-
end
|
19
|
-
|
20
|
-
def numeric?
|
21
|
-
self.matches.curry.call("0123456789").dup.freeze
|
22
|
-
end
|
23
|
-
|
24
|
-
def alpanumeric?
|
25
|
-
self.matches.curry.call("abcdefghijklmnopqrstuvwxyz_'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789").dup.freeze
|
26
|
-
end
|
27
|
-
|
28
|
-
def lexwhile(prop, inp)
|
29
|
-
tokl = inp.split("").take_while { |c| prop.call(c) }.inject(:+)
|
30
|
-
tokl = "" if tokl.nil?
|
31
|
-
return tokl, inp[tokl.length..-1]
|
32
|
-
end
|
33
|
-
|
34
|
-
def lex(inp)
|
35
|
-
inp, rest = self.lexwhile(self.space?, inp)
|
36
|
-
return [] if rest == "" || rest.nil?
|
37
|
-
c = rest[0]
|
38
|
-
cs = rest[1..-1]
|
39
|
-
prop = if self.alpanumeric?.call(c) then self.alpanumeric?
|
40
|
-
elsif self.symbolic?.call(c) then self.symbolic?
|
41
|
-
else proc { false } end
|
42
|
-
toktl, rest = self.lexwhile prop, cs
|
43
|
-
[c+toktl] + lex(rest)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|