dpll_solver 0.0.1

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 (40) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +2 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +62 -0
  7. data/Rakefile +9 -0
  8. data/dpll_solver.gemspec +35 -0
  9. data/lib/dpll_solver.rb +115 -0
  10. data/lib/dpll_solver/atomic_formula.rb +34 -0
  11. data/lib/dpll_solver/formulas/and.rb +54 -0
  12. data/lib/dpll_solver/formulas/binary_formula.rb +33 -0
  13. data/lib/dpll_solver/formulas/clause.rb +52 -0
  14. data/lib/dpll_solver/formulas/falsum.rb +18 -0
  15. data/lib/dpll_solver/formulas/literal.rb +25 -0
  16. data/lib/dpll_solver/formulas/not.rb +84 -0
  17. data/lib/dpll_solver/formulas/or.rb +64 -0
  18. data/lib/dpll_solver/formulas/variable.rb +26 -0
  19. data/lib/dpll_solver/formulas/verum.rb +18 -0
  20. data/lib/dpll_solver/heuristics/most_frequent_literal.rb +22 -0
  21. data/lib/dpll_solver/parsers/dimacs_parser.rb +46 -0
  22. data/lib/dpll_solver/parsers/parser.rb +53 -0
  23. data/lib/dpll_solver/version.rb +3 -0
  24. data/spec/dpll/dpll_solver_spec.rb +114 -0
  25. data/spec/formulas/and_spec.rb +75 -0
  26. data/spec/formulas/clause_spec.rb +55 -0
  27. data/spec/formulas/falsum_spec.rb +42 -0
  28. data/spec/formulas/formulas_spec.rb +47 -0
  29. data/spec/formulas/literal_spec.rb +26 -0
  30. data/spec/formulas/not_spec.rb +77 -0
  31. data/spec/formulas/or_spec.rb +74 -0
  32. data/spec/formulas/variable_spec.rb +44 -0
  33. data/spec/formulas/verum_spec.rb +42 -0
  34. data/spec/heuristics/most_frequent_literal_spec.rb +19 -0
  35. data/spec/parsers/dimacs_parser_spec.rb +23 -0
  36. data/spec/parsers/grammar_spec.rb +54 -0
  37. data/spec/parsers/parser_spec.rb +23 -0
  38. data/spec/parsers/transformer_spec.rb +30 -0
  39. data/spec/spec_helper.rb +4 -0
  40. metadata +183 -0
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe DpllSolver::Formulas::And do
4
+ let(:falsum) { DpllSolver::Formulas::Falsum }
5
+ let(:verum) { DpllSolver::Formulas::Verum }
6
+ let(:var1) { DpllSolver::Formulas::Variable.new("x1") }
7
+ let(:var2) { DpllSolver::Formulas::Variable.new("x2") }
8
+ let(:f1) { DpllSolver::Formulas::Not.new(var1)}
9
+ let(:f2) { DpllSolver::Formulas::And.new(var1, var2)}
10
+ let(:f3) { DpllSolver::Formulas::And.new(f1, f2)}
11
+ let(:f4) { DpllSolver::Formulas::And.new(f1, DpllSolver::Formulas::Not.new(f2))}
12
+ it 'should convert to string' do
13
+ expect(f2.to_s).to eql "(x1 AND x2)"
14
+ expect(f3.to_s).to eql "((NOT x1) AND (x1 AND x2))"
15
+ expect(f4.to_s).to eql "((NOT x1) AND (NOT (x1 AND x2)))"
16
+ end
17
+
18
+ it 'should test syntactic eqivalenz' do
19
+ expect(f2 == f2).to eql true
20
+ expect(f2 == DpllSolver::Formulas::And.new(var1, var2)).to eql true
21
+ expect(f2 == f3).to eql false
22
+ end
23
+
24
+ it 'should not be a literal' do
25
+ expect(f2.literal?).to eql false
26
+ expect(f3.literal?).to eql false
27
+ expect(f4.literal?).to eql false
28
+ end
29
+
30
+ it 'should not be a atomic formula' do
31
+ expect(f2.atomic_formula?).to eql false
32
+ expect(f3.atomic_formula?).to eql false
33
+ expect(f4.atomic_formula?).to eql false
34
+ end
35
+
36
+ it 'should not be a clause' do
37
+ expect(f2.clause?).to eql false
38
+ expect(f3.clause?).to eql false
39
+ expect(f4.clause?).to eql false
40
+ end
41
+
42
+ it 'should be a min term if both formulas are min term' do
43
+ expect(f2.min_term?).to eql true
44
+ expect(f3.min_term?).to eql true
45
+ expect(f4.min_term?).to eql false
46
+ end
47
+
48
+ it 'should be a nnf, cnf, dnf if both formulas are in nnf, cnf or dnf' do
49
+ expect(f2.nnf?).to eql true
50
+ expect(f2.cnf?).to eql true
51
+ expect(f2.dnf?).to eql true
52
+ expect(f3.nnf?).to eql true
53
+ expect(f3.cnf?).to eql true
54
+ expect(f3.dnf?).to eql true
55
+ expect(f4.nnf?).to eql false
56
+ expect(f4.cnf?).to eql false
57
+ expect(f4.dnf?).to eql false
58
+ end
59
+
60
+ it 'should simply and' do
61
+ and_falsum1= DpllSolver::Formulas::And.new(var1, falsum)
62
+ and_verum1 = DpllSolver::Formulas::And.new(var1, verum)
63
+ and_falsum2 = DpllSolver::Formulas::And.new(falsum, var2)
64
+ and_verum2 = DpllSolver::Formulas::And.new(verum, var2)
65
+ not_f1 = DpllSolver::Formulas::Not.new(f1)
66
+ and_not = DpllSolver::Formulas::And.new(not_f1, var1)
67
+ expect(and_falsum1.simplify).to eql falsum
68
+ expect(and_falsum2.simplify).to eql falsum
69
+ expect(and_verum1.simplify).to eql var1
70
+ expect(and_verum2.simplify).to eql var2
71
+ expect(and_not.simplify).to eql var1
72
+ end
73
+
74
+ end
75
+
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe DpllSolver::Formulas::Clause do
4
+ let(:var1) { DpllSolver::Formulas::Variable.new("x1") }
5
+ let(:var2) { DpllSolver::Formulas::Variable.new("x2") }
6
+ let(:lit1) { DpllSolver::Formulas::Literal.new(var1, true) }
7
+ let(:lit1_neg) { DpllSolver::Formulas::Literal.new(var1, false) }
8
+ let(:lit2) { DpllSolver::Formulas::Literal.new(var2, true) }
9
+ let(:c) { DpllSolver::Formulas::Clause.new()}
10
+ let(:c1) { DpllSolver::Formulas::Clause.new(lit1)}
11
+ let(:c2) { DpllSolver::Formulas::Clause.new(lit1, lit2)}
12
+
13
+ it 'should test if clause is a unit clause' do
14
+ expect(c1.unit?).to eql true
15
+ expect(c2.unit?).to eql false
16
+ end
17
+
18
+ it 'should add and remove literal to clause' do
19
+ expect(c1.add(lit2)).to eql c2
20
+ c2.delete(lit2)
21
+ expect(c2.unit?).to eql true
22
+ expect(c2.delete(DpllSolver::Formulas::Literal.new(var1, true)).empty?).to eql true
23
+ end
24
+
25
+ it 'should detect if a clause is empty' do
26
+ expect(c.empty?).to eql true
27
+ expect(c1.empty?).to eql false
28
+ end
29
+
30
+ it 'should detect if a clause contains the given literal' do
31
+ expect(c.include?(lit1)).to eql false
32
+ expect(c1.include?(lit1)).to eql true
33
+ end
34
+
35
+ it 'should union a clause to an other' do
36
+ c.union(c1)
37
+ expect(c).to eql c1
38
+ end
39
+
40
+ it 'should get the unit literal' do
41
+ c2.add(lit1_neg)
42
+ expect(c2.get_unit_literal.nil?).to eql true
43
+ expect(c1.get_unit_literal).to eql lit1
44
+ end
45
+
46
+ it 'should compare two clauses' do
47
+ expect(c == c).to eql true
48
+ expect(c1 == DpllSolver::Formulas::Clause.new(lit1)).to eql true
49
+ expect(c1 == c2).to eql false
50
+ end
51
+
52
+ it 'should convert clause to string' do
53
+ expect(c2.to_s).to eql "{x1, x2}"
54
+ end
55
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe DpllSolver::Formulas::Falsum do
4
+ let(:falsum) { DpllSolver::Formulas::Falsum }
5
+ it 'should be "0" as string' do
6
+ expect(falsum.to_s).to eql "0"
7
+ end
8
+
9
+ it 'should test syntactic eqivalenz' do
10
+ expect(falsum == DpllSolver::Formulas::Falsum).to eql true
11
+ expect(falsum == DpllSolver::Formulas).to eql false
12
+ end
13
+
14
+ it 'should be a literal' do
15
+ expect(falsum.literal?).to eql true
16
+ end
17
+
18
+ it 'should be a atomic formula' do
19
+ expect(falsum.atomic_formula?).to eql true
20
+ end
21
+
22
+ it 'should be a min term' do
23
+ expect(falsum.min_term?).to eql true
24
+ end
25
+
26
+ it 'should be a nnf' do
27
+ expect(falsum.nnf?).to eql true
28
+ end
29
+
30
+ it 'should be a cnf' do
31
+ expect(falsum.cnf?).to eql true
32
+ end
33
+
34
+ it 'should be a dnf' do
35
+ expect(falsum.dnf?).to eql true
36
+ end
37
+
38
+ it 'should simplify falsum' do
39
+ expect(falsum.simplify).to eql falsum
40
+ end
41
+ end
42
+
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe DpllSolver::Formulas do
4
+ let(:falsum) { DpllSolver::Formulas::Falsum }
5
+ let(:verum) { DpllSolver::Formulas::Verum }
6
+ let(:var1) { DpllSolver::Formulas::Variable.new("x1") }
7
+ let(:var2) { DpllSolver::Formulas::Variable.new("x2") }
8
+
9
+ it 'should convert a formula correctly to nnf' do
10
+ expect(falsum.nnf).to eql falsum
11
+ expect(verum.nnf).to eql verum
12
+ expect(var1.nnf).to eql var1
13
+
14
+ #more complex formulas
15
+ f = DpllSolver::Formulas::Not.new(DpllSolver::Formulas::And.new(var1, falsum))
16
+ f_nnf = DpllSolver::Formulas::Or.new(DpllSolver::Formulas::Not.new(var1), DpllSolver::Formulas::Not.new(falsum))
17
+ expect(f.nnf).to eql f_nnf
18
+
19
+ f = DpllSolver::Formulas::Not.new(DpllSolver::Formulas::Or.new(DpllSolver::Formulas::And.new(var1, var2), DpllSolver::Formulas::Not.new(DpllSolver::Formulas::Or.new(falsum, var2))))
20
+ f_nnf = DpllSolver::Formulas::And.new(DpllSolver::Formulas::Or.new(DpllSolver::Formulas::Not.new(var1), DpllSolver::Formulas::Not.new(var2)), DpllSolver::Formulas::Or.new(falsum, var2))
21
+ expect(f.nnf).to eql f_nnf
22
+
23
+ f = DpllSolver::Formulas::Or.new(DpllSolver::Formulas::Not.new(DpllSolver::Formulas::Or.new(DpllSolver::Formulas::And.new(var1, falsum), var2)), verum)
24
+ f_nnf = DpllSolver::Formulas::Or.new(DpllSolver::Formulas::And.new(DpllSolver::Formulas::Or.new(DpllSolver::Formulas::Not.new(var1), DpllSolver::Formulas::Not.new(falsum)), DpllSolver::Formulas::Not.new(var2)), verum)
25
+ expect(f.nnf).to eql f_nnf
26
+ end
27
+
28
+ it 'should convert a formula correctly to cnf' do
29
+ expect(falsum.cnf).to eql falsum
30
+ expect(verum.cnf).to eql verum
31
+ expect(var1.cnf).to eql var1
32
+
33
+ #more complex formulas
34
+ f = DpllSolver::Formulas::Not.new(DpllSolver::Formulas::And.new(var1, falsum))
35
+ f_cnf = DpllSolver::Formulas::Or.new(DpllSolver::Formulas::Not.new(var1), DpllSolver::Formulas::Not.new(falsum))
36
+ expect(f.cnf).to eql f_cnf
37
+
38
+ f = DpllSolver::Formulas::Not.new(DpllSolver::Formulas::Or.new(DpllSolver::Formulas::And.new(var1, var2), DpllSolver::Formulas::Not.new(DpllSolver::Formulas::Or.new(falsum, var2))))
39
+ f_cnf = DpllSolver::Formulas::And.new(DpllSolver::Formulas::Or.new(DpllSolver::Formulas::Not.new(var1), DpllSolver::Formulas::Not.new(var2)), DpllSolver::Formulas::Or.new(falsum, var2))
40
+ expect(f.cnf).to eql f_cnf
41
+
42
+ f = DpllSolver::Formulas::Or.new(DpllSolver::Formulas::Not.new(DpllSolver::Formulas::Or.new(DpllSolver::Formulas::And.new(var1, falsum), var2)), verum)
43
+ f_cnf = DpllSolver::Formulas::And.new(DpllSolver::Formulas::Or.new(DpllSolver::Formulas::Or.new(DpllSolver::Formulas::Not.new(var1), DpllSolver::Formulas::Not.new(falsum)), verum), DpllSolver::Formulas::Or.new(DpllSolver::Formulas::Not.new(var2), verum))
44
+ expect(f.cnf).to eql f_cnf
45
+ end
46
+
47
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe DpllSolver::Formulas::Literal do
4
+ let(:var1) { DpllSolver::Formulas::Variable.new("x1") }
5
+ let(:var2) { DpllSolver::Formulas::Variable.new("x2") }
6
+ let(:lit1) { DpllSolver::Formulas::Literal.new(var1, true) }
7
+ let(:lit1_neg) { DpllSolver::Formulas::Literal.new(var1, false) }
8
+ let(:lit2) { DpllSolver::Formulas::Literal.new(var2, true) }
9
+
10
+ it 'should negate the literal' do
11
+ expect(lit1.negate()).to eql lit1_neg
12
+ expect(lit1_neg.negate()).to eql lit1
13
+ end
14
+
15
+ it 'should convert literal to string' do
16
+ expect(lit2.to_s).to eql "x2"
17
+ expect(lit1.to_s).to eql "x1"
18
+ expect(lit1_neg.to_s).to eql "-x1"
19
+ end
20
+
21
+ it 'should compare two literals' do
22
+ expect(lit1 == lit1).to eql true
23
+ expect(lit1 == lit2).to eql false
24
+ expect(lit1 == lit1_neg).to eql false
25
+ end
26
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+
3
+ describe DpllSolver::Formulas::Not do
4
+ let(:falsum) { DpllSolver::Formulas::Falsum }
5
+ let(:verum) { DpllSolver::Formulas::Verum }
6
+ let(:var1) { DpllSolver::Formulas::Variable.new("x1") }
7
+ let(:var2) { DpllSolver::Formulas::Variable.new("x2") }
8
+ let(:f1) { DpllSolver::Formulas::Not.new(var1)}
9
+ let(:f2) { DpllSolver::Formulas::Not.new(f1)}
10
+ let(:f3) { DpllSolver::Formulas::Not.new(DpllSolver::Formulas::Falsum)}
11
+ it 'should convert to string' do
12
+ expect(f1.to_s).to eql "(NOT x1)"
13
+ expect(f2.to_s).to eql "(NOT (NOT x1))"
14
+ expect(f3.to_s).to eql "(NOT 0)"
15
+ end
16
+
17
+ it 'should test syntactic eqivalenz' do
18
+ expect(f1 == f1).to eql true
19
+ expect(f1 == DpllSolver::Formulas::Not.new(var1)).to eql true
20
+ expect(f1 == f2).to eql false
21
+ end
22
+
23
+ it 'should be a literal if contains an atomic formula' do
24
+ expect(f1.literal?).to eql true
25
+ expect(f2.literal?).to eql false
26
+ expect(f3.literal?).to eql true
27
+ end
28
+
29
+ it 'should not be a atomic formula' do
30
+ expect(f1.atomic_formula?).to eql false
31
+ expect(f3.atomic_formula?).to eql false
32
+ end
33
+
34
+ it 'should be a min term if contains an atomic formula' do
35
+ expect(f1.min_term?).to eql true
36
+ expect(f3.min_term?).to eql true
37
+ expect(f2.min_term?).to eql false
38
+ end
39
+
40
+ it 'should be a nnf, cnf, dnf if contains an atomic formula' do
41
+ expect(f1.nnf?).to eql true
42
+ expect(f1.cnf?).to eql true
43
+ expect(f1.dnf?).to eql true
44
+ expect(f3.nnf?).to eql true
45
+ expect(f3.cnf?).to eql true
46
+ expect(f3.dnf?).to eql true
47
+ expect(f2.nnf?).to eql false
48
+ expect(f2.cnf?).to eql false
49
+ expect(f2.dnf?).to eql false
50
+ end
51
+
52
+ it 'should simplify not' do
53
+ not_falsum = DpllSolver::Formulas::Not.new(falsum)
54
+ not_verum = DpllSolver::Formulas::Not.new(verum)
55
+ expect(not_falsum.simplify).to eql verum
56
+ expect(not_verum.simplify).to eql falsum
57
+ expect(f2.simplify).to eql var1
58
+ not_f2 = DpllSolver::Formulas::Not.new(f2)
59
+ expect(not_f2.simplify).to eql f1
60
+ not_not_f2 = DpllSolver::Formulas::Not.new(DpllSolver::Formulas::Not.new(f2))
61
+ expect(not_not_f2.simplify).to eql var1
62
+ end
63
+
64
+ it 'should apply DeMorgan' do
65
+ not_var1 = DpllSolver::Formulas::Not.new(var1)
66
+ not_var2 = DpllSolver::Formulas::Not.new(var2)
67
+ and_f = DpllSolver::Formulas::Not.new(DpllSolver::Formulas::And.new(var1, var2))
68
+ and_f_after = DpllSolver::Formulas::Or.new(not_var1, not_var2)
69
+ or_f = DpllSolver::Formulas::Not.new(DpllSolver::Formulas::Or.new(var1, var2))
70
+ or_f_after = DpllSolver::Formulas::And.new(not_var1, not_var2)
71
+ expect(and_f.apply_DeMorgan).to eql and_f_after
72
+ expect(or_f.apply_DeMorgan).to eql or_f_after
73
+ expect{ f1.apply_DeMorgan }.to raise_error(ArgumentError)
74
+ expect{ f2.apply_DeMorgan }.to raise_error(ArgumentError)
75
+ end
76
+ end
77
+
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ describe DpllSolver::Formulas::Or do
4
+ let(:falsum) { DpllSolver::Formulas::Falsum }
5
+ let(:verum) { DpllSolver::Formulas::Verum }
6
+ let(:var1) { DpllSolver::Formulas::Variable.new("x1") }
7
+ let(:var2) { DpllSolver::Formulas::Variable.new("x2") }
8
+ let(:f1) { DpllSolver::Formulas::Not.new(var1)}
9
+ let(:f2) { DpllSolver::Formulas::Or.new(var1, var2)}
10
+ let(:f3) { DpllSolver::Formulas::Or.new(f1, f2)}
11
+ let(:f4) { DpllSolver::Formulas::Or.new(f1, DpllSolver::Formulas::Not.new(f2))}
12
+ it 'should convert to string' do
13
+ expect(f2.to_s).to eql "(x1 OR x2)"
14
+ expect(f3.to_s).to eql "((NOT x1) OR (x1 OR x2))"
15
+ expect(f4.to_s).to eql "((NOT x1) OR (NOT (x1 OR x2)))"
16
+ end
17
+
18
+ it 'should test syntactic eqivalenz' do
19
+ expect(f2 == f2).to eql true
20
+ expect(f2 == DpllSolver::Formulas::Or.new(var1, var2)).to eql true
21
+ expect(f2 == f3).to eql false
22
+ end
23
+
24
+ it 'should not be a literal' do
25
+ expect(f2.literal?).to eql false
26
+ expect(f3.literal?).to eql false
27
+ expect(f4.literal?).to eql false
28
+ end
29
+
30
+ it 'should not be a atomic formula' do
31
+ expect(f2.atomic_formula?).to eql false
32
+ expect(f3.atomic_formula?).to eql false
33
+ expect(f4.atomic_formula?).to eql false
34
+ end
35
+
36
+ it 'should not be a min term' do
37
+ expect(f2.min_term?).to eql false
38
+ expect(f3.min_term?).to eql false
39
+ expect(f4.min_term?).to eql false
40
+ end
41
+
42
+ it 'should be a clause if both formulas are clause' do
43
+ expect(f2.clause?).to eql true
44
+ expect(f3.clause?).to eql true
45
+ expect(f4.clause?).to eql false
46
+ end
47
+
48
+ it 'should be a nnf, cnf, dnf if both formulas are in nnf, cnf or dnf' do
49
+ expect(f2.nnf?).to eql true
50
+ expect(f2.cnf?).to eql true
51
+ expect(f2.dnf?).to eql true
52
+ expect(f3.nnf?).to eql true
53
+ expect(f3.cnf?).to eql true
54
+ expect(f3.dnf?).to eql true
55
+ expect(f4.nnf?).to eql false
56
+ expect(f4.cnf?).to eql false
57
+ expect(f4.dnf?).to eql false
58
+ end
59
+
60
+ it 'should simply or' do
61
+ or_falsum1= DpllSolver::Formulas::Or.new(var1, falsum)
62
+ or_verum1 = DpllSolver::Formulas::Or.new(var1, verum)
63
+ or_falsum2 = DpllSolver::Formulas::Or.new(falsum, var2)
64
+ or_verum2 = DpllSolver::Formulas::Or.new(verum, var2)
65
+ not_f1 = DpllSolver::Formulas::Not.new(f1)
66
+ or_not = DpllSolver::Formulas::Or.new(not_f1, var1)
67
+ expect(or_falsum1.simplify).to eql var1
68
+ expect(or_falsum2.simplify).to eql var2
69
+ expect(or_verum1.simplify).to eql verum
70
+ expect(or_verum2.simplify).to eql verum
71
+ expect(or_not.simplify).to eql var1
72
+ end
73
+ end
74
+
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe DpllSolver::Formulas::Variable do
4
+ let(:var1) { DpllSolver::Formulas::Variable.new("x1") }
5
+ let(:var2) { DpllSolver::Formulas::Variable.new("x2") }
6
+ it 'should have "x1" as string and name' do
7
+ expect(var1.to_s).to eql "x1"
8
+ expect(var1.name).to eql "x1"
9
+ end
10
+
11
+ it 'should test syntactic eqivalenz' do
12
+ expect(var1 == var2).to eql false
13
+ expect(var1 == DpllSolver::Formulas::Variable.new("x1")).to eql true
14
+ end
15
+
16
+ it 'should be a literal' do
17
+ expect(var1.literal?).to eql true
18
+ end
19
+
20
+ it 'should be a atomic formula' do
21
+ expect(var1.atomic_formula?).to eql true
22
+ end
23
+
24
+ it 'should be a min term' do
25
+ expect(var1.min_term?).to eql true
26
+ end
27
+
28
+ it 'should be a nnf' do
29
+ expect(var1.nnf?).to eql true
30
+ end
31
+
32
+ it 'should be a cnf' do
33
+ expect(var1.cnf?).to eql true
34
+ end
35
+
36
+ it 'should be a dnf' do
37
+ expect(var1.dnf?).to eql true
38
+ end
39
+
40
+ it 'should simplify variable' do
41
+ expect(var1.simplify).to eql var1
42
+ end
43
+ end
44
+