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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9284e24b8881153af1c176da6c00ad1d941e9865
4
- data.tar.gz: c7b867612d502482258b27a8c3394ed4a3108021
3
+ metadata.gz: 7bb9d290e43ab1740a0ae02f2fd3114cd97a5551
4
+ data.tar.gz: 9d0f9212637e9305900abb80d0b173eef4cbdaf8
5
5
  SHA512:
6
- metadata.gz: 52e4914ee2c6494410df25eb227410a1c6937721b9294968c7fe9ef61f55ba7c1fd8922c4e6b96414357b26033d7a70be0e74046ad003b3018ac5d8fece54c0a
7
- data.tar.gz: baa4ae312af5b6eb16d81887d02f823111097388236f0c566583aa57a4a15b7738294852b7cefae4b6241a45cfb4500442dfb7db3ffcbf52d149dd488f75cdb8
6
+ metadata.gz: 9dfa67b219f98a724c0e1bb145ba540f185e711510f650be7d3f43b10262ff928b67813547bd73ba99e66b0cca35b93461f1f3f8db98eea5ff704c76431b57f9
7
+ data.tar.gz: d652a9ad06ede5fb9ca5bda81b6ab3a0d5aa1d77b489958ef64156d81b0111c8acb27bc270cdb84e0977167615849288b468e49610b8ba81397542f5910afba3
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- satre (0.1.0)
4
+ satre (1.0.0)
5
5
  terminal-table
6
6
 
7
7
  GEM
@@ -10,6 +10,8 @@ GEM
10
10
  ast (2.1.0)
11
11
  astrolabe (1.3.1)
12
12
  parser (~> 2.2)
13
+ codeclimate-test-reporter (0.4.8)
14
+ simplecov (>= 0.7.1, < 1.0.0)
13
15
  coderay (1.1.0)
14
16
  diff-lcs (1.2.5)
15
17
  docile (1.1.5)
@@ -95,6 +97,7 @@ PLATFORMS
95
97
 
96
98
  DEPENDENCIES
97
99
  bundler (~> 1.10)
100
+ codeclimate-test-reporter
98
101
  guard-bundler
99
102
  guard-minitest
100
103
  guard-rubocop
data/README.md CHANGED
@@ -36,30 +36,32 @@ The see the results of the exercise run `./bin/exercise` from the root directory
36
36
  To embed proportional logic solving in your project one can use `String#to_formula`, on a well formed proportional logic string.
37
37
  Possible operations are
38
38
 
39
- * True value `"True"`
40
- * False value `"False"`
39
+ * True value `"true"`
40
+ * False value `"false"`
41
41
  * Atomic logical variable `"A"` (or any other alphanumeric combination)
42
42
  * logical negation `"~A"`
43
43
  * logical and `"A /\\ B"`
44
44
  * logical or `"A \\/ B"`
45
45
  * Implies `"A <=> B"`
46
- * If and only if `"A => B"`
46
+ * If and only if `"A ==> B"`
47
47
  * Entails `"A |= B"`
48
+ * Forall `"forall x. y"`
49
+ * Exists `"exists x. y"`
48
50
 
49
51
  An example
50
52
 
51
53
  ```ruby
52
- formula = '(Fire => Smoke) /\\ Fire /\\ ~Smoke'.to_formula
54
+ formula = '(Fire ==> Smoke) /\\ Fire /\\ ~Smoke'.to_formula
53
55
  ```
54
56
 
55
57
  To evaluate a formula use `Satre::Formula#eval`
56
58
 
57
59
  ```ruby
58
- formula = '(Fire => Smoke) /\\ Fire /\\ ~Smoke'.to_formula
59
- formula.eval 'Fire' => true, 'Smoke' => true
60
+ formula = '(Fire ==> Smoke) /\\ Fire /\\ ~Smoke'.to_formula
61
+ formula.eval Fire: true, Smoke: true
60
62
  ```
61
63
 
62
- Further are provided `Satre::Formula#tauntolgy?`,`Satre::Formula#satisfiable?`,`Satre::Formula#unsatisfiable?`
64
+ Further are provided `Satre::Formula#tauntolgy?`,`Satre::Formula#satisfiable?`,`Satre::Formula#unsatisfiable?`, `Satre::Formula#holds?`,`Satre::Formula#wellformed?`
63
65
 
64
66
  For further information see the doc.
65
67
 
@@ -6,16 +6,17 @@ require 'terminal-table'
6
6
 
7
7
  include Satre
8
8
 
9
- problem_4_1_1 = 'False |= True'.to_formula
10
- problem_4_1_2 = 'True |= False'.to_formula
9
+ problem_4_1_1 = 'false |= true'.to_formula
10
+ problem_4_1_2 = 'true |= false'.to_formula
11
11
  problem_4_1_3 = '(A /\\ B) |= (A <=> B)'.to_formula
12
12
  problem_4_1_4 = '(A <=> B) |= A \\/ B'.to_formula
13
13
  problem_4_1_5 = '(A <=> B) |= ~A \\/ B'.to_formula
14
14
 
15
- problem_4_2_1 = 'Smoke => Smoke'.to_formula
16
- problem_4_2_2 = '(Smoke => Fire) => (~Smoke => ~Fire)'.to_formula
15
+ problem_4_2_1 = 'Smoke ==> Smoke'.to_formula
16
+ problem_4_2_2 = '(Smoke ==> Fire) ==> (~Smoke ==> ~Fire)'.to_formula
17
17
  problem_4_2_3 = 'Smoke \\/ Fire \\/ ~Fire'.to_formula
18
- problem_4_2_4 = '(Fire => Smoke) /\\ Fire /\\ ~Smoke'.to_formula
18
+ problem_4_2_4 = '(Fire ==> Smoke) /\\ Fire /\\ ~Smoke'.to_formula
19
+
19
20
 
20
21
  bsays = 'b <=> (a <=> ~a)'.to_formula
21
22
  csays = 'c <=> ~b'.to_formula
@@ -29,6 +30,33 @@ b_is_knave = Entails.new(kb,'~b'.to_formula)
29
30
  c_is_knight = Entails.new(kb,'c'.to_formula)
30
31
  c_is_knave = Entails.new(kb,'~c'.to_formula)
31
32
 
33
+ problem_5_1_1_1 = 'g(d,d)'.to_term
34
+ problem_5_1_1_2 = 'f(x,g(y,z),d)'.to_term
35
+ problem_5_1_1_3 = 'g(x,f(y,z),d)'.to_term
36
+ problem_5_1_1_4 = 'f(x,h(x,z),d)'.to_term
37
+ sig_5_1_1 = {d: 0, f: 2, g: 3}
38
+
39
+ problem_5_1_2_1 = 'S(m, x)'.to_formula
40
+ p problem_5_1_2_1
41
+ problem_5_1_2_2 = 'B(m, f(m))'.to_formula
42
+ problem_5_1_2_3 = 'B(B(m,x),y)'.to_formula
43
+ problem_5_1_2_4 = 'B(x,y) ==> (exists z. S(z,y))'.to_formula
44
+ problem_5_1_2_5 = 'S(x,y) ==> S(y,f(f(x)))'.to_formula
45
+ sig_5_1_2 = {m: 0, f: 1, S: 2, B: 2}
46
+
47
+ axiom_1 = "forall x. x = x".to_formula
48
+ axiom_2 = "forall x y. (x = y ==> y = x)".to_formula
49
+ axiom_3 = "forall x y z. (x = y /\\ y = x ==> x = z)".to_formula
50
+
51
+ domain = (0..23).to_a
52
+ valudation = {}
53
+ func = ->(f, args) {}
54
+ empty = ->(p, args) { if p == '=' then false else fail "undefined predicate #{p}" end }
55
+ universal = ->(p, args) { if p == '=' then true else fail "undefined predicate #{p}" end }
56
+ equality = ->(p, args) { if p == '=' then args.inject(:==) else fail "undefined predicate #{p}" end }
57
+ even_sum = ->(p, args) { if p == '=' then args.inject(:+).even? else fail "undefined predicate #{p}" end }
58
+ modular_aritmetic = ->(p, args) { if p == '=' then args[0] == (args[1] % 16) else fail "undefined predicate #{p}" end }
59
+
32
60
  problem_4_1 = Terminal::Table.new do |t|
33
61
  t.title = 'Problem 4.1'
34
62
  t.headings = ['', 'Formula', 'Result' ]
@@ -39,7 +67,6 @@ problem_4_1 = Terminal::Table.new do |t|
39
67
  t << ['5.', problem_4_1_5, problem_4_1_5.eval ]
40
68
  end
41
69
 
42
-
43
70
  problem_4_2 = Terminal::Table.new do |t|
44
71
  t.title = 'Problem 4.2'
45
72
  t.headings = ['', 'Formula', 'tauntolgy?', 'satifiable?', 'unsatifiable?']
@@ -56,15 +83,44 @@ problem_4_3 = Terminal::Table.new do |t|
56
83
  t << ['is knave?', a_is_knave.eval , b_is_knave.eval , c_is_knave.eval ]
57
84
  end
58
85
 
86
+ problem_5_1_1 = Terminal::Table.new do |t|
87
+ t.title = 'Problem 5.1.1'
88
+ t.headings = ['', 'Term', 'Signature', 'wellformed?']
89
+ t << ['1.', problem_5_1_1_1, sig_5_1_1.to_s, problem_5_1_1_1.wellformed?(sig_5_1_1) ]
90
+ t << ['2.', problem_5_1_1_2, sig_5_1_1.to_s, problem_5_1_1_2.wellformed?(sig_5_1_1) ]
91
+ t << ['3.', problem_5_1_1_3, sig_5_1_1.to_s, problem_5_1_1_3.wellformed?(sig_5_1_1) ]
92
+ t << ['4.', problem_5_1_1_4, sig_5_1_1.to_s, problem_5_1_1_4.wellformed?(sig_5_1_1) ]
93
+ end
94
+
95
+ problem_5_1_2 = Terminal::Table.new do |t|
96
+ t.title = 'Problem 5.1.2'
97
+ t.headings = ['', 'Formula', 'Signature', 'wellformed?']
98
+ t << ['1.', problem_5_1_2_1, sig_5_1_2.to_s, problem_5_1_2_1.wellformed?(sig_5_1_2) ]
99
+ t << ['2.', problem_5_1_2_2, sig_5_1_2.to_s, problem_5_1_2_2.wellformed?(sig_5_1_2) ]
100
+ t << ['3.', problem_5_1_2_3, sig_5_1_2.to_s, problem_5_1_2_3.wellformed?(sig_5_1_2) ]
101
+ t << ['4.', problem_5_1_2_4, sig_5_1_2.to_s, problem_5_1_2_4.wellformed?(sig_5_1_2) ]
102
+ t << ['5.', problem_5_1_2_5, sig_5_1_2.to_s, problem_5_1_2_5.wellformed?(sig_5_1_2) ]
103
+ end
104
+
105
+ problem_5_2 = Terminal::Table.new do |t|
106
+ t.title = 'Problem 5.2'
107
+ t.headings = ['relation', "#{axiom_1}.holds?", "#{axiom_2}.holds?", "#{axiom_3}.holds?"]
108
+ t << ['empty', axiom_1.holds?(domain, func, empty, valudation), axiom_2.holds?(domain, func, empty, valudation), axiom_3.holds?(domain, func, empty, valudation)]
109
+ t << ['universal', axiom_1.holds?(domain, func, universal, valudation), axiom_2.holds?(domain, func, universal, valudation), axiom_3.holds?(domain, func, universal, valudation)]
110
+ t << ['equality', axiom_1.holds?(domain, func, equality, valudation), axiom_2.holds?(domain, func, equality, valudation), axiom_3.holds?(domain, func, equality, valudation)]
111
+ t << ['even sum', axiom_1.holds?(domain, func, even_sum, valudation), axiom_2.holds?(domain, func, even_sum, valudation), axiom_3.holds?(domain, func, even_sum, valudation)]
112
+ t << ['modular aritmetic', axiom_1.holds?(domain, func, modular_aritmetic, valudation), axiom_2.holds?(domain, func, modular_aritmetic, valudation), axiom_3.holds?(domain, func, modular_aritmetic, valudation)]
113
+ end
59
114
 
60
115
  puts problem_4_1
61
116
  puts """I used a similar approach in my pencil-and-paper derivations
62
117
  first subtitude the entails a |= b with a /\\ ~b and then check this statement
63
118
  on unsatisfiability.
64
119
  """
65
-
66
120
  puts problem_4_2
67
121
  puts problem_4_3
68
-
69
122
  puts """This approach uses the entails functions to solve the puzzle,
70
123
  while in the exercise we substituded with the rules until clear statements were made."""
124
+ puts problem_5_1_1
125
+ puts problem_5_1_2
126
+ puts problem_5_2
@@ -1,6 +1,4 @@
1
1
  require 'satre/version'
2
- require 'satre/expression'
3
- require 'satre/lexer'
2
+ require 'satre/errors'
4
3
  require 'satre/formula'
5
4
  require 'satre/parser'
6
- require 'satre/formula_parser'
@@ -0,0 +1,3 @@
1
+ require 'satre/errors/expression_error'
2
+ require 'satre/errors/parser_error'
3
+ require 'satre/errors/argument_error'
@@ -0,0 +1,2 @@
1
+ class ArgumentError < StandardError
2
+ end
@@ -0,0 +1,2 @@
1
+ class ExpressionError < StandardError
2
+ end
@@ -0,0 +1,2 @@
1
+ class ParserError < StandardError
2
+ end
@@ -1,10 +1,4 @@
1
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'
2
+ require 'satre/formula/term'
3
+ require 'satre/formula/propositional_logic'
4
+ require 'satre/formula/first_order_logic'
@@ -0,0 +1,4 @@
1
+ require 'satre/formula/first_order_logic/exists'
2
+ require 'satre/formula/first_order_logic/fol_formula'
3
+ require 'satre/formula/first_order_logic/forall'
4
+ require 'satre/formula/first_order_logic/relation'
@@ -0,0 +1,32 @@
1
+ require 'satre/formula/first_order_logic/fol_formula'
2
+
3
+ module Satre
4
+ class Exists < Fol_Formula
5
+ attr_reader :variable
6
+ attr_reader :term
7
+
8
+ def initialize(variable, term)
9
+ #fail(ArgumentError, '...') unless variable.is_a?(Formula)
10
+ #fail(ArgumentError, '...') unless term.is_a?(Formula)
11
+ @variable = variable.dup.freeze
12
+ @term = term.dup.freeze
13
+ end
14
+
15
+ # exists x. p is well-formed if p is well-formed
16
+ def wellformed?(sig)
17
+ term.wellformed?(sig)
18
+ end
19
+
20
+ # Exists(x,p) -> exists (fun a -> holds m ((x |-> a) v) p) domain;;
21
+ def holds?(domain, func, pred, valudation)
22
+ domain.any? do |a|
23
+ valudation[variable.to_s.to_sym] = a
24
+ term.holds?(domain, func, pred, valudation )
25
+ end
26
+ end
27
+
28
+ def to_s
29
+ "∃ #{variable}. #{term}"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,35 @@
1
+ require 'satre/formula/formula'
2
+
3
+ module Satre
4
+ class Fol_Formula < Formula
5
+
6
+ # let rec holds (domain, func, pred as m) v fm =
7
+ # match fm with
8
+ # False -> false
9
+ # | True -> true
10
+ # | Atom(R(r,args)) -> pred r (map (termval m v) args)
11
+ # | Not(p) -> not(holds m v p)
12
+ # | And(p,q) -> (holds m v p) & (holds m v q)
13
+ # | Or(p,q) -> (holds m v p) or (holds m v q)
14
+ # | Imp(p,q) -> not(holds m v p) or (holds m v q)
15
+ # | Iff(p,q) -> (holds m v p = holds m v q)
16
+ # | Forall(x,p) -> forall (fun a -> holds m ((x |-> a) v) p) domain
17
+ # | Exists(x,p) -> exists (fun a -> holds m ((x |-> a) v) p) domani;;
18
+ def holds?(domain, func, predicate, valudation)
19
+ fail 'abstract method'
20
+ end
21
+
22
+ # 1. Constant True and False are wellformed
23
+ # 2. Predicate $p(x_1, \dots, x_n)$ is well-formed if
24
+ # (a) Each term is $x_1, \dots, x_n$ is well formed
25
+ # (b) There is a pair (q, m) in signature sig q = p and n = m
26
+ # 3. p //\ q is wellformed if p and q are wellformed
27
+ # 4. p \// q is wellformed if p and q are wellformed
28
+ # 5. p ==> q is wellformed if p and q are wellformed
29
+ # 6. p <=> q is wellformed if p and q are wellformed
30
+ # 7. forall x. p and exists x. p are wellformed if p is wellformed
31
+ def wellformed?(signature)
32
+ fail 'abstract method'
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,32 @@
1
+ require 'satre/formula/first_order_logic/fol_formula'
2
+
3
+ module Satre
4
+ class Forall < Fol_Formula
5
+ attr_reader :variable
6
+ attr_reader :term
7
+
8
+ def initialize(variable, term)
9
+ #fail(ArgumentError, "Variable was #{variable.class}") unless variable.is_a?(Formula)
10
+ #fail(ArgumentError, "Term was #{term.class}") unless term.is_a?(Formula)
11
+ @variable = variable.dup.freeze
12
+ @term = term.dup.freeze
13
+ end
14
+
15
+ # forall x. p is well-formed if p is well-formed
16
+ def wellformed?(sig)
17
+ term.wellformed?(sig)
18
+ end
19
+
20
+ # | Forall(x,p) -> forall (fun a -> holds m ((x |-> a) v) p) domain
21
+ def holds?(domain, func, pred, valudation)
22
+ domain.all? do |a|
23
+ valudation[variable.to_s.to_sym] = a
24
+ term.holds?(domain, func, pred, valudation)
25
+ end
26
+ end
27
+
28
+ def to_s
29
+ "∀ #{variable}. #{term}"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,38 @@
1
+ require 'satre/formula/first_order_logic/fol_formula'
2
+
3
+ module Satre
4
+ # A first-order-logig relation between terms
5
+ #
6
+ # Typical relations are
7
+ # p > q - term p is greater than term p
8
+ # p < q - term p is less than term p
9
+ # p = q - term p is equvivalent to term p
10
+ # p >= q - term p is greter or equvivalent to term q
11
+ # p <= q - term p is less or equvivalent to term q
12
+ # p != q - term p is not equvivalent to term q
13
+ class Relation < Fol_Formula
14
+ attr_reader :relation
15
+ attr_reader :term_list
16
+
17
+ def initialize(relation, term_list)
18
+ @relation = relation.dup.freeze
19
+ @term_list = term_list.dup.freeze
20
+ end
21
+
22
+ def holds?(domain, func, predicate, valudation)
23
+ predicate.call(relation, term_list.map { |t| t.validate(func, predicate, valudation) })
24
+ end
25
+ # A predicate p(x_1,...,x_n) is well-formed if
26
+ # (a) each term x_1,...,x_n is well-formed
27
+ # (b) there is a pair (q, m) in signature sig where q = p and n = m
28
+ def wellformed?(sig)
29
+ term_list.all? { |x| x.wellformed?(sig) } && sig[relation.to_sym] == term_list.length
30
+ end
31
+
32
+ def to_s
33
+ return term_list.map(&:to_s).join(relation.to_s) if ['>','<','=','<=','>=','!='].include?(relation)
34
+ s = term_list.map(&:to_s).join(',')
35
+ "#{relation}#{"("+s+")" unless s.to_s == ''}"
36
+ end
37
+ end
38
+ end
@@ -3,18 +3,7 @@ module Satre
3
3
  include Comparable
4
4
 
5
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
6
+ self.to_s <=> other.to_s
18
7
  end
19
8
 
20
9
  def atoms
@@ -53,7 +42,6 @@ module Satre
53
42
  end
54
43
 
55
44
  def entails?(other)
56
- #Imp.new(self, other).tautology?
57
45
  And.new(self, Not.new(other)).unsatifiable?
58
46
  end
59
47
 
@@ -0,0 +1,9 @@
1
+ require 'satre/formula/propositional_logic/and'
2
+ require 'satre/formula/propositional_logic/atom'
3
+ require 'satre/formula/propositional_logic/entails'
4
+ require 'satre/formula/propositional_logic/false'
5
+ require 'satre/formula/propositional_logic/iff'
6
+ require 'satre/formula/propositional_logic/imp'
7
+ require 'satre/formula/propositional_logic/not'
8
+ require 'satre/formula/propositional_logic/or'
9
+ require 'satre/formula/propositional_logic/true'
@@ -0,0 +1,37 @@
1
+ require 'satre/formula'
2
+
3
+ module Satre
4
+ class And < Formula
5
+ attr_reader :left_conjunct
6
+ attr_reader :right_conjunct
7
+
8
+ def initialize(left_conjunct, right_conjunct)
9
+ fail(ArgumentError, 'Argument must be a Formula') unless left_conjunct.is_a?(Formula)
10
+ fail(ArgumentError, 'Argument must be a Formula') unless right_conjunct.is_a?(Formula)
11
+ @left_conjunct = left_conjunct.dup.freeze
12
+ @right_conjunct = right_conjunct.dup.freeze
13
+ end
14
+
15
+ def to_s
16
+ "(#{left_conjunct} ∧ #{right_conjunct})"
17
+ end
18
+
19
+ def holds?(domain, func, pred, valudation)
20
+ left_conjunct.holds?(domain, func, pred, valudation) && right_conjunct.holds?(domain, func, pred, valudation)
21
+ end
22
+
23
+ # p /\\ q is well-formed if p and q are well-formed
24
+ def wellformed?(sig)
25
+ left_conjunct.wellformed?(sig) && right_conjunct.wellformed(sig)
26
+ end
27
+
28
+ def eval(valudation)
29
+ left_conjunct.eval(valudation) && right_conjunct.eval(valudation)
30
+ end
31
+
32
+ def atoms
33
+ atoms = left_conjunct.atoms + right_conjunct.atoms
34
+ atoms.uniq || []
35
+ end
36
+ end
37
+ end