satre 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +4 -1
  3. data/README.md +9 -7
  4. data/bin/exercise +64 -8
  5. data/lib/satre.rb +1 -3
  6. data/lib/satre/errors.rb +3 -0
  7. data/lib/satre/errors/argument_error.rb +2 -0
  8. data/lib/satre/errors/expression_error.rb +2 -0
  9. data/lib/satre/errors/parser_error.rb +2 -0
  10. data/lib/satre/formula.rb +3 -9
  11. data/lib/satre/formula/first_order_logic.rb +4 -0
  12. data/lib/satre/formula/first_order_logic/exists.rb +32 -0
  13. data/lib/satre/formula/first_order_logic/fol_formula.rb +35 -0
  14. data/lib/satre/formula/first_order_logic/forall.rb +32 -0
  15. data/lib/satre/formula/first_order_logic/relation.rb +38 -0
  16. data/lib/satre/formula/formula.rb +1 -13
  17. data/lib/satre/formula/propositional_logic.rb +9 -0
  18. data/lib/satre/formula/propositional_logic/and.rb +37 -0
  19. data/lib/satre/formula/propositional_logic/atom.rb +44 -0
  20. data/lib/satre/formula/propositional_logic/entails.rb +42 -0
  21. data/lib/satre/formula/{false.rb → propositional_logic/false.rb} +9 -2
  22. data/lib/satre/formula/propositional_logic/iff.rb +38 -0
  23. data/lib/satre/formula/propositional_logic/imp.rb +38 -0
  24. data/lib/satre/formula/propositional_logic/not.rb +34 -0
  25. data/lib/satre/formula/propositional_logic/or.rb +37 -0
  26. data/lib/satre/formula/{true.rb → propositional_logic/true.rb} +11 -2
  27. data/lib/satre/formula/term.rb +3 -0
  28. data/lib/satre/formula/term/function.rb +33 -0
  29. data/lib/satre/formula/term/term.rb +6 -0
  30. data/lib/satre/formula/term/variable.rb +24 -0
  31. data/lib/satre/parser.rb +4 -15
  32. data/lib/satre/parser/formula_parser.rb +74 -0
  33. data/lib/satre/parser/lexer.rb +55 -0
  34. data/lib/satre/parser/parser.rb +80 -0
  35. data/lib/satre/parser/term_parser.rb +85 -0
  36. data/lib/satre/version.rb +1 -1
  37. data/satre.gemspec +1 -0
  38. metadata +43 -20
  39. data/lib/satre/expression.rb +0 -6
  40. data/lib/satre/expression/add.rb +0 -26
  41. data/lib/satre/expression/const.rb +0 -23
  42. data/lib/satre/expression/expression.rb +0 -22
  43. data/lib/satre/expression/expression_parser.rb +0 -56
  44. data/lib/satre/expression/mul.rb +0 -30
  45. data/lib/satre/expression/var.rb +0 -14
  46. data/lib/satre/formula/and.rb +0 -26
  47. data/lib/satre/formula/atom.rb +0 -28
  48. data/lib/satre/formula/entails.rb +0 -29
  49. data/lib/satre/formula/iff.rb +0 -27
  50. data/lib/satre/formula/imp.rb +0 -25
  51. data/lib/satre/formula/not.rb +0 -22
  52. data/lib/satre/formula/or.rb +0 -25
  53. data/lib/satre/formula_parser.rb +0 -92
  54. data/lib/satre/lexer.rb +0 -47
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
-
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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