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 +4 -4
- data/lib/predicate/nodes/and.rb +19 -0
- data/lib/predicate/nodes/contradiction.rb +8 -0
- data/lib/predicate/nodes/eq.rb +36 -0
- data/lib/predicate/nodes/expr.rb +17 -0
- data/lib/predicate/nodes/gt.rb +4 -0
- data/lib/predicate/nodes/gte.rb +4 -0
- data/lib/predicate/nodes/identifier.rb +4 -0
- data/lib/predicate/nodes/in.rb +33 -0
- data/lib/predicate/nodes/intersect.rb +5 -0
- data/lib/predicate/nodes/literal.rb +4 -0
- data/lib/predicate/nodes/lt.rb +4 -0
- data/lib/predicate/nodes/lte.rb +4 -0
- data/lib/predicate/nodes/native.rb +4 -0
- data/lib/predicate/nodes/neq.rb +4 -0
- data/lib/predicate/nodes/not.rb +4 -0
- data/lib/predicate/nodes/or.rb +4 -0
- data/lib/predicate/nodes/qualified_identifier.rb +4 -0
- data/lib/predicate/nodes/tautology.rb +8 -0
- data/lib/predicate/processors/to_ruby_code.rb +2 -1
- data/lib/predicate/version.rb +1 -1
- data/lib/predicate.rb +5 -1
- data/spec/nodes/and/test_and.rb +42 -0
- data/spec/nodes/eq/test_and.rb +18 -0
- data/spec/nodes/in/test_and.rb +36 -0
- data/spec/predicate/test_bool_and.rb +16 -0
- data/spec/predicate/test_constants.rb +111 -0
- data/spec/predicate/test_factory_methods.rb +1 -1
- metadata +5 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61fec1238a5307709753d2214ed0bf4b07af3790
|
4
|
+
data.tar.gz: 8ca0232c14c907971c4bc39b10ddbe3629f2f529
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a66b05a35406d025a78fa0bc44c1508c3c74906eff4ef2270b8fcc4177aeaf88b9f54ff11d259eaa17aa30bb8b728d00ca08a038efcb98b4e735fecde2ad844e
|
7
|
+
data.tar.gz: 88029e029b342093b92a7925ef0ca7edd618e440fc33d99eaf2f128b4cbf0e344639e62aa2768621507582e24f007faff03727bde874b6b0c729e0519d1638c8
|
data/lib/predicate/nodes/and.rb
CHANGED
@@ -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
|
data/lib/predicate/nodes/eq.rb
CHANGED
@@ -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
|
data/lib/predicate/nodes/expr.rb
CHANGED
@@ -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} }"
|
data/lib/predicate/nodes/gt.rb
CHANGED
data/lib/predicate/nodes/gte.rb
CHANGED
data/lib/predicate/nodes/in.rb
CHANGED
@@ -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
|
data/lib/predicate/nodes/lt.rb
CHANGED
data/lib/predicate/nodes/lte.rb
CHANGED
data/lib/predicate/nodes/neq.rb
CHANGED
data/lib/predicate/nodes/not.rb
CHANGED
data/lib/predicate/nodes/or.rb
CHANGED
@@ -50,7 +50,8 @@ class Predicate
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def on_intersect(sexpr)
|
53
|
-
|
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)
|
data/lib/predicate/version.rb
CHANGED
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
|
-
|
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.
|
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
|