satre 0.1.0 → 1.0.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 +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
|