predicate 1.2.0 → 1.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 710a45c31d1350beeded48ea522d3e868925e600
4
- data.tar.gz: 8e9acddd67b337218c749aa6744940b26ca8568e
3
+ metadata.gz: 61fec1238a5307709753d2214ed0bf4b07af3790
4
+ data.tar.gz: 8ca0232c14c907971c4bc39b10ddbe3629f2f529
5
5
  SHA512:
6
- metadata.gz: e3d92a4dfa7227cbac8dc6b9dc9e4856861983103e2840ad041721269a66ecce74980750293178b3c3cdc9f34c06aa2d5a396880634f47e84a0b03aaac3a202d
7
- data.tar.gz: ff1eee7dcc029585926d897eb5f3da17b68dd6f392f6e2c73bb50208ae00d22aedf0422feccea4cf747d869555b37dfa720407aa73746dd74935cfd52384f8de
6
+ metadata.gz: a66b05a35406d025a78fa0bc44c1508c3c74906eff4ef2270b8fcc4177aeaf88b9f54ff11d259eaa17aa30bb8b728d00ca08a038efcb98b4e735fecde2ad844e
7
+ data.tar.gz: 88029e029b342093b92a7925ef0ca7edd618e440fc33d99eaf2f128b4cbf0e344639e62aa2768621507582e24f007faff03727bde874b6b0c729e0519d1638c8
@@ -6,6 +6,15 @@ class Predicate
6
6
  :'&&'
7
7
  end
8
8
 
9
+ def &(other)
10
+ case other
11
+ when Tautology then self
12
+ when Contradiction then other
13
+ when And then sexpr(dup + other[1..-1])
14
+ else dup << other
15
+ end
16
+ end
17
+
9
18
  def and_split(attr_list)
10
19
  # Say we are X = X1 & X2 & X3
11
20
  # We will split each term: X = (X1 & Y1) & (X2 & Y2) & (X3 & Y3)
@@ -34,5 +43,15 @@ class Predicate
34
43
  end
35
44
  end
36
45
 
46
+ def constants
47
+ sexpr_body.each_with_object({}) do |op, cs|
48
+ cs.merge!(op.constants){|k,v1,v2| v1 }
49
+ end
50
+ end
51
+
52
+ def evaluate(tuple)
53
+ sexpr_body.all?{|operand| operand.evaluate(tuple) }
54
+ end
55
+
37
56
  end
38
57
  end
@@ -18,6 +18,10 @@ class Predicate
18
18
  other
19
19
  end
20
20
 
21
+ def dyadic_priority
22
+ 1000
23
+ end
24
+
21
25
  def priority
22
26
  100
23
27
  end
@@ -30,5 +34,9 @@ class Predicate
30
34
  { nil => self }
31
35
  end
32
36
 
37
+ def evaluate(tuple)
38
+ false
39
+ end
40
+
33
41
  end
34
42
  end
@@ -6,10 +6,46 @@ class Predicate
6
6
  :==
7
7
  end
8
8
 
9
+ def &(other)
10
+ case other
11
+ when Eq
12
+ if free_variables == other.free_variables
13
+ return self if constants == other.constants
14
+ contradiction
15
+ else
16
+ super
17
+ end
18
+ when In
19
+ return self if free_variables == other.free_variables
20
+ super
21
+ else
22
+ super
23
+ end
24
+ end
25
+
9
26
  def constant_variables
10
27
  fv = free_variables
11
28
  fv.size == 1 ? fv : []
12
29
  end
13
30
 
31
+ def constants
32
+ left, right = sexpr(self.left), sexpr(self.right)
33
+ if left.identifier? && right.literal?
34
+ { left.name => right.value }
35
+ elsif right.identifier? && left.literal?
36
+ { right.name => left.value }
37
+ else
38
+ {}
39
+ end
40
+ end
41
+
42
+ def dyadic_priority
43
+ 900
44
+ end
45
+
46
+ def evaluate(tuple)
47
+ left.evaluate(tuple) == right.evaluate(tuple)
48
+ end
49
+
14
50
  end
15
51
  end
@@ -19,13 +19,26 @@ class Predicate
19
19
  false
20
20
  end
21
21
 
22
+ def literal?
23
+ sexpr_type == :literal
24
+ end
25
+
26
+ def identifier?
27
+ sexpr_type == :identifier
28
+ end
29
+
22
30
  def !
23
31
  sexpr([:not, self])
24
32
  end
25
33
 
34
+ def dyadic_priority
35
+ 0
36
+ end
37
+
26
38
  def &(other)
27
39
  return other if other.contradiction?
28
40
  return self if other.tautology?
41
+ return other & self if other.dyadic_priority > self.dyadic_priority
29
42
  sexpr([:and, self, other])
30
43
  end
31
44
 
@@ -64,6 +77,10 @@ class Predicate
64
77
  []
65
78
  end
66
79
 
80
+ def constants
81
+ {}
82
+ end
83
+
67
84
  def to_ruby_code(scope = 't')
68
85
  code = ToRubyCode.call(self, scope: scope)
69
86
  "->(t){ #{code} }"
@@ -6,5 +6,9 @@ class Predicate
6
6
  :>
7
7
  end
8
8
 
9
+ def evaluate(tuple)
10
+ left.evaluate(tuple) > right.evaluate(tuple)
11
+ end
12
+
9
13
  end
10
14
  end
@@ -6,5 +6,9 @@ class Predicate
6
6
  :>=
7
7
  end
8
8
 
9
+ def evaluate(tuple)
10
+ left.evaluate(tuple) >= right.evaluate(tuple)
11
+ end
12
+
9
13
  end
10
14
  end
@@ -14,5 +14,9 @@ class Predicate
14
14
  @free_variables ||= [ name ]
15
15
  end
16
16
 
17
+ def evaluate(tuple)
18
+ tuple[name]
19
+ end
20
+
17
21
  end
18
22
  end
@@ -14,6 +14,27 @@ class Predicate
14
14
  self[2]
15
15
  end
16
16
 
17
+ def &(other)
18
+ case other
19
+ when In
20
+ fv = free_variables
21
+ if fv.size == 1 && fv == other.free_variables
22
+ intersection = values & other.values
23
+ if intersection.empty?
24
+ Factory.contradiction
25
+ elsif intersection.size == 1
26
+ Factory.eq(fv.first, [:literal, intersection.first])
27
+ else
28
+ Factory.in(fv.first, intersection)
29
+ end
30
+ else
31
+ super
32
+ end
33
+ else
34
+ super
35
+ end
36
+ end
37
+
17
38
  def free_variables
18
39
  @free_variables ||= identifier.free_variables
19
40
  end
@@ -22,5 +43,17 @@ class Predicate
22
43
  values.size == 1 ? free_variables : []
23
44
  end
24
45
 
46
+ def constants
47
+ values.size == 1 ? { identifier.name => values.first } : {}
48
+ end
49
+
50
+ def dyadic_priority
51
+ 800
52
+ end
53
+
54
+ def evaluate(tuple)
55
+ values.include?(left.evaluate(tuple))
56
+ end
57
+
25
58
  end
26
59
  end
@@ -22,5 +22,10 @@ class Predicate
22
22
  values.size == 1 ? free_variables : []
23
23
  end
24
24
 
25
+ def evaluate(tuple)
26
+ t_x = left.evaluate(tuple)
27
+ t_x && !(tx & right.evaluate(tuple)).empty?
28
+ end
29
+
25
30
  end
26
31
  end
@@ -14,5 +14,9 @@ class Predicate
14
14
  last
15
15
  end
16
16
 
17
+ def evaluate(tuple)
18
+ value
19
+ end
20
+
17
21
  end
18
22
  end
@@ -6,5 +6,9 @@ class Predicate
6
6
  :<
7
7
  end
8
8
 
9
+ def evaluate(tuple)
10
+ left.evaluate(tuple) < right.evaluate(tuple)
11
+ end
12
+
9
13
  end
10
14
  end
@@ -6,5 +6,9 @@ class Predicate
6
6
  :<=
7
7
  end
8
8
 
9
+ def evaluate(tuple)
10
+ left.evaluate(tuple) <= right.evaluate(tuple)
11
+ end
12
+
9
13
  end
10
14
  end
@@ -36,6 +36,10 @@ class Predicate
36
36
  proc
37
37
  end
38
38
 
39
+ def evaluate(tuple)
40
+ proc.call(tuple)
41
+ end
42
+
39
43
  def free_variables
40
44
  raise NotSupportedError
41
45
  end
@@ -6,5 +6,9 @@ class Predicate
6
6
  :'!='
7
7
  end
8
8
 
9
+ def evaluate(tuple)
10
+ left.evaluate(tuple) != right.evaluate(tuple)
11
+ end
12
+
9
13
  end
10
14
  end
@@ -18,5 +18,9 @@ class Predicate
18
18
  @free_variables ||= last.free_variables
19
19
  end
20
20
 
21
+ def evaluate(tuple)
22
+ !last.evaluate(tuple)
23
+ end
24
+
21
25
  end
22
26
  end
@@ -6,5 +6,9 @@ class Predicate
6
6
  :'||'
7
7
  end
8
8
 
9
+ def evaluate(tuple)
10
+ sexpr_body.any?{|op| op.evaluate(tuple) }
11
+ end
12
+
9
13
  end
10
14
  end
@@ -18,5 +18,9 @@ class Predicate
18
18
  @free_variables ||= [ name ]
19
19
  end
20
20
 
21
+ def evaluate(tuple)
22
+ tuple[name]
23
+ end
24
+
21
25
  end
22
26
  end
@@ -18,6 +18,10 @@ class Predicate
18
18
  self
19
19
  end
20
20
 
21
+ def dyadic_priority
22
+ 1000
23
+ end
24
+
21
25
  def priority
22
26
  100
23
27
  end
@@ -30,5 +34,9 @@ class Predicate
30
34
  {}
31
35
  end
32
36
 
37
+ def evaluate(tuple)
38
+ true
39
+ end
40
+
33
41
  end
34
42
  end
@@ -50,7 +50,8 @@ class Predicate
50
50
  end
51
51
 
52
52
  def on_intersect(sexpr)
53
- "!(#{apply(sexpr.identifier)} & #{to_ruby_literal(sexpr.values)}).empty?"
53
+ t_x = apply(sexpr.identifier)
54
+ "!#{t_x}.nil? && !(#{t_x} & #{to_ruby_literal(sexpr.values)}).empty?"
54
55
  end
55
56
 
56
57
  def on_literal(sexpr)
@@ -1,7 +1,7 @@
1
1
  class Predicate
2
2
  module Version
3
3
  MAJOR = 1
4
- MINOR = 2
4
+ MINOR = 3
5
5
  TINY = 0
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
data/lib/predicate.rb CHANGED
@@ -60,6 +60,10 @@ class Predicate
60
60
  expr.constant_variables
61
61
  end
62
62
 
63
+ def constants
64
+ expr.constants
65
+ end
66
+
63
67
  def &(other)
64
68
  return self if other.tautology? or other==self
65
69
  return other if tautology?
@@ -85,7 +89,7 @@ class Predicate
85
89
  end
86
90
 
87
91
  def evaluate(tuple)
88
- to_proc.call(tuple)
92
+ expr.evaluate(tuple)
89
93
  end
90
94
 
91
95
  # Splits this predicate, say P, as too predicates P1 & P2
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ class Predicate
3
+ describe And, "&" do
4
+
5
+ let(:left){
6
+ Factory.eq(:x, 2) & Factory.eq(:y, 3)
7
+ }
8
+
9
+ subject{ left & right }
10
+
11
+ context 'with another predicate' do
12
+ let(:right) {
13
+ Factory.eq(:z, 4)
14
+ }
15
+
16
+ it 'collects it' do
17
+ expect(subject).to be_a(And)
18
+ expect(subject.size).to eql(4)
19
+ end
20
+
21
+ it 'is as expected' do
22
+ expect(subject.to_ruby_code).to eql("->(t){ (t[:x] == 2) && (t[:y] == 3) && (t[:z] == 4) }")
23
+ end
24
+ end
25
+
26
+ context 'with another and' do
27
+ let(:right) {
28
+ Factory.eq(:w, 5) & Factory.eq(:z, 4)
29
+ }
30
+
31
+ it 'collects it' do
32
+ expect(subject).to be_a(And)
33
+ expect(subject.size).to eql(5)
34
+ end
35
+
36
+ it 'is as expected' do
37
+ expect(subject.to_ruby_code).to eql("->(t){ (t[:x] == 2) && (t[:y] == 3) && (t[:w] == 5) && (t[:z] == 4) }")
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+ class Predicate
3
+ describe Eq, "&" do
4
+
5
+ let(:left){
6
+ Factory.eq(:x, 2)
7
+ }
8
+
9
+ subject{ left & right }
10
+
11
+ context 'with an eq leading to a contradiction' do
12
+ let(:right){ Factory.eq(:x, 3) }
13
+
14
+ it{ should be_a(Contradiction) }
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ class Predicate
3
+ describe In, "&" do
4
+
5
+ let(:left){
6
+ Factory.in(:x, [2, 4, 8])
7
+ }
8
+
9
+ subject{ left & right }
10
+
11
+ context 'with an eq on same variable' do
12
+ let(:right){ Factory.eq(:x, 3) }
13
+
14
+ it{ should be(right) }
15
+ end
16
+
17
+ context 'with an in on same variable' do
18
+ let(:right){ Factory.in(:x, [2, 4, 5]) }
19
+
20
+ it{ should eql(Factory.in(:x, [2, 4])) }
21
+ end
22
+
23
+ context 'with an in on same variable, leading to a singleton' do
24
+ let(:right){ Factory.in(:x, [2, 5]) }
25
+
26
+ it{ should eql(Factory.eq(:x, 2)) }
27
+ end
28
+
29
+ context 'with an in on same variable, leading to a empty set' do
30
+ let(:right){ Factory.in(:x, [5]) }
31
+
32
+ it{ should eql(Factory.contradiction) }
33
+ end
34
+
35
+ end
36
+ end
@@ -30,5 +30,21 @@ class Predicate
30
30
  end
31
31
  end
32
32
 
33
+ context 'with tautology' do
34
+ let(:right){ Predicate.tautology }
35
+
36
+ it 'returns self' do
37
+ expect(subject).to eql(left)
38
+ end
39
+ end
40
+
41
+ context 'with contradiction' do
42
+ let(:right){ Predicate.contradiction }
43
+
44
+ it 'returns contradiction' do
45
+ expect(subject).to eql(right)
46
+ end
47
+ end
48
+
33
49
  end
34
50
  end
@@ -0,0 +1,111 @@
1
+ require 'spec_helper'
2
+ class Predicate
3
+ describe Predicate, "constants" do
4
+
5
+ let(:p){ Predicate }
6
+ subject{ pred.constants }
7
+
8
+ context "on tautology" do
9
+ let(:pred){ p.tautology }
10
+
11
+ it{ should eq({}) }
12
+ end
13
+
14
+ context "on contradiction" do
15
+ let(:pred){ p.contradiction }
16
+
17
+ it{ should eq({}) }
18
+ end
19
+
20
+ context "on eq(identifier,value)" do
21
+ let(:pred){ p.eq(:x, 2) }
22
+
23
+ it{ should eq({x: 2}) }
24
+ end
25
+
26
+ context "on eq(value,identifier)" do
27
+ let(:pred){ p.eq(2, :x) }
28
+
29
+ it{ should eq({x: 2}) }
30
+ end
31
+
32
+ context "on eq(identifier,identifier)" do
33
+ let(:pred){ p.eq(:x, :y) }
34
+
35
+ it{ should eq({}) }
36
+ end
37
+
38
+ context "on not" do
39
+ let(:pred){ !p.eq(:x, 2) }
40
+
41
+ it{ should eq({}) }
42
+ end
43
+
44
+ context "on neq" do
45
+ let(:pred){ p.neq(:x, 2) }
46
+
47
+ it{ should eq({}) }
48
+ end
49
+
50
+ context "on gt" do
51
+ let(:pred){ p.gt(:x, 2) }
52
+
53
+ it{ should eq({}) }
54
+ end
55
+
56
+ context "on in (singleton)" do
57
+ let(:pred){ p.in(:x, [2]) }
58
+
59
+ it{ should eq({x: 2}) }
60
+ end
61
+
62
+ context "on in (multiples)" do
63
+ let(:pred){ p.in(:x, [2, 3]) }
64
+
65
+ it{ should eq({}) }
66
+ end
67
+
68
+ context "on and (two eqs)" do
69
+ let(:pred){ p.eq(:x, 2) & p.eq(:y, 4) }
70
+
71
+ it{ should eq({x: 2, y: 4}) }
72
+ end
73
+
74
+ context "on and (one eq)" do
75
+ let(:pred){ p.eq(:x, 2) & p.in(:y, [4,8]) }
76
+
77
+ it{ should eq({x: 2}) }
78
+ end
79
+
80
+ context "on and (one eq, one in, same variable)" do
81
+ let(:pred){ p.in(:x, [4,8]) & p.eq(:x, 2) }
82
+
83
+ it{ should eq({x: 2}) }
84
+ end
85
+
86
+ context "on and (contradiction)" do
87
+ let(:pred){ p.eq(:x, 2) & p.eq(:x, 4) }
88
+
89
+ it{ should eq({}) }
90
+ end
91
+
92
+ context "on intersect" do
93
+ let(:pred){ p.intersect(:x, [4,8]) }
94
+
95
+ it{ should eq({}) }
96
+ end
97
+
98
+ context "on or (two eqs)" do
99
+ let(:pred){ p.eq(:x, 2) | p.eq(:y, 4) }
100
+
101
+ it{ should eq({}) }
102
+ end
103
+
104
+ context "on native" do
105
+ let(:pred){ p.native(->(t){}) }
106
+
107
+ it{ should eq({}) }
108
+ end
109
+
110
+ end
111
+ end
@@ -76,7 +76,7 @@ class Predicate
76
76
  context 'intersect' do
77
77
  subject{ Predicate.intersect(:x, [7,8]) }
78
78
 
79
- specify{ subject.to_ruby_code.should eq("->(t){ !(t[:x] & [7, 8]).empty? }") }
79
+ specify{ subject.to_ruby_code.should eq("->(t){ !t[:x].nil? && !(t[:x] & [7, 8]).empty? }") }
80
80
  end
81
81
 
82
82
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: predicate
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
@@ -148,12 +148,15 @@ files:
148
148
  - spec/factory/test_tautology.rb
149
149
  - spec/grammar/test_match.rb
150
150
  - spec/grammar/test_sexpr.rb
151
+ - spec/nodes/and/test_and.rb
151
152
  - spec/nodes/and/test_and_split.rb
152
153
  - spec/nodes/and/test_attr_split.rb
153
154
  - spec/nodes/dyadic_comp/test_and_split.rb
155
+ - spec/nodes/eq/test_and.rb
154
156
  - spec/nodes/identifier/test_and_split.rb
155
157
  - spec/nodes/identifier/test_free_variables.rb
156
158
  - spec/nodes/identifier/test_name.rb
159
+ - spec/nodes/in/test_and.rb
157
160
  - spec/nodes/nadic_bool/test_free_variables.rb
158
161
  - spec/nodes/or/test_and_split.rb
159
162
  - spec/nodes/qualified_identifier/test_and_split.rb
@@ -167,6 +170,7 @@ files:
167
170
  - spec/predicate/test_bool_or.rb
168
171
  - spec/predicate/test_coerce.rb
169
172
  - spec/predicate/test_constant_variables.rb
173
+ - spec/predicate/test_constants.rb
170
174
  - spec/predicate/test_contradiction.rb
171
175
  - spec/predicate/test_evaluate.rb
172
176
  - spec/predicate/test_factory_methods.rb