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.
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