porolog 0.0.8 → 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.
- checksums.yaml +4 -4
- data/README.md +11 -1
- data/Rakefile +2 -2
- data/bin/porolog +34 -13
- data/coverage/badge.svg +1 -1
- data/coverage/index.html +43822 -25140
- data/doc/Array.html +158 -51
- data/doc/Object.html +2 -2
- data/doc/Porolog.html +1584 -1113
- data/doc/Symbol.html +2 -2
- data/doc/_index.html +40 -56
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +8 -4
- data/doc/index.html +8 -4
- data/doc/method_list.html +424 -248
- data/doc/top-level-namespace.html +1 -1
- data/lib/porolog.rb +184 -61
- data/lib/porolog/arguments.rb +12 -11
- data/lib/porolog/core_ext.rb +27 -9
- data/lib/porolog/error.rb +3 -0
- data/lib/porolog/goal.rb +57 -15
- data/lib/porolog/instantiation.rb +55 -9
- data/lib/porolog/predicate.rb +52 -26
- data/lib/porolog/predicate/builtin.rb +825 -0
- data/lib/porolog/rule.rb +8 -24
- data/lib/porolog/scope.rb +1 -1
- data/lib/porolog/tail.rb +5 -0
- data/lib/porolog/value.rb +3 -3
- data/lib/porolog/variable.rb +29 -11
- data/test/porolog/arguments_test.rb +45 -66
- data/test/porolog/core_ext_test.rb +25 -0
- data/test/porolog/goal_test.rb +86 -9
- data/test/porolog/instantiation_test.rb +36 -0
- data/test/porolog/porolog_test.rb +285 -30
- data/test/porolog/predicate/builtin_test.rb +1340 -0
- data/test/porolog/predicate_test.rb +78 -16
- data/test/porolog/rule_test.rb +19 -0
- data/test/porolog/variable_test.rb +44 -55
- data/test/samples_test.rb +277 -0
- data/test/test_helper.rb +9 -0
- metadata +9 -5
data/lib/porolog/rule.rb
CHANGED
@@ -122,39 +122,23 @@ module Porolog
|
|
122
122
|
end
|
123
123
|
|
124
124
|
if arguments == :CUT
|
125
|
-
|
126
|
-
|
125
|
+
goal.terminate!
|
126
|
+
goal.log << "TERMINATED after #{subgoal.inspect}"
|
127
127
|
end
|
128
128
|
|
129
129
|
return result
|
130
130
|
|
131
131
|
when false
|
132
132
|
return false
|
133
|
-
end
|
134
|
-
|
135
|
-
# -- Unify Subgoal --
|
136
|
-
subsubgoal = arguments.goal(subgoal)
|
137
|
-
variables = (subgoal.arguments.variables + subsubgoal.arguments.variables).map(&:to_sym).uniq
|
138
|
-
unified = true
|
139
|
-
unifications = []
|
140
|
-
|
141
|
-
variables.each do |variable|
|
142
|
-
name = variable
|
143
133
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
unifications += unification
|
148
|
-
else
|
149
|
-
#:nocov:
|
150
|
-
subsubgoal.log << "Couldn't unify: #{name.inspect} WITH #{subgoal.myid} AND #{subsubgoal.myid}"
|
151
|
-
break
|
152
|
-
#:nocov:
|
153
|
-
end
|
134
|
+
when nil
|
135
|
+
block.call(subgoal)
|
136
|
+
return true
|
154
137
|
end
|
155
138
|
|
156
|
-
# --
|
157
|
-
|
139
|
+
# -- Unify Subsubgoal --
|
140
|
+
subsubgoal = arguments.goal(subgoal)
|
141
|
+
unified = subsubgoal.inherit_variables(subgoal)
|
158
142
|
|
159
143
|
# -- Satisfy Subgoal --
|
160
144
|
result = false
|
data/lib/porolog/scope.rb
CHANGED
@@ -73,7 +73,7 @@ module Porolog
|
|
73
73
|
# @param predicate [Porolog::Predicate] a Predicate to be assigned to the Scope.
|
74
74
|
# @return [Porolog::Predicate] the Predicate assigned to the Scope.
|
75
75
|
# @raise [NotPredicateError] when provided predicate is not actually a Predicate.
|
76
|
-
def []=(name,predicate)
|
76
|
+
def []=(name, predicate)
|
77
77
|
raise NotPredicateError, "#{predicate.inspect} is not a Predicate" unless predicate.is_a?(Predicate)
|
78
78
|
@predicates[name.to_sym] = predicate
|
79
79
|
end
|
data/lib/porolog/tail.rb
CHANGED
@@ -23,6 +23,11 @@ module Porolog
|
|
23
23
|
@value = value
|
24
24
|
end
|
25
25
|
|
26
|
+
# @return [Symbol] the type of the Tail, which should be :tail.
|
27
|
+
def type
|
28
|
+
:tail
|
29
|
+
end
|
30
|
+
|
26
31
|
# Returns the value of the Tail.
|
27
32
|
# The optional arguments are ignored; this is for polymorphic compatibility with Porolog::Value and Porolog::Variable,
|
28
33
|
# which are used to prevent inifinite recursion.
|
data/lib/porolog/value.rb
CHANGED
@@ -54,8 +54,8 @@ module Porolog
|
|
54
54
|
# @param self_index [Integer,Symbol,Array] the index of which this value belongs.
|
55
55
|
# @return [String] the inspect of the value in the context of the variables of a goal.
|
56
56
|
def inspect_with_instantiations(visited = [], depth = 0, index = nil, self_index = nil)
|
57
|
-
index_str = index
|
58
|
-
prefix = self_index
|
57
|
+
index_str = index && "[#{index.inspect}]" || ''
|
58
|
+
prefix = self_index&.inspect || ''
|
59
59
|
|
60
60
|
"#{' ' * depth}#{prefix}#{inspect}#{index_str}"
|
61
61
|
end
|
@@ -75,7 +75,7 @@ module Porolog
|
|
75
75
|
|
76
76
|
# Responds to all the Value's value methods as well as its own.
|
77
77
|
# @return [Boolean] whether the value responds to the method.
|
78
|
-
def respond_to?(method, include_all=false)
|
78
|
+
def respond_to?(method, include_all = false)
|
79
79
|
@value.respond_to?(method, include_all) || super
|
80
80
|
end
|
81
81
|
|
data/lib/porolog/variable.rb
CHANGED
@@ -5,7 +5,6 @@
|
|
5
5
|
# created
|
6
6
|
#
|
7
7
|
|
8
|
-
|
9
8
|
module Porolog
|
10
9
|
|
11
10
|
# A Porolog::Variable is used to hold instantiations during the process of satisfying a goal.
|
@@ -69,7 +68,7 @@ module Porolog
|
|
69
68
|
# Converts a Variable back to a Symbol.
|
70
69
|
# @return [Symbol, nil] the name of the Variable.
|
71
70
|
def to_sym
|
72
|
-
@name
|
71
|
+
@name&.to_sym
|
73
72
|
end
|
74
73
|
|
75
74
|
# @return [Symbol] the type of the Variable, which should be :variable.
|
@@ -135,20 +134,39 @@ module Porolog
|
|
135
134
|
# -- Condense Values --
|
136
135
|
result = if values_values.size > 1
|
137
136
|
# -- Potentially Multiple Values Found --
|
137
|
+
unifications = []
|
138
138
|
if values_values.all?{|value| value.is_a?(Array) }
|
139
139
|
# -- All Values Are Arrays --
|
140
|
-
|
141
|
-
|
140
|
+
values = values.reject{|value| value == UNKNOWN_ARRAY } if values.size > 2 && values.include?(UNKNOWN_ARRAY)
|
142
141
|
values_goals = values.map{|value|
|
143
|
-
value.respond_to?(:goal) && value.goal || value.variables.map(&:goal).first
|
142
|
+
value.respond_to?(:goal) && value.goal || value.variables.map(&:goal).first || values.variables.map(&:goal).first
|
144
143
|
}
|
145
144
|
|
146
|
-
|
145
|
+
if values.size > 2
|
146
|
+
merged, unifications = unify_many_arrays(values, values_goals, visited)
|
147
|
+
elsif values.size == 2
|
148
|
+
no_variables = values.map(&:variables).flatten.empty?
|
149
|
+
if no_variables
|
150
|
+
left_value = values[0].value.value
|
151
|
+
right_value = values[1].value.value
|
152
|
+
if left_value.last == UNKNOWN_TAIL && right_value.first == UNKNOWN_TAIL
|
153
|
+
return [*left_value[0...-1], *right_value[1..-1]]
|
154
|
+
elsif right_value.last == UNKNOWN_TAIL && left_value.first == UNKNOWN_TAIL
|
155
|
+
return [*right_value[0...-1], *left_value[1..-1]]
|
156
|
+
elsif left_value != right_value
|
157
|
+
return nil
|
158
|
+
end
|
159
|
+
end
|
160
|
+
merged, unifications = unify_arrays(*values, *values_goals, visited)
|
161
|
+
else
|
162
|
+
# :nocov: NOT REACHED
|
163
|
+
merged, unifications = values.first, []
|
164
|
+
# :nocov:
|
165
|
+
end
|
147
166
|
|
148
167
|
merged.value(visited).to_a
|
149
168
|
else
|
150
169
|
# -- Not All Values Are Arrays --
|
151
|
-
unifications = []
|
152
170
|
values.each_cons(2){|left,right|
|
153
171
|
unification = unify(left, right, @goal, @goal, visited)
|
154
172
|
if unification && unifications
|
@@ -158,26 +176,26 @@ module Porolog
|
|
158
176
|
end
|
159
177
|
}
|
160
178
|
if unifications
|
161
|
-
values.
|
179
|
+
values.min_by{|value|
|
162
180
|
case value
|
163
181
|
when Variable, Symbol then 2
|
164
182
|
when UNKNOWN_TAIL, UNKNOWN_ARRAY then 9
|
165
183
|
else 0
|
166
184
|
end
|
167
|
-
}
|
185
|
+
} || self
|
168
186
|
else
|
169
187
|
raise MultipleValuesError, "Multiple values detected for #{inspect}: #{values.inspect}"
|
170
188
|
end
|
171
189
|
end
|
172
190
|
else
|
173
191
|
# -- One (or None) Value Found --
|
174
|
-
values.
|
192
|
+
values.min_by{|value|
|
175
193
|
case value
|
176
194
|
when Variable, Symbol then 2
|
177
195
|
when UNKNOWN_TAIL, UNKNOWN_ARRAY then 9
|
178
196
|
else 0
|
179
197
|
end
|
180
|
-
}
|
198
|
+
} || self
|
181
199
|
end
|
182
200
|
|
183
201
|
# -- Splat Tail --
|
@@ -504,8 +504,7 @@ describe 'Porolog' do
|
|
504
504
|
end
|
505
505
|
|
506
506
|
it 'should call a builtin predicate' do
|
507
|
-
|
508
|
-
|
507
|
+
builtin :write
|
509
508
|
predicate :callwrite
|
510
509
|
|
511
510
|
callwrite(:MESSAGE) << [
|
@@ -522,8 +521,7 @@ describe 'Porolog' do
|
|
522
521
|
end
|
523
522
|
|
524
523
|
it 'should pass on instantiations between goals' do
|
525
|
-
|
526
|
-
|
524
|
+
builtin :write
|
527
525
|
predicate :passon, :copy
|
528
526
|
|
529
527
|
copy(:A,:A).fact!
|
@@ -548,8 +546,7 @@ describe 'Porolog' do
|
|
548
546
|
end
|
549
547
|
|
550
548
|
it 'should implement simple recursion' do
|
551
|
-
|
552
|
-
|
549
|
+
builtin :write, :is, :gtr
|
553
550
|
predicate :count
|
554
551
|
|
555
552
|
count(1) << [
|
@@ -557,10 +554,12 @@ describe 'Porolog' do
|
|
557
554
|
:CUT
|
558
555
|
]
|
559
556
|
count(:N) << [
|
557
|
+
gtr(:N,1),
|
560
558
|
write("N = ",:N),
|
561
559
|
is(:M,:N){|n| n - 1 },
|
562
560
|
write(" M = ",:M,"\n"),
|
563
561
|
count(:M),
|
562
|
+
:CUT
|
564
563
|
]
|
565
564
|
|
566
565
|
expected_output = [
|
@@ -586,8 +585,7 @@ describe 'Porolog' do
|
|
586
585
|
end
|
587
586
|
|
588
587
|
it 'should solve tower of Hanoi' do
|
589
|
-
|
590
|
-
|
588
|
+
builtin :gtr, :is, :write
|
591
589
|
predicate :move
|
592
590
|
|
593
591
|
move(1,:X,:Y,:Z) << [
|
@@ -629,23 +627,22 @@ describe 'Porolog' do
|
|
629
627
|
end
|
630
628
|
|
631
629
|
it 'should solve a peeling off predicate' do
|
632
|
-
|
633
|
-
|
634
|
-
predicate :size
|
630
|
+
builtin :is
|
631
|
+
predicate :peel
|
635
632
|
|
636
|
-
|
637
|
-
|
638
|
-
|
633
|
+
peel([],0).cut_fact!
|
634
|
+
peel(:H/:T,:N) << [
|
635
|
+
peel(:T,:NT),
|
639
636
|
is(:N,:NT){|nt| nt + 1 },
|
640
637
|
]
|
641
638
|
|
642
|
-
solutions =
|
639
|
+
solutions = peel([],:N).solve
|
643
640
|
|
644
641
|
assert_equal [
|
645
642
|
{ N: 0 }
|
646
643
|
],solutions
|
647
644
|
|
648
|
-
solutions =
|
645
|
+
solutions = peel([13,17,19,23],:N).solve
|
649
646
|
|
650
647
|
assert_equal [
|
651
648
|
{ N: 4 },
|
@@ -653,10 +650,10 @@ describe 'Porolog' do
|
|
653
650
|
end
|
654
651
|
|
655
652
|
it 'should solve tower of Hanoi with list representation' do
|
656
|
-
skip 'until StandardPredicates added and converted to list representation'
|
657
653
|
# TODO: convert to list representation
|
658
654
|
|
659
|
-
|
655
|
+
builtin :gtr, :is, :append, :write
|
656
|
+
predicate :tower, :move
|
660
657
|
|
661
658
|
tower(1, :X, :Y, :Z, [[:X,:Z]]).fact!
|
662
659
|
tower(:N, :X, :Y, :Z, :S) << [
|
@@ -668,68 +665,50 @@ describe 'Porolog' do
|
|
668
665
|
append(:S1, :S2, :S12),
|
669
666
|
append(:S12, :S3, :S),
|
670
667
|
]
|
671
|
-
predicate :move
|
672
|
-
|
673
|
-
move(1,:X,:Y,:Z) << [
|
674
|
-
write('Move top disk from ', :X, ' to ', :Y, "\n"),
|
675
|
-
]
|
676
|
-
move(:N,:X,:Y,:Z) << [
|
677
|
-
gtr(:N,1),
|
678
|
-
is(:M,:N){|n| n - 1 },
|
679
|
-
move(:M,:X,:Z,:Y),
|
680
|
-
move(1,:X,:Y,:Q),
|
681
|
-
move(:M,:Z,:Y,:X),
|
682
|
-
]
|
683
|
-
|
684
|
-
expected_output = [
|
685
|
-
'Move top disk from left to center',
|
686
|
-
'Move top disk from left to right',
|
687
|
-
'Move top disk from center to right',
|
688
|
-
'Move top disk from left to center',
|
689
|
-
'Move top disk from right to left',
|
690
|
-
'Move top disk from right to center',
|
691
|
-
'Move top disk from left to center',
|
692
|
-
'Move top disk from center to right',
|
693
|
-
'Move top disk from center to left',
|
694
|
-
'Move top disk from right to left',
|
695
|
-
'Move top disk from center to right',
|
696
|
-
'Move top disk from left to center',
|
697
|
-
'Move top disk from left to right',
|
698
|
-
'Move top disk from center to right',
|
699
|
-
].map{|s| "#{s}\n" }.join
|
700
668
|
|
701
669
|
solutions = tower(3, 'left', 'middle', 'right', :moves).solve
|
702
670
|
|
703
671
|
expected_solutions = [
|
704
672
|
{
|
705
673
|
moves: [
|
706
|
-
['left', 'center'],
|
707
674
|
['left', 'right'],
|
708
|
-
['
|
709
|
-
['
|
710
|
-
['right', 'left'],
|
711
|
-
['right', 'center'],
|
712
|
-
['left', 'center'],
|
713
|
-
['center', 'right'],
|
714
|
-
['center', 'left'],
|
715
|
-
['right', 'left'],
|
716
|
-
['center', 'right'],
|
717
|
-
['left', 'center'],
|
675
|
+
['left', 'middle'],
|
676
|
+
['right', 'middle'],
|
718
677
|
['left', 'right'],
|
719
|
-
['
|
678
|
+
['middle', 'left'],
|
679
|
+
['middle', 'right'],
|
680
|
+
['left', 'right']
|
720
681
|
]
|
721
682
|
}
|
722
683
|
]
|
723
684
|
|
724
685
|
assert_equal expected_solutions, solutions
|
725
686
|
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
687
|
+
solutions = tower(4, 'left', 'middle', 'right', :moves).solve
|
688
|
+
|
689
|
+
expected_solutions = [
|
690
|
+
{
|
691
|
+
moves: [
|
692
|
+
['left', 'middle'],
|
693
|
+
['left', 'right'],
|
694
|
+
['middle', 'right'],
|
695
|
+
['left', 'middle'],
|
696
|
+
['right', 'left'],
|
697
|
+
['right', 'middle'],
|
698
|
+
['left', 'middle'],
|
699
|
+
['left', 'right'],
|
700
|
+
['middle', 'right'],
|
701
|
+
['middle', 'left'],
|
702
|
+
['right', 'left'],
|
703
|
+
['middle', 'right'],
|
704
|
+
['left', 'middle'],
|
705
|
+
['left', 'right'],
|
706
|
+
['middle', 'right']
|
707
|
+
]
|
708
|
+
}
|
709
|
+
]
|
710
|
+
|
711
|
+
assert_equal expected_solutions, solutions
|
733
712
|
end
|
734
713
|
|
735
714
|
end
|
@@ -262,4 +262,29 @@ describe 'Array' do
|
|
262
262
|
|
263
263
|
end
|
264
264
|
|
265
|
+
describe '#clean' do
|
266
|
+
|
267
|
+
let(:predicate1) { Predicate.new :generic }
|
268
|
+
let(:arguments1) { predicate1.arguments(:m,:n) }
|
269
|
+
let(:goal1) { arguments1.goal }
|
270
|
+
|
271
|
+
let(:array5) { [1, 2, goal1[:A], 4, [goal1[:B], 6, 7, goal1[:C]], 9] }
|
272
|
+
let(:array6) { [1, goal1[:B], 3]/:T }
|
273
|
+
let(:array7) { [1, goal1[:B], 3]/goal1[:T] }
|
274
|
+
|
275
|
+
it 'should return simple Arrays as is' do
|
276
|
+
assert_equal [1, 2, :A, 4, [:B, 6, 7, :C], 9], array1.clean
|
277
|
+
assert_equal [], array2.clean
|
278
|
+
assert_equal [UNKNOWN_TAIL], array3.clean
|
279
|
+
assert_equal [1, :B, 3, UNKNOWN_TAIL], array4.clean
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'should return the values of its elements with variables replaced by nil and Tails replaced by UNKNOWN_TAIL' do
|
283
|
+
assert_equal [1, 2, nil, 4, [nil, 6, 7, nil], 9], array5.clean
|
284
|
+
assert_equal [1, nil, 3, UNKNOWN_TAIL], array6.clean
|
285
|
+
assert_equal [1, nil, 3, UNKNOWN_TAIL], array7.clean
|
286
|
+
end
|
287
|
+
|
288
|
+
end
|
289
|
+
|
265
290
|
end
|
data/test/porolog/goal_test.rb
CHANGED
@@ -669,23 +669,20 @@ describe 'Porolog' do
|
|
669
669
|
end
|
670
670
|
|
671
671
|
it 'should solve a goal recursively' do
|
672
|
-
|
673
|
-
skip 'until Standard Predicates added'
|
674
|
-
|
672
|
+
builtin :write
|
675
673
|
predicate :recursive
|
676
674
|
|
677
675
|
recursive([]) << [:CUT, true]
|
678
676
|
recursive(:head/:tail) << [
|
679
677
|
write('(',:head,')'),
|
680
|
-
|
678
|
+
recursive(:tail)
|
681
679
|
]
|
682
680
|
|
683
681
|
assert_output '(1)(2)(3)(four)(5)(6)(7)' do
|
684
|
-
solutions =
|
682
|
+
solutions = recursive([1,2,3,'four',5,6,7]).solve
|
685
683
|
|
686
684
|
assert_equal [{}], solutions
|
687
685
|
end
|
688
|
-
#:nocov:
|
689
686
|
end
|
690
687
|
|
691
688
|
end
|
@@ -706,14 +703,14 @@ describe 'Porolog' do
|
|
706
703
|
goal.arguments.expects(:predicate).with().returns(nil).times(1)
|
707
704
|
block.expects(:call).times(0)
|
708
705
|
|
709
|
-
|
706
|
+
refute goal.satisfy(&block), name
|
710
707
|
end
|
711
708
|
|
712
709
|
it 'should try to satisfy the predicate with itself' do
|
713
710
|
pred.expects(:satisfy).with(goal).returns(nil).times(1)
|
714
711
|
block.expects(:call).times(0)
|
715
712
|
|
716
|
-
|
713
|
+
refute goal.satisfy(&block), name
|
717
714
|
end
|
718
715
|
|
719
716
|
it 'should call the block when the predicate is satisfied' do
|
@@ -721,7 +718,7 @@ describe 'Porolog' do
|
|
721
718
|
pred.(3,4).fact!
|
722
719
|
pred.(5,6).fact!
|
723
720
|
|
724
|
-
block.expects(:call).times(3)
|
721
|
+
block.expects(:call).returns(true).times(3)
|
725
722
|
|
726
723
|
assert goal.satisfy(&block), name
|
727
724
|
end
|
@@ -809,6 +806,86 @@ describe 'Porolog' do
|
|
809
806
|
|
810
807
|
end
|
811
808
|
|
809
|
+
describe '#inherit_variables' do
|
810
|
+
|
811
|
+
it 'should return true for an initial goal' do
|
812
|
+
goal = new_goal :goal, :x, :y, :z
|
813
|
+
|
814
|
+
assert goal.inherit_variables
|
815
|
+
assert_Goal_variables goal, { x: nil, y: nil, z: nil }, [
|
816
|
+
'Goal1.:x',
|
817
|
+
'Goal1.:y',
|
818
|
+
'Goal1.:z',
|
819
|
+
].join("\n")
|
820
|
+
end
|
821
|
+
|
822
|
+
it 'should instantiate combined variables of both goals' do
|
823
|
+
goal = new_goal :goal, :x, :y, :z
|
824
|
+
subgoal = new_goal :subgoal, :a, :b, :c
|
825
|
+
|
826
|
+
assert subgoal.inherit_variables(goal)
|
827
|
+
assert_Goal_variables goal, { x: nil, y: nil, z: nil, a: nil, b: nil, c: nil }, [
|
828
|
+
'Goal1.:x',
|
829
|
+
' Goal2.:x',
|
830
|
+
'Goal1.:y',
|
831
|
+
' Goal2.:y',
|
832
|
+
'Goal1.:z',
|
833
|
+
' Goal2.:z',
|
834
|
+
'Goal1.:a',
|
835
|
+
' Goal2.:a',
|
836
|
+
'Goal1.:b',
|
837
|
+
' Goal2.:b',
|
838
|
+
'Goal1.:c',
|
839
|
+
' Goal2.:c',
|
840
|
+
].join("\n")
|
841
|
+
assert_Goal_variables subgoal, { a: nil, b: nil, c: nil, x: nil, y: nil, z: nil }, [
|
842
|
+
'Goal2.:a',
|
843
|
+
' Goal1.:a',
|
844
|
+
'Goal2.:b',
|
845
|
+
' Goal1.:b',
|
846
|
+
'Goal2.:c',
|
847
|
+
' Goal1.:c',
|
848
|
+
'Goal2.:x',
|
849
|
+
' Goal1.:x',
|
850
|
+
'Goal2.:y',
|
851
|
+
' Goal1.:y',
|
852
|
+
'Goal2.:z',
|
853
|
+
' Goal1.:z',
|
854
|
+
].join("\n")
|
855
|
+
end
|
856
|
+
|
857
|
+
it 'should not make any instantiations when variables cannot be unified' do
|
858
|
+
goal = new_goal :goal, :x, :y, :z
|
859
|
+
subgoal = new_goal :subgoal, :a, :b, :c
|
860
|
+
|
861
|
+
goal[:x].instantiate 1
|
862
|
+
subgoal[:x].instantiate 2
|
863
|
+
|
864
|
+
refute subgoal.inherit_variables(goal)
|
865
|
+
assert_equal [
|
866
|
+
'Cannot unify because 1 != 2 (variable != variable)',
|
867
|
+
], goal.log
|
868
|
+
assert_equal [
|
869
|
+
'Cannot unify because 1 != 2 (variable != variable)',
|
870
|
+
"Couldn't unify: :x WITH Goal1 AND Goal2"
|
871
|
+
], subgoal.log
|
872
|
+
assert_Goal_variables goal, { x: 1, y: nil, z: nil }, [
|
873
|
+
'Goal1.:x',
|
874
|
+
' Goal1.1',
|
875
|
+
'Goal1.:y',
|
876
|
+
'Goal1.:z',
|
877
|
+
].join("\n")
|
878
|
+
assert_Goal_variables subgoal, { a: nil, b: nil, c: nil, x: 2 }, [
|
879
|
+
'Goal2.:a',
|
880
|
+
'Goal2.:b',
|
881
|
+
'Goal2.:c',
|
882
|
+
'Goal2.:x',
|
883
|
+
' Goal2.2',
|
884
|
+
].join("\n")
|
885
|
+
end
|
886
|
+
|
887
|
+
end
|
888
|
+
|
812
889
|
end
|
813
890
|
|
814
891
|
end
|