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