porolog 0.0.7 → 0.0.8
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 +18 -4
- data/bin/porolog +38 -2
- data/coverage/badge.svg +1 -1
- data/coverage/index.html +52327 -6692
- data/doc/Array.html +113 -33
- data/doc/Object.html +11 -17
- data/doc/Porolog.html +3681 -73
- data/doc/Symbol.html +17 -20
- data/doc/_index.html +181 -13
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +28 -38
- data/doc/index.html +28 -38
- data/doc/method_list.html +871 -167
- data/doc/top-level-namespace.html +2 -2
- data/lib/porolog.rb +1015 -2
- data/lib/porolog/arguments.rb +16 -14
- data/lib/porolog/core_ext.rb +6 -0
- data/lib/porolog/error.rb +6 -0
- data/lib/porolog/goal.rb +205 -68
- data/lib/porolog/instantiation.rb +300 -0
- data/lib/porolog/predicate.rb +33 -16
- data/lib/porolog/rule.rb +129 -2
- data/lib/porolog/scope.rb +3 -3
- data/lib/porolog/tail.rb +52 -0
- data/lib/porolog/value.rb +9 -12
- data/lib/porolog/variable.rb +307 -0
- data/test/porolog/arguments_test.rb +217 -135
- data/test/porolog/core_ext_test.rb +24 -17
- data/test/porolog/goal_test.rb +481 -74
- data/test/porolog/instantiation_test.rb +874 -0
- data/test/porolog/porolog_test.rb +2121 -13
- data/test/porolog/predicate_test.rb +1 -1
- data/test/porolog/rule_test.rb +395 -0
- data/test/porolog/scope_test.rb +0 -2
- data/test/porolog/tail_test.rb +127 -0
- data/test/porolog/value_test.rb +1 -1
- data/test/porolog/variable_test.rb +1625 -0
- data/test/test_helper.rb +78 -5
- metadata +12 -4
@@ -13,13 +13,24 @@ describe 'Porolog' do
|
|
13
13
|
reset
|
14
14
|
end
|
15
15
|
|
16
|
+
describe 'UNKNOWN_TAIL#inspect' do
|
17
|
+
|
18
|
+
it 'should return distinctive notation' do
|
19
|
+
assert_equal '...', UNKNOWN_TAIL.inspect
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
16
24
|
describe '#predicate' do
|
17
25
|
|
18
26
|
it 'should create a Predicate' do
|
19
|
-
|
27
|
+
# -- Precondition Baseline --
|
28
|
+
assert_equal 0, Scope[:default].predicates.size
|
20
29
|
|
30
|
+
# -- Test --
|
21
31
|
single_predicate = predicate :single
|
22
32
|
|
33
|
+
# -- Compare Result Against Baseline --
|
23
34
|
assert_equal 1, Scope[:default].predicates.size
|
24
35
|
assert_equal :single, Scope[:default].predicates.first.name
|
25
36
|
assert_Predicate single_predicate, :single, []
|
@@ -31,23 +42,23 @@ describe 'Porolog' do
|
|
31
42
|
predicate :delta
|
32
43
|
|
33
44
|
assert respond_to?(:delta)
|
34
|
-
assert_Arguments delta(1, :X, ['left','right']),
|
45
|
+
assert_Arguments delta(1, :X, ['left','right']), :delta, [1, :X, ['left','right']]
|
35
46
|
end
|
36
47
|
|
37
48
|
it 'should create multiple Predicates' do
|
38
|
-
assert_equal
|
49
|
+
assert_equal 0, Scope[:default].predicates.size
|
39
50
|
|
40
51
|
multiple_predicates = predicate :alpha, :beta, :gamma
|
41
52
|
|
42
|
-
assert_equal
|
43
|
-
assert_equal
|
44
|
-
assert_equal
|
45
|
-
assert_equal
|
46
|
-
assert_instance_of
|
47
|
-
assert_equal
|
48
|
-
assert_Predicate
|
49
|
-
assert_Predicate
|
50
|
-
assert_Predicate
|
53
|
+
assert_equal 3, Scope[:default].predicates.size
|
54
|
+
assert_equal :alpha, Scope[:default].predicates[0].name
|
55
|
+
assert_equal :beta, Scope[:default].predicates[1].name
|
56
|
+
assert_equal :gamma, Scope[:default].predicates[2].name
|
57
|
+
assert_instance_of Array, multiple_predicates
|
58
|
+
assert_equal 3, multiple_predicates.size
|
59
|
+
assert_Predicate multiple_predicates[0], :alpha, []
|
60
|
+
assert_Predicate multiple_predicates[1], :beta, []
|
61
|
+
assert_Predicate multiple_predicates[2], :gamma, []
|
51
62
|
end
|
52
63
|
|
53
64
|
it 'should define multiple methods to create Arguments for solving' do
|
@@ -57,11 +68,2108 @@ describe 'Porolog' do
|
|
57
68
|
predicate :epsilon, :upsilon
|
58
69
|
|
59
70
|
assert respond_to?(:epsilon)
|
60
|
-
assert_Arguments epsilon(), :epsilon, []
|
61
71
|
assert respond_to?(:upsilon)
|
72
|
+
assert_Arguments epsilon(), :epsilon, []
|
62
73
|
assert_Arguments upsilon([]), :upsilon, [[]]
|
63
74
|
end
|
64
75
|
|
65
76
|
end
|
66
77
|
|
78
|
+
describe '#unify_goals' do
|
79
|
+
|
80
|
+
it 'should unify goals for the same predicate' do
|
81
|
+
# -- Setup --
|
82
|
+
goal1 = new_goal :p, :m, :n
|
83
|
+
goal2 = new_goal :p, :s, :t
|
84
|
+
|
85
|
+
# -- Precondition Baseline --
|
86
|
+
assert_Goal_variables goal1, { m: nil, n: nil }, [
|
87
|
+
'Goal1.:m',
|
88
|
+
'Goal1.:n',
|
89
|
+
].join("\n")
|
90
|
+
|
91
|
+
assert_Goal_variables goal2, { s: nil, t: nil }, [
|
92
|
+
'Goal2.:s',
|
93
|
+
'Goal2.:t',
|
94
|
+
].join("\n")
|
95
|
+
|
96
|
+
# -- Test --
|
97
|
+
assert unify_goals(goal1, goal2), name
|
98
|
+
|
99
|
+
# -- Compare Result Against Baseline --
|
100
|
+
assert_Goal_variables goal1, { m: nil, n: nil }, [
|
101
|
+
'Goal1.:m',
|
102
|
+
' Goal2.:s',
|
103
|
+
'Goal1.:n',
|
104
|
+
' Goal2.:t',
|
105
|
+
].join("\n")
|
106
|
+
|
107
|
+
assert_Goal_variables goal2, { s: nil, t: nil }, [
|
108
|
+
'Goal2.:s',
|
109
|
+
' Goal1.:m',
|
110
|
+
'Goal2.:t',
|
111
|
+
' Goal1.:n',
|
112
|
+
].join("\n")
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should not unify goals for different predicates' do
|
116
|
+
goal1 = new_goal :p, :x, :y
|
117
|
+
goal2 = new_goal :q, :x, :y
|
118
|
+
|
119
|
+
refute unify_goals(goal1, goal2), name
|
120
|
+
|
121
|
+
assert_equal ['Cannot unify goals because they are for different predicates: :p and :q'], goal1.log
|
122
|
+
assert_equal ['Cannot unify goals because they are for different predicates: :p and :q'], goal2.log
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
describe '#instantiate_unifications' do
|
128
|
+
|
129
|
+
let(:goal1) { new_goal :p, :x, :y }
|
130
|
+
let(:goal2) { new_goal :q, :i, :j, :k }
|
131
|
+
let(:goal3) { new_goal :r, :n }
|
132
|
+
|
133
|
+
it 'should precheck inconsistent unifications' do
|
134
|
+
unifications = [
|
135
|
+
[:x, :k, goal1, goal2],
|
136
|
+
[:x, :j, goal1, goal2],
|
137
|
+
[:x, 12, goal1, goal3],
|
138
|
+
[:x, 37, goal1, goal3],
|
139
|
+
]
|
140
|
+
|
141
|
+
refute instantiate_unifications(unifications), name
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'should create instantiations' do
|
145
|
+
# -- Setup --
|
146
|
+
unifications = [
|
147
|
+
[:x, :k, goal1, goal2],
|
148
|
+
[:x, :j, goal1, goal2],
|
149
|
+
[:x, 12, goal1, goal3],
|
150
|
+
]
|
151
|
+
|
152
|
+
# -- Precondition Baseline --
|
153
|
+
assert_Goal_variables goal1, { x: nil, y: nil }, [
|
154
|
+
'Goal1.:x',
|
155
|
+
'Goal1.:y',
|
156
|
+
].join("\n")
|
157
|
+
|
158
|
+
assert_Goal_variables goal2, { i: nil, j: nil, k: nil }, [
|
159
|
+
'Goal2.:i',
|
160
|
+
'Goal2.:j',
|
161
|
+
'Goal2.:k',
|
162
|
+
].join("\n")
|
163
|
+
|
164
|
+
assert_Goal_variables goal3, { n: nil }, [
|
165
|
+
'Goal3.:n',
|
166
|
+
].join("\n")
|
167
|
+
|
168
|
+
# -- Test --
|
169
|
+
assert instantiate_unifications(unifications), name
|
170
|
+
|
171
|
+
# -- Compare Result Against Baseline --
|
172
|
+
assert_Goal_variables goal1, { x: 12, y: nil }, [
|
173
|
+
'Goal1.:x',
|
174
|
+
' Goal2.:k',
|
175
|
+
' Goal2.:j',
|
176
|
+
' Goal3.12',
|
177
|
+
'Goal1.:y',
|
178
|
+
].join("\n")
|
179
|
+
|
180
|
+
assert_Goal_variables goal2, { i: nil, j: 12, k: 12 }, [
|
181
|
+
'Goal2.:i',
|
182
|
+
'Goal2.:j',
|
183
|
+
' Goal1.:x',
|
184
|
+
' Goal2.:k',
|
185
|
+
' Goal3.12',
|
186
|
+
'Goal2.:k',
|
187
|
+
' Goal1.:x',
|
188
|
+
' Goal2.:j',
|
189
|
+
' Goal3.12',
|
190
|
+
].join("\n")
|
191
|
+
|
192
|
+
assert_Goal_variables goal3, { n: nil }, [
|
193
|
+
'Goal3.:n',
|
194
|
+
].join("\n")
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'should return false for inconsistent unifications not picked up by the precheck' do
|
198
|
+
# 12
|
199
|
+
# /
|
200
|
+
# i
|
201
|
+
# \
|
202
|
+
# x
|
203
|
+
# /
|
204
|
+
# j
|
205
|
+
# \
|
206
|
+
# y
|
207
|
+
# /
|
208
|
+
# k
|
209
|
+
# \
|
210
|
+
# 37
|
211
|
+
unifications = [
|
212
|
+
[:x, :i, goal1, goal2],
|
213
|
+
[:i, 12, goal2, goal3],
|
214
|
+
[:j, :x, goal2, goal1],
|
215
|
+
[:j, :y, goal2, goal1],
|
216
|
+
[:k, :y, goal2, goal1],
|
217
|
+
[:k, 37, goal2, goal3],
|
218
|
+
]
|
219
|
+
|
220
|
+
refute instantiate_unifications(unifications), name
|
221
|
+
|
222
|
+
assert_Goal_variables goal1, { x: nil, y: nil }, [
|
223
|
+
'Goal1.:x',
|
224
|
+
'Goal1.:y',
|
225
|
+
].join("\n")
|
226
|
+
|
227
|
+
assert_Goal_variables goal2, { i: nil, j: nil, k: nil }, [
|
228
|
+
'Goal2.:i',
|
229
|
+
'Goal2.:j',
|
230
|
+
'Goal2.:k',
|
231
|
+
].join("\n")
|
232
|
+
|
233
|
+
assert_Goal_variables goal3, { n: nil }, [
|
234
|
+
'Goal3.:n',
|
235
|
+
].join("\n")
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
describe '#unify' do
|
241
|
+
|
242
|
+
let(:goal) { new_goal :p, :x, :y }
|
243
|
+
let(:goal2) { new_goal :q, :x, :y }
|
244
|
+
|
245
|
+
describe 'when [:atomic,:atomic]' do
|
246
|
+
|
247
|
+
it 'should unify equal atomic numbers' do
|
248
|
+
assert unify(42, 42, goal), name
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'should not unify unequal atomic numbers' do
|
252
|
+
refute unify(42, 99, goal), name
|
253
|
+
|
254
|
+
expected_log = [
|
255
|
+
'Cannot unify because 42 != 99 (atomic != atomic)',
|
256
|
+
]
|
257
|
+
|
258
|
+
assert_equal expected_log, goal.log
|
259
|
+
end
|
260
|
+
|
261
|
+
end
|
262
|
+
|
263
|
+
describe 'when [:array,:array]' do
|
264
|
+
|
265
|
+
before do
|
266
|
+
@spy = Spy.on(self, :unify_arrays).and_call_through
|
267
|
+
end
|
268
|
+
|
269
|
+
after do
|
270
|
+
assert_equal 1, @spy.calls.size
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'should unify empty arrays' do
|
274
|
+
assert unify([], [], goal), name
|
275
|
+
end
|
276
|
+
|
277
|
+
it 'should unify equal arrays' do
|
278
|
+
assert unify([7,11,13], [7,11,13], goal), name
|
279
|
+
end
|
280
|
+
|
281
|
+
it 'should not unify unequal arrays' do
|
282
|
+
refute unify([7,11,13], [7,11,14], goal), name
|
283
|
+
|
284
|
+
expected_log = [
|
285
|
+
'Cannot unify incompatible values: 13 with 14',
|
286
|
+
'Cannot unify because [7, 11, 13] != [7, 11, 14] (array != array)',
|
287
|
+
]
|
288
|
+
|
289
|
+
assert_equal expected_log, goal.log
|
290
|
+
end
|
291
|
+
|
292
|
+
it 'should not unify arrays of different lengths' do
|
293
|
+
refute unify([7,11,13], [7,11,13,13], goal), name
|
294
|
+
|
295
|
+
expected_log = [
|
296
|
+
'Cannot unify arrays of different lengths: [7, 11, 13] with [7, 11, 13, 13]',
|
297
|
+
'Cannot unify because [7, 11, 13] != [7, 11, 13, 13] (array != array)',
|
298
|
+
]
|
299
|
+
|
300
|
+
assert_equal expected_log, goal.log
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
304
|
+
|
305
|
+
describe 'when [:variable,:atomic]' do
|
306
|
+
|
307
|
+
before do
|
308
|
+
expects(:unify_arrays).times(0)
|
309
|
+
end
|
310
|
+
|
311
|
+
it 'should return an instantiation' do
|
312
|
+
assert_equal [[:word, 'word', goal, goal]], unify(:word, 'word', goal), name
|
313
|
+
end
|
314
|
+
|
315
|
+
it 'should not unify an instantiated variable with a different value' do
|
316
|
+
goal.instantiate :word, 'other'
|
317
|
+
|
318
|
+
assert_nil unify(:word, 'word', goal), name
|
319
|
+
|
320
|
+
expected_log = [
|
321
|
+
'Cannot unify because Goal1."other" != "word" (variable != atomic)',
|
322
|
+
]
|
323
|
+
|
324
|
+
assert_equal expected_log, goal.log
|
325
|
+
end
|
326
|
+
|
327
|
+
end
|
328
|
+
|
329
|
+
describe 'when [:atomic,:variable]' do
|
330
|
+
|
331
|
+
before do
|
332
|
+
expects(:unify_arrays).times(0)
|
333
|
+
end
|
334
|
+
|
335
|
+
it 'should return an instantiation' do
|
336
|
+
assert_equal [[:word, 'word', goal, goal]], unify('word', :word, goal), name
|
337
|
+
end
|
338
|
+
|
339
|
+
it 'should not unify instantiated variables with different values' do
|
340
|
+
goal.instantiate :word, 'something'
|
341
|
+
|
342
|
+
assert_nil unify('word', :word, goal), name
|
343
|
+
|
344
|
+
expected_log = [
|
345
|
+
'Cannot unify because "word" != Goal1."something" (atomic != variable)',
|
346
|
+
]
|
347
|
+
|
348
|
+
assert_equal expected_log, goal.log
|
349
|
+
end
|
350
|
+
|
351
|
+
end
|
352
|
+
|
353
|
+
describe 'when [:variable, :variable]' do
|
354
|
+
|
355
|
+
before do
|
356
|
+
expects(:unify_arrays).times(0)
|
357
|
+
end
|
358
|
+
|
359
|
+
it 'should return an instantiation' do
|
360
|
+
assert_equal [[:x, :y, goal, goal2]], unify(:x, :y, goal, goal2), name
|
361
|
+
end
|
362
|
+
|
363
|
+
it 'should not unify instantiated variables with different values' do
|
364
|
+
goal.instantiate :word, 'something'
|
365
|
+
goal.instantiate :draw, 'picturing'
|
366
|
+
|
367
|
+
assert_nil unify(:draw, :word, goal), name
|
368
|
+
|
369
|
+
expected_log = [
|
370
|
+
'Cannot unify because Goal1."picturing" != Goal1."something" (variable != variable)'
|
371
|
+
]
|
372
|
+
|
373
|
+
assert_equal expected_log, goal.log
|
374
|
+
end
|
375
|
+
|
376
|
+
end
|
377
|
+
|
378
|
+
describe 'when [:variable, :array]' do
|
379
|
+
|
380
|
+
it 'should return an instantiation' do
|
381
|
+
expects(:unify_arrays).times(0)
|
382
|
+
|
383
|
+
assert_equal [[:list, [7,11,13], goal, goal]], unify(:list, [7,11,13], goal), name
|
384
|
+
end
|
385
|
+
|
386
|
+
it 'should not unify instantiated variables with different values' do
|
387
|
+
goal.instantiate :word, [1,2,3,4]
|
388
|
+
expects(:unify_arrays).times(1)
|
389
|
+
|
390
|
+
assert_nil unify(:word, [1,2,3,5], goal), name
|
391
|
+
|
392
|
+
expected_log = [
|
393
|
+
'Cannot unify because Goal1.[1, 2, 3, 4] != [1, 2, 3, 5] (variable/array != array)'
|
394
|
+
]
|
395
|
+
|
396
|
+
assert_equal expected_log, goal.log
|
397
|
+
end
|
398
|
+
|
399
|
+
it 'should not unify instantiated variables with a non-array value' do
|
400
|
+
goal.instantiate :word, 1234
|
401
|
+
expects(:unify_arrays).times(0)
|
402
|
+
|
403
|
+
assert_nil unify(:word, [1,2,3,5], goal), name
|
404
|
+
|
405
|
+
expected_log = [
|
406
|
+
'Cannot unify because Goal1.1234 != [1, 2, 3, 5] (variable != array)'
|
407
|
+
]
|
408
|
+
|
409
|
+
assert_equal expected_log, goal.log
|
410
|
+
end
|
411
|
+
|
412
|
+
end
|
413
|
+
|
414
|
+
describe 'when [:array, :variable]' do
|
415
|
+
|
416
|
+
it 'should not unify instantiated variables that are not instantiated with an array' do
|
417
|
+
goal.instantiate :word, '1 2 3 4'
|
418
|
+
|
419
|
+
assert_nil unify([1,2,3,4], :word, goal), name
|
420
|
+
|
421
|
+
expected_log = [
|
422
|
+
'Cannot unify because [1, 2, 3, 4] != Goal1."1 2 3 4" (array != variable)'
|
423
|
+
]
|
424
|
+
|
425
|
+
assert_equal expected_log, goal.log
|
426
|
+
end
|
427
|
+
|
428
|
+
it 'should return an instantiation' do
|
429
|
+
expects(:unify_arrays).times(0)
|
430
|
+
|
431
|
+
assert_equal [[:list, [7,11,13], goal, goal]], unify([7,11,13], :list, goal), name
|
432
|
+
end
|
433
|
+
|
434
|
+
it 'should not unify instantiated variables with different values' do
|
435
|
+
goal.instantiate :word, [1,2,3,4]
|
436
|
+
expects(:unify_arrays).times(1)
|
437
|
+
|
438
|
+
assert_nil unify([1,2,3,5], :word, goal), name
|
439
|
+
|
440
|
+
expected_log = [
|
441
|
+
'Cannot unify because [1, 2, 3, 5] != Goal1.[1, 2, 3, 4] (variable/array != array)'
|
442
|
+
]
|
443
|
+
|
444
|
+
assert_equal expected_log, goal.log
|
445
|
+
end
|
446
|
+
|
447
|
+
it 'should unify instantiated variables with unifiable values' do
|
448
|
+
goal.instantiate :word, [1,2,3]/:w
|
449
|
+
|
450
|
+
instantiations = unify([nil,nil,3,4,5], :word, goal)
|
451
|
+
|
452
|
+
expected_log = []
|
453
|
+
expected_instantiations = [
|
454
|
+
[:w, [4,5], goal, goal],
|
455
|
+
]
|
456
|
+
|
457
|
+
assert_equal expected_log, goal.log
|
458
|
+
assert_equal expected_instantiations, instantiations
|
459
|
+
end
|
460
|
+
|
461
|
+
end
|
462
|
+
|
463
|
+
describe 'when [:array,:atomic], [:atomic,:array]' do
|
464
|
+
|
465
|
+
before do
|
466
|
+
expects(:unify_arrays).times(0)
|
467
|
+
end
|
468
|
+
|
469
|
+
it 'should return nil for unifying array and atomic' do
|
470
|
+
assert_nil unify([7,11,13], 'word', goal), name
|
471
|
+
|
472
|
+
expected_log = [
|
473
|
+
'Cannot unify [7, 11, 13] with "word"',
|
474
|
+
]
|
475
|
+
|
476
|
+
assert_equal expected_log, goal.log
|
477
|
+
end
|
478
|
+
|
479
|
+
it 'should return nil for unifying atomic and array' do
|
480
|
+
assert_nil unify('word', [7,11,13], goal), name
|
481
|
+
|
482
|
+
expected_log = [
|
483
|
+
'Cannot unify "word" with [7, 11, 13]',
|
484
|
+
]
|
485
|
+
|
486
|
+
assert_equal expected_log, goal.log
|
487
|
+
end
|
488
|
+
|
489
|
+
end
|
490
|
+
|
491
|
+
end
|
492
|
+
|
493
|
+
describe '#unify_arrays' do
|
494
|
+
|
495
|
+
let(:g1) { new_goal(:p, :x, :y) }
|
496
|
+
let(:g2) { new_goal(:q, :a, :b) }
|
497
|
+
let(:goals) { [g1, g2] }
|
498
|
+
|
499
|
+
it 'should not unify arrays when left is not an Array' do
|
500
|
+
expect_unify_arrays_with_calls 0, 0, 0
|
501
|
+
|
502
|
+
refute_Unify_arrays [{}, []], goals, [
|
503
|
+
'Cannot unify a non-array with an array: {} with []',
|
504
|
+
]
|
505
|
+
end
|
506
|
+
|
507
|
+
it 'should not unify arrays when right is not an Array' do
|
508
|
+
expect_unify_arrays_with_calls 0, 0, 0
|
509
|
+
|
510
|
+
refute_Unify_arrays [[], 4], goals, [
|
511
|
+
'Cannot unify a non-array with an array: [] with 4',
|
512
|
+
]
|
513
|
+
end
|
514
|
+
|
515
|
+
it 'should unify but without unifications when left is the unknown array' do
|
516
|
+
expect_unify_arrays_with_calls 0, 0, 0
|
517
|
+
|
518
|
+
assert_Unify_arrays [UNKNOWN_ARRAY, [:a,:b,:c]], goals, [g2[:a], g2[:b], g2[:c]]
|
519
|
+
end
|
520
|
+
|
521
|
+
it 'should unify but without unifications when right is the unknown array' do
|
522
|
+
expect_unify_arrays_with_calls 0, 0, 0
|
523
|
+
|
524
|
+
assert_Unify_arrays [[:x,:y,:z], UNKNOWN_ARRAY], goals, [g1[:x], g1[:y], g1[:z]]
|
525
|
+
end
|
526
|
+
|
527
|
+
it 'should unify but without unifications when left and right are the unknown array' do
|
528
|
+
expect_unify_arrays_with_calls 0, 0, 0
|
529
|
+
|
530
|
+
assert_Unify_arrays [[UNKNOWN_TAIL], UNKNOWN_ARRAY], goals, UNKNOWN_ARRAY
|
531
|
+
end
|
532
|
+
|
533
|
+
arrays_without_tails = [
|
534
|
+
[],
|
535
|
+
[1, 2, 3],
|
536
|
+
[1, 2, 3, 4],
|
537
|
+
[:x, :y, :z],
|
538
|
+
[['one'], ['word'], ['sentences']],
|
539
|
+
]
|
540
|
+
|
541
|
+
arrays_with_tails = [
|
542
|
+
[]/:t,
|
543
|
+
[1]/:z,
|
544
|
+
[1, 2]/:s,
|
545
|
+
[1, UNKNOWN_TAIL],
|
546
|
+
[1, 2, 3, UNKNOWN_TAIL],
|
547
|
+
[1, 2, 3, 4, UNKNOWN_TAIL],
|
548
|
+
[:x, :y, :z, UNKNOWN_TAIL],
|
549
|
+
[['one'], ['word'], ['sentences']]/:tail,
|
550
|
+
]
|
551
|
+
|
552
|
+
arrays_without_tails.combination(2).each do |arrays|
|
553
|
+
it "should call unify_arrays_with_no_tails when there are no tails: #{arrays.map(&:inspect).join(' and ')}" do
|
554
|
+
expect_unify_arrays_with_calls 1, 0, 0
|
555
|
+
|
556
|
+
unify_arrays(*arrays, *goals)
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
560
|
+
arrays_with_tails.combination(2).each do |arrays|
|
561
|
+
it "should call unify_arrays_with_all_tails when all arrays have tails: #{arrays.map(&:inspect).join(' and ')}" do
|
562
|
+
expect_unify_arrays_with_calls 0, 0, 1
|
563
|
+
|
564
|
+
unify_arrays(*arrays, *goals)
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
(
|
569
|
+
arrays_without_tails.product(arrays_with_tails) +
|
570
|
+
arrays_with_tails.product(arrays_without_tails)
|
571
|
+
).each do |arrays|
|
572
|
+
it "should call unify_arrays_with_some_tails when one array has a tail and the other does not: #{arrays.map(&:inspect).join(' and ')}" do
|
573
|
+
expect_unify_arrays_with_calls 0, 1, 0
|
574
|
+
|
575
|
+
unify_arrays(*arrays, *goals)
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
579
|
+
it 'should unify identical arrays without variables' do
|
580
|
+
assert_Unify_arrays [[1,2,3], [1,2,3]], goals, [1,2,3]
|
581
|
+
end
|
582
|
+
|
583
|
+
it 'should unify an array of variables with an array of atomics' do
|
584
|
+
assert_Unify_arrays [[:a,:b,:c], [1,2,3]], goals, [1,2,3], [
|
585
|
+
[:a, 1, g1, g2],
|
586
|
+
[:b, 2, g1, g2],
|
587
|
+
[:c, 3, g1, g2],
|
588
|
+
]
|
589
|
+
end
|
590
|
+
|
591
|
+
it 'should unify an array of atomics with an array of variables' do
|
592
|
+
assert_Unify_arrays [[1,2,3], [:a,:b,:c]], goals, [1,2,3], [
|
593
|
+
[:a, 1, g2, g1],
|
594
|
+
[:b, 2, g2, g1],
|
595
|
+
[:c, 3, g2, g1],
|
596
|
+
]
|
597
|
+
end
|
598
|
+
|
599
|
+
it 'should unify arrays of variables' do
|
600
|
+
assert_Unify_arrays [[:x,:y,:z], [:a,:b,:c]], goals, [nil,nil,nil], [
|
601
|
+
[:x, :a, g1, g2],
|
602
|
+
[:y, :b, g1, g2],
|
603
|
+
[:z, :c, g1, g2],
|
604
|
+
]
|
605
|
+
end
|
606
|
+
|
607
|
+
it 'should unify a fixed array with an array with a tail' do
|
608
|
+
assert_Unify_arrays [[:a, 2, 3], [1]/:t], goals, [1,2,3], [
|
609
|
+
[:a, 1, g1, g2],
|
610
|
+
[:t, [2,3], g2, g1],
|
611
|
+
]
|
612
|
+
end
|
613
|
+
|
614
|
+
it 'should unify a fixed array with the unknown array' do
|
615
|
+
assert_Unify_arrays [[1,2,3], UNKNOWN_ARRAY], goals, [1,2,3]
|
616
|
+
end
|
617
|
+
|
618
|
+
it 'should unify the unknown array with the unknown array' do
|
619
|
+
assert_Unify_arrays [UNKNOWN_ARRAY, UNKNOWN_ARRAY], goals, UNKNOWN_ARRAY
|
620
|
+
end
|
621
|
+
|
622
|
+
it 'should unify arrays with variable tails' do
|
623
|
+
assert_Unify_arrays [[:a, :b]/:c, [:x, :y]/:z], goals, [nil,nil,UNKNOWN_TAIL], [
|
624
|
+
[:a, :x, g1, g2],
|
625
|
+
[:b, :y, g1, g2],
|
626
|
+
[:c, :z, g1, g2],
|
627
|
+
]
|
628
|
+
end
|
629
|
+
|
630
|
+
it 'should unify arrays with variable tails of different lenths' do
|
631
|
+
assert_Unify_arrays [[:a, :b]/:c, [:x]/:z], goals, [nil,nil,UNKNOWN_TAIL], [
|
632
|
+
[g2[:x], g1[:a], g2, g1],
|
633
|
+
[g2[:z], [g1[:b]]/g1[:c], g2, g1],
|
634
|
+
]
|
635
|
+
end
|
636
|
+
|
637
|
+
it 'should unify arrays with overlapping variables' do
|
638
|
+
assert_Unify_arrays [[:a,:a,:c,:c,:e], [1,:b,:b,:d,:d]], goals, [1, nil, nil, nil, nil], [
|
639
|
+
[g1[:a], g2[1], g1, g2],
|
640
|
+
[g1[:a], g2[:b], g1, g2],
|
641
|
+
[g1[:c], g2[:b], g1, g2],
|
642
|
+
[g1[:c], g2[:d], g1, g2],
|
643
|
+
[g1[:e], g2[:d], g1, g2],
|
644
|
+
]
|
645
|
+
end
|
646
|
+
|
647
|
+
it 'should unify complementary arrays' do
|
648
|
+
assert_Unify_arrays [[1,2]/:t, [:a,:b,3,4,5]], goals, [1,2,3,4,5], [
|
649
|
+
[g2[:a], g1[1], g2, g1],
|
650
|
+
[g2[:b], g1[2], g2, g1],
|
651
|
+
[g1[:t], [3, 4, 5], g1, g2],
|
652
|
+
]
|
653
|
+
end
|
654
|
+
|
655
|
+
end
|
656
|
+
|
657
|
+
describe '#unify_many_arrays' do
|
658
|
+
|
659
|
+
let(:goal) { new_goal(:p, :x, :y) }
|
660
|
+
|
661
|
+
it 'should return nil when not all arrays are Arrays or variables' do
|
662
|
+
arrays = [
|
663
|
+
[1,2,3],
|
664
|
+
123,
|
665
|
+
:x,
|
666
|
+
]
|
667
|
+
|
668
|
+
assert_nil unify_many_arrays(arrays, [goal] * arrays.size), name
|
669
|
+
|
670
|
+
expected_log = [
|
671
|
+
'Cannot unify: [1, 2, 3] with 123 with :x',
|
672
|
+
]
|
673
|
+
|
674
|
+
assert_equal expected_log, goal.log
|
675
|
+
end
|
676
|
+
|
677
|
+
it 'should not return nil when all arrays are Arrays or variables' do
|
678
|
+
arrays = [
|
679
|
+
[1,2,3],
|
680
|
+
UNKNOWN_ARRAY,
|
681
|
+
:x,
|
682
|
+
]
|
683
|
+
|
684
|
+
result = unify_many_arrays(arrays, [goal] * arrays.size)
|
685
|
+
refute_nil result, name
|
686
|
+
|
687
|
+
merged, unifications = result
|
688
|
+
|
689
|
+
expected_merged = [1,2,3]
|
690
|
+
expected_unifications = [
|
691
|
+
]
|
692
|
+
|
693
|
+
assert_equal expected_merged, merged
|
694
|
+
assert_equal expected_unifications, unifications
|
695
|
+
end
|
696
|
+
|
697
|
+
it 'should automatically merge unknown arrays' do
|
698
|
+
arrays = [
|
699
|
+
[1,2,3],
|
700
|
+
UNKNOWN_ARRAY,
|
701
|
+
]
|
702
|
+
|
703
|
+
assert_equal [[1,2,3], []], unify_many_arrays(arrays, [goal] * arrays.size), name
|
704
|
+
end
|
705
|
+
|
706
|
+
it 'should call unify_arrays_with_no_tails when there are no Arrays with Tails' do
|
707
|
+
expect_unify_arrays_with_calls 1, 0, 0
|
708
|
+
|
709
|
+
arrays = [
|
710
|
+
[1, 2, 3, nil],
|
711
|
+
[1, nil, 3, 4],
|
712
|
+
[nil, 2, 3, nil],
|
713
|
+
]
|
714
|
+
|
715
|
+
unify_many_arrays(arrays, [goal] * arrays.size)
|
716
|
+
end
|
717
|
+
|
718
|
+
it 'should call unify_arrays_with_all_tails when all Arrays have Tails' do
|
719
|
+
expect_unify_arrays_with_calls 0, 0, 1
|
720
|
+
|
721
|
+
arrays = [
|
722
|
+
[1, 2, 3, UNKNOWN_TAIL],
|
723
|
+
[1, nil, 3, ]/:x,
|
724
|
+
]
|
725
|
+
|
726
|
+
unify_many_arrays(arrays, [goal] * arrays.size)
|
727
|
+
end
|
728
|
+
|
729
|
+
it 'should call unify_arrays_with_some_tails when there is a combination of Arrays with and without Tails' do
|
730
|
+
expect_unify_arrays_with_calls 0, 1, 0
|
731
|
+
|
732
|
+
arrays = [
|
733
|
+
[1, 2, 3, UNKNOWN_TAIL],
|
734
|
+
[1, nil, 3, 4],
|
735
|
+
[nil, 2, 3, nil],
|
736
|
+
]
|
737
|
+
|
738
|
+
unify_many_arrays(arrays, [goal] * arrays.size)
|
739
|
+
end
|
740
|
+
|
741
|
+
end
|
742
|
+
|
743
|
+
describe '#has_tail?' do
|
744
|
+
|
745
|
+
# -- Non-Arrays --
|
746
|
+
let(:goal) { new_goal(:p, :x, :y) }
|
747
|
+
let(:variable) { goal.variable(:x) }
|
748
|
+
let(:object) { Object.new }
|
749
|
+
let(:symbol) { :symbol }
|
750
|
+
let(:integer) { 789 }
|
751
|
+
|
752
|
+
# -- Arrays --
|
753
|
+
let(:empty_array) { [] }
|
754
|
+
let(:finite_array) { [1,2,3,4,5] }
|
755
|
+
let(:array_with_unknown_tail) { [1,2,3,4,5,UNKNOWN_TAIL] }
|
756
|
+
let(:array_with_variable_tail) { [1,2,3,4,5]/:tail }
|
757
|
+
let(:unknown_array) { UNKNOWN_ARRAY }
|
758
|
+
|
759
|
+
describe 'when not given an Array' do
|
760
|
+
|
761
|
+
it 'should return false when given an uninstantiated variable' do
|
762
|
+
refute has_tail?(variable), name
|
763
|
+
end
|
764
|
+
|
765
|
+
it 'should return false when given an Object' do
|
766
|
+
refute has_tail?(object), name
|
767
|
+
end
|
768
|
+
|
769
|
+
it 'should return false when given a Symbol' do
|
770
|
+
refute has_tail?(symbol), name
|
771
|
+
end
|
772
|
+
|
773
|
+
it 'should return false when given an Integer' do
|
774
|
+
refute has_tail?(integer), name
|
775
|
+
end
|
776
|
+
|
777
|
+
end
|
778
|
+
|
779
|
+
describe 'when given an Array' do
|
780
|
+
|
781
|
+
it 'should return false when the Array is empty' do
|
782
|
+
refute has_tail?(empty_array), name
|
783
|
+
end
|
784
|
+
|
785
|
+
it 'should return false when the last element is atomic' do
|
786
|
+
refute has_tail?(finite_array), name
|
787
|
+
end
|
788
|
+
|
789
|
+
it 'should return true when the last element is unknown' do
|
790
|
+
assert has_tail?(array_with_unknown_tail), name
|
791
|
+
end
|
792
|
+
|
793
|
+
it 'should return true when the last element is a Tail' do
|
794
|
+
assert has_tail?(array_with_variable_tail), name
|
795
|
+
end
|
796
|
+
|
797
|
+
it 'should return true when given an unknown array' do
|
798
|
+
assert has_tail?(unknown_array), name
|
799
|
+
end
|
800
|
+
|
801
|
+
describe 'and the array has an instantiated tail' do
|
802
|
+
|
803
|
+
before do
|
804
|
+
goal.instantiate :a, 1
|
805
|
+
goal.instantiate :b, 2
|
806
|
+
goal.instantiate :c, 3
|
807
|
+
goal.instantiate :d, 4
|
808
|
+
goal.instantiate :e, [5]
|
809
|
+
end
|
810
|
+
|
811
|
+
describe 'and to apply value to the array' do
|
812
|
+
|
813
|
+
it 'should return false' do
|
814
|
+
array = goal.variablise([:a, :b, :c, :d]/:e)
|
815
|
+
|
816
|
+
refute has_tail?(array, true), name
|
817
|
+
end
|
818
|
+
|
819
|
+
end
|
820
|
+
|
821
|
+
describe 'and to not apply value to the array' do
|
822
|
+
|
823
|
+
it 'should return true' do
|
824
|
+
array = goal.variablise([:a, :b, :c, :d]/:e)
|
825
|
+
|
826
|
+
assert has_tail?(array, false), name
|
827
|
+
end
|
828
|
+
|
829
|
+
end
|
830
|
+
|
831
|
+
end
|
832
|
+
|
833
|
+
end
|
834
|
+
|
835
|
+
end
|
836
|
+
|
837
|
+
describe '#expand_splat' do
|
838
|
+
|
839
|
+
it 'should return an empty array as is' do
|
840
|
+
assert_equal [], expand_splat([])
|
841
|
+
end
|
842
|
+
|
843
|
+
it 'should return non-arrays as is' do
|
844
|
+
assert_equal 5, expand_splat(5)
|
845
|
+
end
|
846
|
+
|
847
|
+
it 'should expand an array of just a Tail' do
|
848
|
+
assert_equal :t, expand_splat([]/:t)
|
849
|
+
end
|
850
|
+
|
851
|
+
it 'should not expand an array with a Tail' do
|
852
|
+
assert_equal [1,2,3]/:t, expand_splat([1,2,3]/:t)
|
853
|
+
end
|
854
|
+
|
855
|
+
it 'should expand a tail' do
|
856
|
+
assert_equal [1,2,3,4,5], expand_splat([1,2,3,Tail.new([4,5])])
|
857
|
+
end
|
858
|
+
|
859
|
+
it 'should expand nested arrays' do
|
860
|
+
assert_equal [99, [1,2,3,4], 99], expand_splat([99,[1,2,3,Tail.new([4])],99])
|
861
|
+
end
|
862
|
+
|
863
|
+
end
|
864
|
+
|
865
|
+
describe '#unify_arrays_with_no_tails' do
|
866
|
+
|
867
|
+
let(:g1) { new_goal(:p, :x, :y) }
|
868
|
+
let(:g2) { new_goal(:q, :a, :b) }
|
869
|
+
let(:g3) { new_goal(:r, :s, :t) }
|
870
|
+
let(:g4) { new_goal(:v, :i, :j) }
|
871
|
+
let(:goals) { [g1, g2, g3, g4] }
|
872
|
+
|
873
|
+
it 'should return nil when any array has a tail' do
|
874
|
+
arrays = [
|
875
|
+
[1, 2, 3, 4],
|
876
|
+
[1, 2, 3]/:tail,
|
877
|
+
[:w, :x, :y, :z]
|
878
|
+
]
|
879
|
+
arrays_goals = goals[0..arrays.size]
|
880
|
+
|
881
|
+
assert_nil unify_arrays_with_no_tails(arrays, arrays_goals, []), name
|
882
|
+
|
883
|
+
expected_log = [
|
884
|
+
'Wrong unification method called: no_tails but one or more of [[1, 2, 3, 4], [1, 2, 3, *:tail], [:w, :x, :y, :z]] has a tail',
|
885
|
+
]
|
886
|
+
|
887
|
+
arrays_goals.each do |goal|
|
888
|
+
assert_equal expected_log, goal.log
|
889
|
+
end
|
890
|
+
end
|
891
|
+
|
892
|
+
it 'should not unify finite arrays with unequal sizes' do
|
893
|
+
# -- First > Last --
|
894
|
+
arrays = [
|
895
|
+
[nil, nil, nil, nil],
|
896
|
+
[1, 2, 3]
|
897
|
+
]
|
898
|
+
arrays_goals = goals[0...arrays.size]
|
899
|
+
|
900
|
+
assert_nil unify_arrays_with_no_tails(arrays, arrays_goals, []), name
|
901
|
+
|
902
|
+
# -- First = Last --
|
903
|
+
arrays = [
|
904
|
+
[nil, nil, nil],
|
905
|
+
[1, 2, 3]
|
906
|
+
]
|
907
|
+
arrays_goals = goals[0...arrays.size]
|
908
|
+
|
909
|
+
expected_merged = [1,2,3]
|
910
|
+
expected_unifications = []
|
911
|
+
|
912
|
+
merged, unifications = unify_arrays_with_no_tails(arrays, arrays_goals, [])
|
913
|
+
|
914
|
+
assert_equal expected_merged, merged
|
915
|
+
assert_equal expected_unifications, unifications
|
916
|
+
|
917
|
+
# -- First < Last --
|
918
|
+
arrays = [
|
919
|
+
[nil, nil],
|
920
|
+
[1, 2, 3]
|
921
|
+
]
|
922
|
+
arrays_goals = goals[0...arrays.size]
|
923
|
+
|
924
|
+
assert_nil unify_arrays_with_no_tails(arrays, arrays_goals, []), name
|
925
|
+
|
926
|
+
# -- Check Log --
|
927
|
+
expected_log = [
|
928
|
+
'Cannot unify arrays of different lengths: [nil, nil, nil, nil] with [1, 2, 3]',
|
929
|
+
'Cannot unify arrays of different lengths: [nil, nil] with [1, 2, 3]',
|
930
|
+
]
|
931
|
+
|
932
|
+
arrays_goals.each do |goal|
|
933
|
+
assert_equal expected_log, goal.log
|
934
|
+
end
|
935
|
+
end
|
936
|
+
|
937
|
+
it 'should merge values with nil as an empty slot' do
|
938
|
+
arrays = [
|
939
|
+
[1, 2, 3, nil, nil],
|
940
|
+
[nil, nil, nil, 4, nil],
|
941
|
+
[nil, nil, nil, nil, 5],
|
942
|
+
]
|
943
|
+
arrays_goals = goals[0...arrays.size]
|
944
|
+
|
945
|
+
merged, unifications = unify_arrays_with_no_tails(arrays, arrays_goals, [])
|
946
|
+
|
947
|
+
expected_merged = [1, 2, 3, 4, 5]
|
948
|
+
expected_unifications = []
|
949
|
+
|
950
|
+
assert_equal expected_merged, merged
|
951
|
+
assert_equal expected_unifications, unifications
|
952
|
+
end
|
953
|
+
|
954
|
+
it 'should return nil when the finite arrays have different sizes' do
|
955
|
+
arrays = [
|
956
|
+
[nil],
|
957
|
+
[nil, nil, nil, nil],
|
958
|
+
[nil, nil, nil, nil, nil, nil],
|
959
|
+
]
|
960
|
+
arrays_goals = goals[0...arrays.size]
|
961
|
+
|
962
|
+
assert_nil unify_arrays_with_no_tails(arrays, arrays_goals, []), name
|
963
|
+
|
964
|
+
expected_log = [
|
965
|
+
'Cannot unify arrays of different lengths: [nil] with [nil, nil, nil, nil] with [nil, nil, nil, nil, nil, nil]',
|
966
|
+
]
|
967
|
+
|
968
|
+
arrays_goals.each do |goal|
|
969
|
+
assert_equal expected_log, goal.log
|
970
|
+
end
|
971
|
+
end
|
972
|
+
|
973
|
+
it 'should return nil when the arrays have incompatible values' do
|
974
|
+
arrays = [
|
975
|
+
[1, 2, 3, nil, nil],
|
976
|
+
[nil, nil, nil, 4, nil],
|
977
|
+
[8, nil, nil, nil, 5],
|
978
|
+
]
|
979
|
+
arrays_goals = goals[0...arrays.size]
|
980
|
+
|
981
|
+
assert_nil unify_arrays_with_no_tails(arrays, arrays_goals, []), name
|
982
|
+
|
983
|
+
expected_log = [
|
984
|
+
'Cannot unify incompatible values: 1 with 8',
|
985
|
+
]
|
986
|
+
|
987
|
+
arrays_goals.each do |goal|
|
988
|
+
assert_equal expected_log, goal.log
|
989
|
+
end
|
990
|
+
end
|
991
|
+
|
992
|
+
it 'should return necessary unifications to unify variables' do
|
993
|
+
arrays = [
|
994
|
+
[1, 2, nil, nil, nil],
|
995
|
+
[:j, :n, :n, 4, nil],
|
996
|
+
[:x, nil, :m, :y, :z],
|
997
|
+
]
|
998
|
+
arrays_goals = goals[0...arrays.size]
|
999
|
+
|
1000
|
+
merged, unifications = unify_arrays_with_no_tails(arrays, arrays_goals, [])
|
1001
|
+
|
1002
|
+
expected_merged = [1, 2, nil, 4, nil]
|
1003
|
+
expected_unifications = [
|
1004
|
+
[g2[:j], g1[1], g2, g1],
|
1005
|
+
[g3[:x], g1[1], g3, g1],
|
1006
|
+
[g2[:j], g3[:x], g2, g3],
|
1007
|
+
[g2[:n], g1[2], g2, g1],
|
1008
|
+
[g2[:n], g3[:m], g2, g3],
|
1009
|
+
[g3[:y], g2[4], g3, g2],
|
1010
|
+
]
|
1011
|
+
|
1012
|
+
assert_equal expected_merged, merged
|
1013
|
+
assert_equal expected_unifications, unifications
|
1014
|
+
end
|
1015
|
+
|
1016
|
+
it 'should deduce array goals from array elements when missing' do
|
1017
|
+
arrays = [
|
1018
|
+
[ nil, 2, nil, g1.value(4), nil],
|
1019
|
+
g2.value([1, nil, 3, nil, nil]),
|
1020
|
+
g3.value([nil, :x, nil, nil, 5]),
|
1021
|
+
]
|
1022
|
+
missing_goals = [nil, nil, nil]
|
1023
|
+
|
1024
|
+
merged, unifications = unify_arrays_with_no_tails(arrays, missing_goals, [])
|
1025
|
+
|
1026
|
+
expected_merged = [1, 2, 3, 4, 5]
|
1027
|
+
expected_unifications = [
|
1028
|
+
[g3.variable(:x), g1.value(2), g3, g1]
|
1029
|
+
]
|
1030
|
+
|
1031
|
+
assert_equal expected_merged, merged
|
1032
|
+
assert_equal expected_unifications, unifications
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
it 'should map Values as is' do
|
1036
|
+
value1 = g1.value(91)
|
1037
|
+
g1.instantiate(:gi, [nil, value1, nil, 93])
|
1038
|
+
|
1039
|
+
arrays = [
|
1040
|
+
[ nil, 2, nil, :gi, nil],
|
1041
|
+
g2.value([1, nil, 3, [90, nil, nil, nil], nil]),
|
1042
|
+
g3.value([nil, :x, nil, [nil, nil, 92, :gy], 5]),
|
1043
|
+
]
|
1044
|
+
|
1045
|
+
arrays_goals = [g1, nil, nil]
|
1046
|
+
|
1047
|
+
merged, unifications = unify_arrays_with_no_tails(arrays, arrays_goals, [])
|
1048
|
+
|
1049
|
+
expected_merged = [1, 2, 3, [90, 91, 92, 93], 5]
|
1050
|
+
expected_unifications = [
|
1051
|
+
[g3.variable(:x), g1.value(2), g3, g1],
|
1052
|
+
[g3.variable(:gy), g1.value(93), g3, g1],
|
1053
|
+
]
|
1054
|
+
|
1055
|
+
assert_equal expected_merged, merged
|
1056
|
+
assert_equal expected_unifications, unifications
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
it 'should detect ununifiable values embedded in subarrays' do
|
1060
|
+
value1 = g1.value(91)
|
1061
|
+
g1.instantiate(:gi, [nil, value1, 92.1, 93])
|
1062
|
+
|
1063
|
+
arrays = [
|
1064
|
+
[ nil, 2, nil, :gi, nil],
|
1065
|
+
g2.value([1, nil, 3, [90, nil, nil, nil], nil]),
|
1066
|
+
g3.value([nil, :x, nil, [nil, nil, 92, :gy], 5]),
|
1067
|
+
]
|
1068
|
+
|
1069
|
+
arrays_goals = [g1, nil, nil]
|
1070
|
+
|
1071
|
+
assert_nil unify_arrays_with_no_tails(arrays, arrays_goals, []), name
|
1072
|
+
|
1073
|
+
expected_log = [
|
1074
|
+
'Cannot unify incompatible values: 92.1 with 92',
|
1075
|
+
'Cannot unify: [nil, 91, 92.1, 93] with [90, nil, nil, nil] with [nil, nil, 92, Goal3.:gy]',
|
1076
|
+
]
|
1077
|
+
|
1078
|
+
[g1, g2, g3].each do |goal|
|
1079
|
+
assert_equal expected_log, goal.log
|
1080
|
+
end
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
it 'should not expand variables when they are instantiated to the unknown array' do
|
1084
|
+
arrays_goals = goals[0...4]
|
1085
|
+
g4.instantiate :z, UNKNOWN_ARRAY
|
1086
|
+
arrays = [
|
1087
|
+
[1, 2, nil, nil, nil],
|
1088
|
+
[:j, :n, :n, 4, nil],
|
1089
|
+
[:x, nil, :m, :y, :z],
|
1090
|
+
:z
|
1091
|
+
]
|
1092
|
+
|
1093
|
+
assert_equal UNKNOWN_ARRAY, g4[:z].value
|
1094
|
+
|
1095
|
+
merged, unifications = unify_arrays_with_no_tails(arrays, arrays_goals, [])
|
1096
|
+
|
1097
|
+
expected_merged = [1, 2, nil, 4, nil]
|
1098
|
+
expected_unifications = [
|
1099
|
+
[g2[:j], g1[1], g2, g1],
|
1100
|
+
[g2[:n], g1[2], g2, g1],
|
1101
|
+
[g3[:x], g1[1], g3, g1],
|
1102
|
+
[g4[:z], [g1[1], g1[2], g1.value(nil), g1.value(nil), g1.value(nil)], g4, g1],
|
1103
|
+
[g2[:j], g3[:x], g2, g3],
|
1104
|
+
[g2[:n], g3[:m], g2, g3],
|
1105
|
+
[g3[:y], g2[4], g3, g2],
|
1106
|
+
[g4[:z], [g2[:j], g2[:n], g2[:n], g2[4], g2.value(nil)], g4, g2],
|
1107
|
+
[g4[:z], [g3[:x], g3.value(nil), g3[:m], g3[:y], g3[:z]], g4, g3],
|
1108
|
+
]
|
1109
|
+
|
1110
|
+
assert_equal expected_merged, merged
|
1111
|
+
assert_equal expected_unifications, unifications
|
1112
|
+
end
|
1113
|
+
|
1114
|
+
it 'should not expand variables when they are instantiated to the unknown tail' do
|
1115
|
+
arrays_goals = goals[0...4]
|
1116
|
+
g4.instantiate :z, UNKNOWN_TAIL
|
1117
|
+
arrays = [
|
1118
|
+
[1, 2, nil, nil, nil],
|
1119
|
+
[:j, :n, :n, 4, nil],
|
1120
|
+
[:x, nil, :m, :y, :z],
|
1121
|
+
:z
|
1122
|
+
]
|
1123
|
+
|
1124
|
+
assert_equal g4[:z], g4[:z].value
|
1125
|
+
|
1126
|
+
merged, unifications = unify_arrays_with_no_tails(arrays, arrays_goals, [])
|
1127
|
+
|
1128
|
+
expected_merged = [1, 2, nil, 4, nil]
|
1129
|
+
expected_unifications = [
|
1130
|
+
[g2[:j], g1[1], g2, g1],
|
1131
|
+
[g2[:n], g1[2], g2, g1],
|
1132
|
+
[g3[:x], g1[1], g3, g1],
|
1133
|
+
[g4[:z], [g1[1], g1[2], g1.value(nil), g1.value(nil), g1.value(nil)], g4, g1],
|
1134
|
+
[g2[:j], g3[:x], g2, g3],
|
1135
|
+
[g2[:n], g3[:m], g2, g3],
|
1136
|
+
[g3[:y], g2[4], g3, g2],
|
1137
|
+
[g4[:z], [g2[:j], g2[:n], g2[:n], g2[4], g2.value(nil)], g4, g2],
|
1138
|
+
[g4[:z], [g3[:x], g3.value(nil), g3[:m], g3[:y], g3[:z]], g4, g3],
|
1139
|
+
]
|
1140
|
+
|
1141
|
+
assert_equal expected_merged, merged
|
1142
|
+
assert_equal expected_unifications, unifications
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
it 'should not unify an atomic with an embedded unknown array ' do
|
1146
|
+
value1 = g1.value(91)
|
1147
|
+
g1.instantiate(:gi, [nil, value1, 92.1, 93])
|
1148
|
+
|
1149
|
+
arrays = [
|
1150
|
+
[ nil, 2, nil, :gi, nil],
|
1151
|
+
g2.value([1, nil, 3, [90, nil, nil, nil], nil]),
|
1152
|
+
g3.value([nil, :x, nil, [nil, nil, UNKNOWN_ARRAY, :gy], 5]),
|
1153
|
+
]
|
1154
|
+
|
1155
|
+
arrays_goals = [g1, nil, nil]
|
1156
|
+
|
1157
|
+
assert_nil unify_arrays_with_no_tails(arrays, arrays_goals, []), name
|
1158
|
+
|
1159
|
+
expected_log = [
|
1160
|
+
'Cannot unify incompatible values: 92.1 with [...]',
|
1161
|
+
'Cannot unify: [nil, 91, 92.1, 93] with [90, nil, nil, nil] with [nil, nil, [...], Goal3.:gy]',
|
1162
|
+
]
|
1163
|
+
|
1164
|
+
[g1, g2, g3].each do |goal|
|
1165
|
+
assert_equal expected_log, goal.log
|
1166
|
+
end
|
1167
|
+
end
|
1168
|
+
|
1169
|
+
it 'should not unify arrays where one embedded variable cannot be unified' do
|
1170
|
+
g1.instantiate(:a, :b)
|
1171
|
+
g2.instantiate(:a, 2)
|
1172
|
+
g3.instantiate(:a, 3)
|
1173
|
+
|
1174
|
+
arrays = [
|
1175
|
+
[[:a]],
|
1176
|
+
[[:a]],
|
1177
|
+
[[:a]],
|
1178
|
+
]
|
1179
|
+
arrays_goals = goals[0...arrays.size]
|
1180
|
+
|
1181
|
+
assert_nil unify_arrays_with_no_tails(arrays, arrays_goals, []), name
|
1182
|
+
|
1183
|
+
assert_equal [
|
1184
|
+
'Cannot unify: [Goal1.:a] with [Goal2.2] with [Goal3.3]',
|
1185
|
+
], g1.log
|
1186
|
+
|
1187
|
+
assert_equal [
|
1188
|
+
'Cannot unify because Goal2.2 != Goal3.3 (atomic != atomic)',
|
1189
|
+
'Cannot unify: Goal2.2 with Goal3.3',
|
1190
|
+
'Cannot unify: [Goal1.:a] with [Goal2.2] with [Goal3.3]',
|
1191
|
+
], g2.log
|
1192
|
+
|
1193
|
+
assert_equal [
|
1194
|
+
'Cannot unify because Goal2.2 != Goal3.3 (atomic != atomic)',
|
1195
|
+
'Cannot unify: Goal2.2 with Goal3.3',
|
1196
|
+
'Cannot unify: [Goal1.:a] with [Goal2.2] with [Goal3.3]',
|
1197
|
+
], g3.log
|
1198
|
+
end
|
1199
|
+
|
1200
|
+
it 'should raise an exception when an array has no associated goal' do # NOT DONE: need to expose the call to unify_arrays_with_no_tails
|
1201
|
+
|
1202
|
+
error = assert_raises Porolog::NoGoalError do
|
1203
|
+
variable1 = Variable.new :x, g1
|
1204
|
+
value = Value.new [7,11,13,23,29], g2
|
1205
|
+
|
1206
|
+
variable1.values << [7,11,13,23,29]
|
1207
|
+
variable1.values << [7,12,13,23,29]
|
1208
|
+
|
1209
|
+
variable1.instantiate value
|
1210
|
+
end
|
1211
|
+
|
1212
|
+
assert_equal 'Array [7, 11, 13, 23, 29] has no goal for unification', error.message
|
1213
|
+
end
|
1214
|
+
|
1215
|
+
end
|
1216
|
+
|
1217
|
+
describe '#unify_arrays_with_some_tails' do
|
1218
|
+
|
1219
|
+
let(:g1) { new_goal(:p, :x, :y) }
|
1220
|
+
let(:g2) { new_goal(:q, :a, :b) }
|
1221
|
+
let(:g3) { new_goal(:r, :s, :t) }
|
1222
|
+
let(:goals) { [g1, g2, g3] }
|
1223
|
+
|
1224
|
+
it 'should not unify a finite array with an array with a tail that has more finite elements' do
|
1225
|
+
arrays = [
|
1226
|
+
[nil, nil, nil, nil, UNKNOWN_TAIL],
|
1227
|
+
[1, 2, 3]
|
1228
|
+
]
|
1229
|
+
arrays_goals = goals[0...arrays.size]
|
1230
|
+
|
1231
|
+
assert_nil unify_arrays_with_some_tails(arrays, arrays_goals, []), name
|
1232
|
+
|
1233
|
+
expected_log = [
|
1234
|
+
'Cannot unify enough elements: [nil, nil, nil, nil, ...] with [Goal2.1, Goal2.2, Goal2.3]',
|
1235
|
+
]
|
1236
|
+
|
1237
|
+
assert_equal expected_log, g1.log
|
1238
|
+
assert_equal expected_log, g2.log
|
1239
|
+
end
|
1240
|
+
|
1241
|
+
it 'should unify a finite array with an array with a tail that has less finite elements' do
|
1242
|
+
arrays = [
|
1243
|
+
[nil, nil, UNKNOWN_TAIL],
|
1244
|
+
[1, 2, 3]
|
1245
|
+
]
|
1246
|
+
arrays_goals = goals[0...arrays.size]
|
1247
|
+
|
1248
|
+
assert_equal [[1,2,3],[]], unify_arrays_with_some_tails(arrays, arrays_goals, []), name
|
1249
|
+
end
|
1250
|
+
|
1251
|
+
it 'should merge values with an unknown tail' do
|
1252
|
+
arrays = [
|
1253
|
+
[1, 2, 3, UNKNOWN_TAIL],
|
1254
|
+
[nil, nil, nil, 4, nil],
|
1255
|
+
[nil, nil, nil, nil, 5],
|
1256
|
+
]
|
1257
|
+
arrays_goals = goals[0...arrays.size]
|
1258
|
+
|
1259
|
+
assert_equal [[1,2,3,4,5],[]], unify_arrays_with_some_tails(arrays, arrays_goals, []), name
|
1260
|
+
end
|
1261
|
+
|
1262
|
+
it 'should return nil when the finite arrays have different sizes' do
|
1263
|
+
arrays = [
|
1264
|
+
[nil, UNKNOWN_TAIL],
|
1265
|
+
[nil, nil, nil, nil],
|
1266
|
+
[nil, nil, nil, nil, nil, nil],
|
1267
|
+
]
|
1268
|
+
arrays_goals = goals[0...arrays.size]
|
1269
|
+
|
1270
|
+
assert_nil unify_arrays_with_some_tails(arrays, arrays_goals, []), name
|
1271
|
+
|
1272
|
+
expected_log = [
|
1273
|
+
'Cannot unify different sizes of arrays: [nil, ...] with [nil, nil, nil, nil] with [nil, nil, nil, nil, nil, nil]',
|
1274
|
+
]
|
1275
|
+
|
1276
|
+
assert_equal expected_log, g1.log
|
1277
|
+
assert_equal expected_log, g2.log
|
1278
|
+
assert_equal expected_log, g3.log
|
1279
|
+
end
|
1280
|
+
|
1281
|
+
it 'should return nil when the arrays have incompatible values' do
|
1282
|
+
arrays = [
|
1283
|
+
[1, 2, 3, UNKNOWN_TAIL],
|
1284
|
+
[nil, nil, nil, 4, nil],
|
1285
|
+
[5, nil, nil, nil, 5],
|
1286
|
+
]
|
1287
|
+
arrays_goals = goals[0...arrays.size]
|
1288
|
+
|
1289
|
+
assert_nil unify_arrays_with_some_tails(arrays, arrays_goals, []), name
|
1290
|
+
|
1291
|
+
expected_log = [
|
1292
|
+
'Cannot unify enough elements: Goal1.1 with Goal3.5',
|
1293
|
+
]
|
1294
|
+
|
1295
|
+
assert_equal expected_log, g1.log
|
1296
|
+
assert_equal expected_log, g2.log
|
1297
|
+
assert_equal expected_log, g3.log
|
1298
|
+
end
|
1299
|
+
|
1300
|
+
it 'should return necessary unification to unify variables' do
|
1301
|
+
arrays = [
|
1302
|
+
[1, 2, nil, UNKNOWN_TAIL],
|
1303
|
+
[:j, :n, :n, 4, nil],
|
1304
|
+
[:x, nil, :m, :y, :z],
|
1305
|
+
]
|
1306
|
+
arrays_goals = goals[0...arrays.size]
|
1307
|
+
|
1308
|
+
merged, unifications = unify_arrays_with_some_tails(arrays, arrays_goals, [])
|
1309
|
+
|
1310
|
+
expected_merged = [1, 2, nil, 4, nil]
|
1311
|
+
expected_unifications = [
|
1312
|
+
[g2.variable(:j), g1.value(1), g2, g1],
|
1313
|
+
[g3.variable(:x), g1.value(1), g3, g1],
|
1314
|
+
[g2.variable(:j), g3.variable(:x), g2, g3],
|
1315
|
+
[g2.variable(:n), g1.value(2), g2, g1],
|
1316
|
+
[g2.variable(:n), g3.variable(:m), g2, g3],
|
1317
|
+
[g3.variable(:y), g2.value(4), g3, g2],
|
1318
|
+
]
|
1319
|
+
|
1320
|
+
assert_equal [expected_merged, expected_unifications], [merged, unifications], name
|
1321
|
+
end
|
1322
|
+
|
1323
|
+
it 'should handle a range of cases' do
|
1324
|
+
[
|
1325
|
+
[[[], [1,UNKNOWN_TAIL] ], nil, ['Cannot unify enough elements: [] with [Goal2.1, ...]']],
|
1326
|
+
[[[]/:t, [1] ], [[1], [[g1.variable(:t), [1], g1, g2]]]],
|
1327
|
+
[[[], [1,2]/:s ], nil, ['Cannot unify enough elements: [] with [Goal2.1, Goal2.2, *Goal2.:s]']],
|
1328
|
+
[[[]/:t, [1,2] ], [[1,2], [[g1.variable(:t), [1,2], g1, g2]]]],
|
1329
|
+
[[[1,2,3], [1,UNKNOWN_TAIL] ], [[1,2,3],[]]],
|
1330
|
+
[[[1,2,3,UNKNOWN_TAIL], [1] ], nil, ['Cannot unify enough elements: [Goal1.1, Goal1.2, Goal1.3, ...] with [Goal2.1]']],
|
1331
|
+
[[[1], [1,2,3,UNKNOWN_TAIL] ], nil, ['Cannot unify enough elements: [Goal1.1] with [Goal2.1, Goal2.2, Goal2.3, ...]']],
|
1332
|
+
[[[1]/:z, [1,2,3] ], [[1,2,3], [[g1.variable(:z), [2, 3], g1, g2]]]],
|
1333
|
+
[[[:x,:y,:z], [1,2,3,4,UNKNOWN_TAIL]], nil, ['Cannot unify enough elements: [Goal1.:x, Goal1.:y, Goal1.:z] with [Goal2.1, Goal2.2, Goal2.3, Goal2.4, ...]']],
|
1334
|
+
[[[:x,:y,:z,UNKNOWN_TAIL], [1,2,3,4] ], [
|
1335
|
+
[1,2,3,4],
|
1336
|
+
[
|
1337
|
+
[g1.variable(:x), g2.value(1), g1, g2],
|
1338
|
+
[g1.variable(:y), g2.value(2), g1, g2],
|
1339
|
+
[g1.variable(:z), g2.value(3), g1, g2]
|
1340
|
+
]
|
1341
|
+
]],
|
1342
|
+
].each do |arrays, expected, expected_log|
|
1343
|
+
arrays_goals = goals[0...arrays.size]
|
1344
|
+
|
1345
|
+
result = unify_arrays_with_some_tails(arrays, arrays_goals, [])
|
1346
|
+
|
1347
|
+
if expected.nil?
|
1348
|
+
assert_nil result
|
1349
|
+
|
1350
|
+
arrays_goals.uniq.each do |goal|
|
1351
|
+
assert_equal expected_log, goal.log
|
1352
|
+
goal.log[0..-1] = []
|
1353
|
+
end
|
1354
|
+
else
|
1355
|
+
assert_equal expected, result
|
1356
|
+
end
|
1357
|
+
end
|
1358
|
+
end
|
1359
|
+
|
1360
|
+
it 'should raise a no goal error when no goals are supplied and the arrays have no embedded goals' do
|
1361
|
+
arrays = [
|
1362
|
+
[nil, nil, nil, nil, UNKNOWN_TAIL],
|
1363
|
+
[1, 2, 3]
|
1364
|
+
]
|
1365
|
+
arrays_goals = [nil] * arrays.size
|
1366
|
+
|
1367
|
+
error = assert_raises Porolog::NoGoalError do
|
1368
|
+
unify_arrays_with_some_tails(arrays, arrays_goals, [])
|
1369
|
+
end
|
1370
|
+
|
1371
|
+
assert_equal '[nil, nil, nil, nil, ...] has no associated goal! Cannot variablise!', error.message
|
1372
|
+
end
|
1373
|
+
|
1374
|
+
it 'should derive goals from embedded goals when the goals are not supplied' do
|
1375
|
+
arrays_goals = [g1, nil]
|
1376
|
+
arrays = [
|
1377
|
+
[nil, nil, nil, nil, UNKNOWN_TAIL],
|
1378
|
+
[1, 2, g2[3], 4]
|
1379
|
+
]
|
1380
|
+
|
1381
|
+
refute arrays.all?{|array| has_tail?(array, false) }, "not all arrays should have a tail"
|
1382
|
+
refute arrays.all?{|array| !has_tail?(array, false) }, "not all arrays should not have a tail"
|
1383
|
+
|
1384
|
+
merged, unifications = unify_arrays_with_some_tails(arrays, arrays_goals, [])
|
1385
|
+
|
1386
|
+
expected_merged = [1,2,3,4]
|
1387
|
+
expected_unifications = [
|
1388
|
+
]
|
1389
|
+
|
1390
|
+
assert_equal expected_merged, merged
|
1391
|
+
assert_equal expected_unifications, unifications
|
1392
|
+
end
|
1393
|
+
|
1394
|
+
it 'should extract embedded variables and values in an array in a value' do
|
1395
|
+
arrays = [
|
1396
|
+
g1.value([nil, :b, nil, nil, 5]),
|
1397
|
+
[1, 2, g2[3], 4]/:t
|
1398
|
+
]
|
1399
|
+
arrays_goals = goals[0...arrays.size]
|
1400
|
+
|
1401
|
+
refute arrays.all?{|array| has_tail?(array, false) }, "not all arrays should have a tail"
|
1402
|
+
refute arrays.all?{|array| !has_tail?(array, false) }, "not all arrays should not have a tail"
|
1403
|
+
|
1404
|
+
merged, unifications = unify_arrays_with_some_tails(arrays, arrays_goals, [])
|
1405
|
+
|
1406
|
+
expected_merged = [1,2,3,4,5]
|
1407
|
+
expected_unifications = [
|
1408
|
+
[g1[:b], g2[2], g1, g2],
|
1409
|
+
[g2[:t], [5], g2, g1],
|
1410
|
+
]
|
1411
|
+
|
1412
|
+
assert_equal expected_merged, merged
|
1413
|
+
assert_equal expected_unifications, unifications
|
1414
|
+
end
|
1415
|
+
|
1416
|
+
it 'should unify multiple atomics and tails' do
|
1417
|
+
arrays = [
|
1418
|
+
g1.value([nil, :b, nil, nil, 5, 6, 7]),
|
1419
|
+
[1, 2, g2[3], 4]/:t,
|
1420
|
+
[1, 2, g3[3], 4]/:t,
|
1421
|
+
]
|
1422
|
+
arrays_goals = goals[0...arrays.size]
|
1423
|
+
|
1424
|
+
refute arrays.all?{|array| has_tail?(array, false) }, "not all arrays should have a tail"
|
1425
|
+
refute arrays.all?{|array| !has_tail?(array, false) }, "not all arrays should not have a tail"
|
1426
|
+
|
1427
|
+
merged, unifications = unify_arrays_with_some_tails(arrays, arrays_goals, [])
|
1428
|
+
|
1429
|
+
expected_merged = [1,2,3,4,5,6,7]
|
1430
|
+
expected_unifications = [
|
1431
|
+
[g1[:b], g2[2], g1, g2],
|
1432
|
+
[g1[:b], g3[2], g1, g3],
|
1433
|
+
[g2[:t], [5,6,7], g2, g1],
|
1434
|
+
[g3[:t], [5,6,7], g3, g1],
|
1435
|
+
]
|
1436
|
+
|
1437
|
+
assert_equal expected_merged, merged
|
1438
|
+
assert_equal expected_unifications, unifications
|
1439
|
+
end
|
1440
|
+
|
1441
|
+
it 'should not unify incompatible atomics' do
|
1442
|
+
arrays = [
|
1443
|
+
g1.value([nil, :b, nil, nil, 5]),
|
1444
|
+
[1, 2, g2[3], 4]/:t,
|
1445
|
+
[1, 3, g3[3], 4]/:t,
|
1446
|
+
]
|
1447
|
+
arrays_goals = goals[0...arrays.size]
|
1448
|
+
|
1449
|
+
refute arrays.all?{|array| has_tail?(array, false) }, "not all arrays should have a tail"
|
1450
|
+
refute arrays.all?{|array| !has_tail?(array, false) }, "not all arrays should not have a tail"
|
1451
|
+
|
1452
|
+
assert_nil unify_arrays_with_some_tails(arrays, arrays_goals, []), name
|
1453
|
+
|
1454
|
+
assert_equal [
|
1455
|
+
'Cannot unify non-variables: 2 with 3'
|
1456
|
+
], g1.log
|
1457
|
+
|
1458
|
+
assert_equal [
|
1459
|
+
'Cannot unify non-variables: 2 with 3'
|
1460
|
+
], g2.log
|
1461
|
+
|
1462
|
+
assert_equal [
|
1463
|
+
'Cannot unify non-variables: 2 with 3'
|
1464
|
+
], g3.log
|
1465
|
+
end
|
1466
|
+
|
1467
|
+
end
|
1468
|
+
|
1469
|
+
describe '#unify_arrays_with_all_tails' do # NOT DONE: coverage
|
1470
|
+
|
1471
|
+
let(:g1) { new_goal(:p, :x, :y) }
|
1472
|
+
let(:g2) { new_goal(:q, :a, :b) }
|
1473
|
+
let(:g3) { new_goal(:r, :s, :t) }
|
1474
|
+
let(:goals) { [g1, g2, g3] }
|
1475
|
+
|
1476
|
+
let(:array_with_tail_1) { [1, 2, Tail.new(:h)] }
|
1477
|
+
let(:array_with_tail_2) { [:h, :b]/:t }
|
1478
|
+
let(:array_with_tail_3) { [:x, :y, UNKNOWN_TAIL] }
|
1479
|
+
let(:head_and_tail_1) { [1, Tail.new([2,3])] }
|
1480
|
+
let(:head_and_tail_2) { [:h]/:t }
|
1481
|
+
let(:head_and_tail_3) { [:x, UNKNOWN_TAIL] }
|
1482
|
+
|
1483
|
+
it 'should call unify_tail_with_tail when no array is headtail' do
|
1484
|
+
expects(:unify_tail_with_tail).times(1)
|
1485
|
+
expects(:unify_headtail_with_tail).times(0)
|
1486
|
+
expects(:unify_headtail_with_headtail).times(0)
|
1487
|
+
|
1488
|
+
arrays = [
|
1489
|
+
array_with_tail_1,
|
1490
|
+
array_with_tail_2,
|
1491
|
+
array_with_tail_3,
|
1492
|
+
]
|
1493
|
+
arrays_goals = goals[0...arrays.size]
|
1494
|
+
|
1495
|
+
unify_arrays_with_all_tails(arrays, arrays_goals, [])
|
1496
|
+
end
|
1497
|
+
|
1498
|
+
it 'should call unify_headtail_with_tail when all arrays but one are headtail' do
|
1499
|
+
expects(:unify_tail_with_tail).times(0)
|
1500
|
+
expects(:unify_headtail_with_tail).times(1)
|
1501
|
+
expects(:unify_headtail_with_headtail).times(0)
|
1502
|
+
|
1503
|
+
arrays = [
|
1504
|
+
array_with_tail_1,
|
1505
|
+
head_and_tail_2,
|
1506
|
+
head_and_tail_3,
|
1507
|
+
]
|
1508
|
+
arrays_goals = goals[0...arrays.size]
|
1509
|
+
|
1510
|
+
unify_arrays_with_all_tails(arrays, arrays_goals, [])
|
1511
|
+
end
|
1512
|
+
|
1513
|
+
it 'should include unifications of variables in a tail' do
|
1514
|
+
arrays = [
|
1515
|
+
[nil, nil, nil]/:list,
|
1516
|
+
[1, 2, 3, nil, :y, UNKNOWN_TAIL],
|
1517
|
+
[nil, :x, nil, 4, Tail.new([nil,6])],
|
1518
|
+
]
|
1519
|
+
arrays_goals = goals[0...arrays.size]
|
1520
|
+
|
1521
|
+
g1.instantiate :list, [4,5,:z]
|
1522
|
+
|
1523
|
+
merged, unifications = unify_arrays_with_all_tails(arrays, arrays_goals, [])
|
1524
|
+
|
1525
|
+
expected_merged = [1,2,3,4,5,6]
|
1526
|
+
expected_unifications = [
|
1527
|
+
[g3[:x], g2[2], g3, g2],
|
1528
|
+
[g2[:y], g1[5], g2, g1],
|
1529
|
+
[g1[:z], g3[6], g1, g3],
|
1530
|
+
]
|
1531
|
+
|
1532
|
+
assert_equal expected_merged, merged
|
1533
|
+
assert_equal expected_unifications, unifications
|
1534
|
+
end
|
1535
|
+
|
1536
|
+
it 'should not unify arrays where one embedded variable cannot be unified' do
|
1537
|
+
g1.instantiate(:a, [g1.value(1), g1.value(2), g1.value(3), UNKNOWN_TAIL])
|
1538
|
+
g2.instantiate(:a, :b)
|
1539
|
+
g3.instantiate(:a, :b)
|
1540
|
+
|
1541
|
+
arrays = [
|
1542
|
+
:a,
|
1543
|
+
[:a,Tail.new([1])],
|
1544
|
+
[:a, UNKNOWN_TAIL],
|
1545
|
+
]
|
1546
|
+
arrays_goals = goals[0...arrays.size]
|
1547
|
+
|
1548
|
+
assert_nil unify_arrays_with_all_tails(arrays, arrays_goals, []), name
|
1549
|
+
|
1550
|
+
assert_equal [
|
1551
|
+
'Cannot unify enough elements: Goal1.[Goal1.1, Goal1.2, Goal1.3, ...] with [Goal2.:a, Goal2.1]',
|
1552
|
+
'Cannot unify because Goal1.[Goal1.1, Goal1.2, Goal1.3, ...] != [:a, 1] (variable/array != array)',
|
1553
|
+
'Cannot unify embedded arrays: :a with [:a, 1]',
|
1554
|
+
], g1.log
|
1555
|
+
|
1556
|
+
assert_equal [
|
1557
|
+
'Cannot unify enough elements: Goal1.[Goal1.1, Goal1.2, Goal1.3, ...] with [Goal2.:a, Goal2.1]',
|
1558
|
+
'Cannot unify because Goal1.[Goal1.1, Goal1.2, Goal1.3, ...] != [:a, 1] (variable/array != array)',
|
1559
|
+
'Cannot unify embedded arrays: :a with [:a, 1]',
|
1560
|
+
], g2.log
|
1561
|
+
|
1562
|
+
assert_equal [
|
1563
|
+
'Cannot unify embedded arrays: :a with [:a, 1]',
|
1564
|
+
], g3.log
|
1565
|
+
end
|
1566
|
+
|
1567
|
+
it 'should unify arrays where all embedded variables can be unified' do
|
1568
|
+
arrays = [
|
1569
|
+
[g1.variable(:a), g1.value(2), g1.variable(:c), g1.value(4)],
|
1570
|
+
[g2.value(1), g1.variable(:b), g2.value(3), UNKNOWN_TAIL],
|
1571
|
+
[:a, :b, Tail.new([3,:d])],
|
1572
|
+
]
|
1573
|
+
arrays_goals = goals[0...arrays.size]
|
1574
|
+
|
1575
|
+
assert arrays.map(&:headtail?).none?
|
1576
|
+
|
1577
|
+
expected_merged = [1,2,3,4]
|
1578
|
+
expected_unifications = [
|
1579
|
+
[g1.variable(:a), g2.value(1), g1, g2],
|
1580
|
+
[g1.variable(:a), g3.variable(:a), g1, g3],
|
1581
|
+
[g3.variable(:a), g2.value(1), g3, g2],
|
1582
|
+
[g1.variable(:b), g1.value(2), g1, g1],
|
1583
|
+
[g3.variable(:b), g1.value(2), g3, g1],
|
1584
|
+
[g1.variable(:b), g3.variable(:b), g1, g3],
|
1585
|
+
[g1.variable(:c), g2.value(3), g1, g2],
|
1586
|
+
[g1.variable(:c), g3.value(3), g1, g3],
|
1587
|
+
[g3.variable(:d), g1.value(4), g3, g1]
|
1588
|
+
]
|
1589
|
+
merged, unifications = unify_arrays_with_all_tails(arrays, arrays_goals, [])
|
1590
|
+
|
1591
|
+
assert_equal [], g1.log
|
1592
|
+
assert_equal [], g2.log
|
1593
|
+
assert_equal [], g3.log
|
1594
|
+
|
1595
|
+
assert_equal expected_merged, merged
|
1596
|
+
assert_equal expected_unifications, unifications
|
1597
|
+
end
|
1598
|
+
|
1599
|
+
it 'should unify embedded arrays where all embedded variables can be unified' do
|
1600
|
+
arrays = [
|
1601
|
+
:e,
|
1602
|
+
[[1],[2],[3],[4]],
|
1603
|
+
[[1],[2],[3],[4]],
|
1604
|
+
]
|
1605
|
+
arrays_goals = goals[0...arrays.size]
|
1606
|
+
|
1607
|
+
assert arrays.map(&:headtail?).none?
|
1608
|
+
|
1609
|
+
expected_merged = [[1],[2],[3],[4]]
|
1610
|
+
expected_unifications = [
|
1611
|
+
[:e, [[1], [2], [3], [4]], g1, g2]
|
1612
|
+
]
|
1613
|
+
merged, unifications = unify_arrays_with_all_tails(arrays, arrays_goals, [])
|
1614
|
+
|
1615
|
+
assert_equal [], g1.log
|
1616
|
+
assert_equal [], g2.log
|
1617
|
+
assert_equal [], g3.log
|
1618
|
+
|
1619
|
+
assert_equal expected_merged, merged
|
1620
|
+
assert_equal expected_unifications, unifications
|
1621
|
+
end
|
1622
|
+
|
1623
|
+
end
|
1624
|
+
|
1625
|
+
describe '#unify_tail_with_tail' do
|
1626
|
+
|
1627
|
+
let(:g1) { new_goal(:p, :x, :y) }
|
1628
|
+
let(:g2) { new_goal(:q, :a, :b) }
|
1629
|
+
let(:g3) { new_goal(:r, :s, :t) }
|
1630
|
+
let(:g4) { new_goal(:j, :k, :l) }
|
1631
|
+
let(:goals) { [g1, g2, g3, g4] }
|
1632
|
+
|
1633
|
+
it 'should reject a non-headtail array' do
|
1634
|
+
arrays = [
|
1635
|
+
[1,Tail.new([2,3])],
|
1636
|
+
[4],
|
1637
|
+
[7,UNKNOWN_TAIL],
|
1638
|
+
]
|
1639
|
+
arrays_goals = goals[0...arrays.size]
|
1640
|
+
|
1641
|
+
refute arrays.all?(&:headtail?)
|
1642
|
+
|
1643
|
+
assert_nil unify_tail_with_tail(arrays, arrays_goals, [])
|
1644
|
+
|
1645
|
+
msg = 'Wrong method called to unify [[1, *[2, 3]], [4], [7, ...]]'
|
1646
|
+
|
1647
|
+
assert_equal [msg], g1.log
|
1648
|
+
assert_equal [msg], g2.log
|
1649
|
+
assert_equal [msg], g3.log
|
1650
|
+
end
|
1651
|
+
|
1652
|
+
it 'should process more than two arrays that are a non-headtail' do
|
1653
|
+
arrays = [
|
1654
|
+
[1, 2, Tail.new([3,4])],
|
1655
|
+
[:a, :b]/:c,
|
1656
|
+
[:d, :e, UNKNOWN_TAIL],
|
1657
|
+
]
|
1658
|
+
arrays_goals = goals[0...arrays.size]
|
1659
|
+
|
1660
|
+
assert arrays.all?{|array| has_tail?(array, false) }
|
1661
|
+
assert arrays.map(&:headtail?).map(&:!).all?
|
1662
|
+
|
1663
|
+
merged, unifications = unify_tail_with_tail(arrays, arrays_goals, [])
|
1664
|
+
|
1665
|
+
expected_merged = [1,2,3,4]
|
1666
|
+
|
1667
|
+
expected_unifications = [
|
1668
|
+
[g2.variable(:a), g1.value(1), g2, g1],
|
1669
|
+
[g3.variable(:d), g1.value(1), g3, g1],
|
1670
|
+
[g2.variable(:a), g3.variable(:d), g2, g3],
|
1671
|
+
[g2.variable(:b), g1.value(2), g2, g1],
|
1672
|
+
[g3.variable(:e), g1.value(2), g3, g1],
|
1673
|
+
[g2.variable(:b), g3.variable(:e), g2, g3],
|
1674
|
+
[g2.variable(:c), g1.variablise([3,4]), g2, g1],
|
1675
|
+
]
|
1676
|
+
|
1677
|
+
assert_equal expected_merged, merged
|
1678
|
+
assert_equal expected_unifications, unifications
|
1679
|
+
end
|
1680
|
+
|
1681
|
+
it 'should unify arrays of different lengths' do
|
1682
|
+
arrays = [
|
1683
|
+
[1, 2, UNKNOWN_TAIL],
|
1684
|
+
[nil, nil, 3, 4, UNKNOWN_TAIL],
|
1685
|
+
[nil, nil, nil, nil, 5, 6, UNKNOWN_TAIL],
|
1686
|
+
]
|
1687
|
+
arrays_goals = goals[0...arrays.size]
|
1688
|
+
|
1689
|
+
assert arrays.all?{|array| has_tail?(array) }
|
1690
|
+
assert arrays.map(&:headtail?).map(&:!).all?
|
1691
|
+
|
1692
|
+
merged, unifications = unify_tail_with_tail(arrays, arrays_goals, [])
|
1693
|
+
|
1694
|
+
expected_merged = [
|
1695
|
+
g1.value(1),
|
1696
|
+
g1.value(2),
|
1697
|
+
g2.value(3),
|
1698
|
+
g2.value(4),
|
1699
|
+
g3.value(5),
|
1700
|
+
g3.value(6),
|
1701
|
+
UNKNOWN_TAIL,
|
1702
|
+
]
|
1703
|
+
|
1704
|
+
expected_unifications = [
|
1705
|
+
]
|
1706
|
+
|
1707
|
+
assert_equal expected_merged, merged
|
1708
|
+
assert_equal expected_unifications, unifications
|
1709
|
+
end
|
1710
|
+
|
1711
|
+
it 'should unify all combinations of tails and tails' do
|
1712
|
+
arrays = [
|
1713
|
+
[:a,:b]/:c,
|
1714
|
+
[:d,:e]/:f,
|
1715
|
+
[:g,:h]/:i,
|
1716
|
+
[:j,:k]/:l,
|
1717
|
+
]
|
1718
|
+
arrays_goals = goals[0...arrays.size]
|
1719
|
+
|
1720
|
+
assert arrays.all?{|array| has_tail?(array) }
|
1721
|
+
assert arrays.map(&:headtail?).map(&:!).all?
|
1722
|
+
|
1723
|
+
merged, unifications = unify_tail_with_tail(arrays, arrays_goals, [])
|
1724
|
+
|
1725
|
+
expected_merged = [nil, nil, UNKNOWN_TAIL]
|
1726
|
+
|
1727
|
+
expected_unifications = [
|
1728
|
+
[g1[:a], g2[:d], g1, g2],
|
1729
|
+
[g1[:a], g3[:g], g1, g3],
|
1730
|
+
[g1[:a], g4[:j], g1, g4],
|
1731
|
+
[g2[:d], g3[:g], g2, g3],
|
1732
|
+
[g2[:d], g4[:j], g2, g4],
|
1733
|
+
[g3[:g], g4[:j], g3, g4],
|
1734
|
+
[g1[:b], g2[:e], g1, g2],
|
1735
|
+
[g1[:b], g3[:h], g1, g3],
|
1736
|
+
[g1[:b], g4[:k], g1, g4],
|
1737
|
+
[g2[:e], g3[:h], g2, g3],
|
1738
|
+
[g2[:e], g4[:k], g2, g4],
|
1739
|
+
[g3[:h], g4[:k], g3, g4],
|
1740
|
+
[g1[:c], g2[:f], g1, g2],
|
1741
|
+
[g1[:c], g3[:i], g1, g3],
|
1742
|
+
[g1[:c], g4[:l], g1, g4],
|
1743
|
+
[g2[:f], g3[:i], g2, g3],
|
1744
|
+
[g2[:f], g4[:l], g2, g4],
|
1745
|
+
[g3[:i], g4[:l], g3, g4],
|
1746
|
+
]
|
1747
|
+
|
1748
|
+
assert_equal expected_merged, merged
|
1749
|
+
assert_equal expected_unifications, unifications
|
1750
|
+
end
|
1751
|
+
|
1752
|
+
it 'should not unify ununifiable arrays' do
|
1753
|
+
arrays = [
|
1754
|
+
[1,2,3,4,UNKNOWN_TAIL],
|
1755
|
+
[1,4,3,2,UNKNOWN_TAIL],
|
1756
|
+
]
|
1757
|
+
arrays_goals = goals[0...arrays.size]
|
1758
|
+
|
1759
|
+
assert arrays.all?{|array| has_tail?(array) }
|
1760
|
+
assert arrays.map(&:headtail?).map(&:!).all?
|
1761
|
+
|
1762
|
+
assert_nil unify_tail_with_tail(arrays, arrays_goals, []), name
|
1763
|
+
|
1764
|
+
expected_log = [
|
1765
|
+
'Cannot unify incompatible values: 2 with 4',
|
1766
|
+
'Cannot unify Goal1.2 with Goal2.4',
|
1767
|
+
]
|
1768
|
+
|
1769
|
+
arrays_goals.each do |goal|
|
1770
|
+
assert_equal expected_log, goal.log
|
1771
|
+
end
|
1772
|
+
end
|
1773
|
+
|
1774
|
+
end
|
1775
|
+
|
1776
|
+
describe '#unify_headtail_with_tail' do
|
1777
|
+
|
1778
|
+
let(:g1) { new_goal(:p, :x, :y) }
|
1779
|
+
let(:g2) { new_goal(:q, :a, :b) }
|
1780
|
+
let(:g3) { new_goal(:r, :s, :t) }
|
1781
|
+
let(:g4) { new_goal(:j, :k, :l) }
|
1782
|
+
let(:goals) { [g1, g2, g3, g4] }
|
1783
|
+
|
1784
|
+
it 'should reject a non-tail array' do
|
1785
|
+
arrays = [
|
1786
|
+
[1,Tail.new([2,3])],
|
1787
|
+
[4],
|
1788
|
+
[1,2,3,7,UNKNOWN_TAIL],
|
1789
|
+
]
|
1790
|
+
arrays_goals = goals[0...arrays.size]
|
1791
|
+
|
1792
|
+
refute arrays.all?{|array| has_tail?(array) }
|
1793
|
+
|
1794
|
+
assert_nil unify_headtail_with_tail(arrays, arrays_goals, [])
|
1795
|
+
|
1796
|
+
msg = 'Wrong method called to unify [[1, *[2, 3]], [4], [1, 2, 3, 7, ...]]'
|
1797
|
+
|
1798
|
+
assert_equal [msg], g1.log
|
1799
|
+
assert_equal [msg], g2.log
|
1800
|
+
assert_equal [msg], g3.log
|
1801
|
+
end
|
1802
|
+
|
1803
|
+
it 'should unify more than two arrays that have a tail' do
|
1804
|
+
arrays = [
|
1805
|
+
[1, Tail.new([2,3])],
|
1806
|
+
[:a, :b]/:f,
|
1807
|
+
[:c, UNKNOWN_TAIL],
|
1808
|
+
[:d, :e, UNKNOWN_TAIL]
|
1809
|
+
]
|
1810
|
+
arrays_goals = goals[0...arrays.size]
|
1811
|
+
|
1812
|
+
assert arrays.all?{|array| has_tail?(array, false) }
|
1813
|
+
|
1814
|
+
merged, unifications = unify_headtail_with_tail(arrays, arrays_goals, [])
|
1815
|
+
|
1816
|
+
expected_merged = [1,2,3]
|
1817
|
+
|
1818
|
+
expected_unifications = [
|
1819
|
+
[g3[:c], g1[1], g3, g1],
|
1820
|
+
[g2[:a], g4[:d], g2, g4],
|
1821
|
+
[g2[:b], g4[:e], g2, g4],
|
1822
|
+
[g2[:a], g1[1], g2, g1],
|
1823
|
+
[g2[:b], g1[2], g2, g1],
|
1824
|
+
[g2[:f], [3], g2, g1],
|
1825
|
+
[g4[:d], g1[1], g4, g1],
|
1826
|
+
[g4[:e], g1[2], g4, g1],
|
1827
|
+
[g3[:c], g2[:a], g3, g2],
|
1828
|
+
[g3[:c], g4[:d], g3, g4]
|
1829
|
+
]
|
1830
|
+
|
1831
|
+
assert_equal expected_merged, merged
|
1832
|
+
assert_equal expected_unifications, unifications
|
1833
|
+
end
|
1834
|
+
|
1835
|
+
it 'should unify unifiable arrays with different length tails' do
|
1836
|
+
arrays = [
|
1837
|
+
[1, UNKNOWN_TAIL],
|
1838
|
+
[:a, :b, :c, :d]/:f,
|
1839
|
+
[:c, UNKNOWN_TAIL],
|
1840
|
+
[:d, 2, UNKNOWN_TAIL]
|
1841
|
+
]
|
1842
|
+
arrays_goals = goals[0...arrays.size]
|
1843
|
+
|
1844
|
+
assert arrays.all?{|array| has_tail?(array, false) }
|
1845
|
+
|
1846
|
+
merged, unifications = unify_headtail_with_tail(arrays, arrays_goals, [])
|
1847
|
+
|
1848
|
+
expected_merged = [1,2,nil,nil,UNKNOWN_TAIL]
|
1849
|
+
|
1850
|
+
expected_unifications = [
|
1851
|
+
[g3[:c], g1[1], g3, g1],
|
1852
|
+
[g2[:a], g4[:d], g2, g4],
|
1853
|
+
[g2[:b], g4[2], g2, g4],
|
1854
|
+
[g2[:a], g1[1], g2, g1],
|
1855
|
+
[g4[:d], g1[1], g4, g1],
|
1856
|
+
[g3[:c], g2[:a], g3, g2],
|
1857
|
+
[g3[:c], g4[:d], g3, g4],
|
1858
|
+
]
|
1859
|
+
|
1860
|
+
assert_equal expected_merged, merged
|
1861
|
+
assert_equal expected_unifications, unifications
|
1862
|
+
end
|
1863
|
+
|
1864
|
+
it 'should not unify unifiable heads across a headtail and an array with a tail' do
|
1865
|
+
g1.instantiate :h, 1
|
1866
|
+
g2.instantiate :h, 2
|
1867
|
+
arrays = [
|
1868
|
+
[:h]/:t,
|
1869
|
+
[:h,:b]/:t,
|
1870
|
+
[:h]/:t,
|
1871
|
+
[:h]/:t,
|
1872
|
+
]
|
1873
|
+
arrays_goals = goals[0...arrays.size]
|
1874
|
+
|
1875
|
+
assert arrays.all?{|array| has_tail?(array, false) }, 'all arrays should have a tail'
|
1876
|
+
refute arrays.map(&:headtail?).all?, 'not all arrays should be a headtail array'
|
1877
|
+
refute arrays.map(&:headtail?).map(&:!).all?, 'not all arrays should be an array with a tail'
|
1878
|
+
|
1879
|
+
assert_nil unify_headtail_with_tail(arrays, arrays_goals, []), name
|
1880
|
+
|
1881
|
+
assert_equal [
|
1882
|
+
'Cannot unify because Goal1.1 != Goal2.2 (variable != variable)',
|
1883
|
+
'Cannot unify heads: Goal1.:h with Goal2.:h',
|
1884
|
+
], g1.log
|
1885
|
+
assert_equal [
|
1886
|
+
'Cannot unify because Goal1.1 != Goal2.2 (variable != variable)',
|
1887
|
+
'Cannot unify heads: Goal1.:h with Goal2.:h',
|
1888
|
+
], g2.log
|
1889
|
+
assert_equal [
|
1890
|
+
], g3.log
|
1891
|
+
assert_equal [
|
1892
|
+
], g4.log
|
1893
|
+
end
|
1894
|
+
|
1895
|
+
it 'should not unify tails with different values' do
|
1896
|
+
g1.instantiate :t, [2,3]
|
1897
|
+
g2.instantiate :t, [2,4]
|
1898
|
+
g3.instantiate :t, 4
|
1899
|
+
arrays = [
|
1900
|
+
[:h]/:t,
|
1901
|
+
[:h]/:t,
|
1902
|
+
[:h,:b]/:t,
|
1903
|
+
[:h]/:t,
|
1904
|
+
]
|
1905
|
+
arrays_goals = goals[0...arrays.size]
|
1906
|
+
|
1907
|
+
assert arrays.all?{|array| has_tail?(array, false) }, 'all arrays should have a tail'
|
1908
|
+
refute arrays.map(&:headtail?).all?, 'not all arrays should be a headtail array'
|
1909
|
+
refute arrays.map(&:headtail?).map(&:!).all?, 'not all arrays should be an array with a tail'
|
1910
|
+
|
1911
|
+
assert_nil unify_headtail_with_tail(arrays, arrays_goals, []), name
|
1912
|
+
|
1913
|
+
assert_equal [
|
1914
|
+
'Cannot unify because Goal1.[2, 3] != Goal2.[2, 4] (variable != variable)',
|
1915
|
+
'Cannot unify headtail tails: Goal1.:t with Goal2.:t',
|
1916
|
+
'Could not unify headtail arrays: [Goal1.:h, Goal1.2, Goal1.3] with [Goal2.:h, Goal2.2, Goal2.4] with [Goal4.:h, *Goal4.:t]',
|
1917
|
+
], g1.log
|
1918
|
+
assert_equal [
|
1919
|
+
'Cannot unify because Goal1.[2, 3] != Goal2.[2, 4] (variable != variable)',
|
1920
|
+
'Cannot unify headtail tails: Goal1.:t with Goal2.:t',
|
1921
|
+
'Could not unify headtail arrays: [Goal1.:h, Goal1.2, Goal1.3] with [Goal2.:h, Goal2.2, Goal2.4] with [Goal4.:h, *Goal4.:t]',
|
1922
|
+
], g2.log
|
1923
|
+
assert_equal [
|
1924
|
+
], g3.log
|
1925
|
+
assert_equal [
|
1926
|
+
'Could not unify headtail arrays: [Goal1.:h, Goal1.2, Goal1.3] with [Goal2.:h, Goal2.2, Goal2.4] with [Goal4.:h, *Goal4.:t]',
|
1927
|
+
], g4.log
|
1928
|
+
end
|
1929
|
+
|
1930
|
+
it 'should not unify variable length arrays that have been instantiatd to different lengths' do
|
1931
|
+
g1.instantiate :t, [2,3]
|
1932
|
+
g2.instantiate :t, 3
|
1933
|
+
g3.instantiate :t, [2,3,4]
|
1934
|
+
arrays = [
|
1935
|
+
[:h]/:t,
|
1936
|
+
[:h,:b]/:t,
|
1937
|
+
[:h]/:t,
|
1938
|
+
[:h]/:t,
|
1939
|
+
]
|
1940
|
+
arrays_goals = goals[0...arrays.size]
|
1941
|
+
|
1942
|
+
assert arrays.all?{|array| has_tail?(array, false) }, 'all arrays should have a tail'
|
1943
|
+
refute arrays.map(&:headtail?).all?, 'not all arrays should be a headtail array'
|
1944
|
+
refute arrays.map(&:headtail?).map(&:!).all?, 'not all arrays should be an array with a tail'
|
1945
|
+
|
1946
|
+
assert_nil unify_headtail_with_tail(arrays, arrays_goals, []), name
|
1947
|
+
|
1948
|
+
assert_equal [
|
1949
|
+
], g1.log
|
1950
|
+
assert_equal [
|
1951
|
+
], g2.log
|
1952
|
+
assert_equal [
|
1953
|
+
'Cannot unify [Goal3.:h, Goal3.2, Goal3.3, Goal3.4] because it has a different length from 3'
|
1954
|
+
], g3.log
|
1955
|
+
assert_equal [
|
1956
|
+
], g4.log
|
1957
|
+
end
|
1958
|
+
|
1959
|
+
it 'should not unify incompatible tails' do
|
1960
|
+
g1.instantiate :t, [2,3]
|
1961
|
+
g2.instantiate :b, 2
|
1962
|
+
g2.instantiate :t, [3]
|
1963
|
+
g3.instantiate :t, [4]
|
1964
|
+
arrays = [
|
1965
|
+
[:h]/:t,
|
1966
|
+
[:h,:b]/:t,
|
1967
|
+
[:h,:b]/:t,
|
1968
|
+
[:h]/:t,
|
1969
|
+
]
|
1970
|
+
arrays_goals = goals[0...arrays.size]
|
1971
|
+
|
1972
|
+
assert arrays.all?{|array| has_tail?(array, false) }, 'all arrays should have a tail'
|
1973
|
+
refute arrays.map(&:headtail?).all?, 'not all arrays should be a headtail array'
|
1974
|
+
refute arrays.map(&:headtail?).map(&:!).all?, 'not all arrays should be an array with a tail'
|
1975
|
+
|
1976
|
+
assert_nil unify_headtail_with_tail(arrays, arrays_goals, []), name
|
1977
|
+
|
1978
|
+
assert_equal [
|
1979
|
+
], g1.log
|
1980
|
+
assert_equal [
|
1981
|
+
'Cannot unify incompatible values: 3 with 4',
|
1982
|
+
'Cannot unify: [3] with [4]',
|
1983
|
+
#'Cannot unify: Goal2.3 with Goal3.4',
|
1984
|
+
], g2.log
|
1985
|
+
assert_equal [
|
1986
|
+
'Cannot unify incompatible values: 3 with 4',
|
1987
|
+
'Cannot unify: [3] with [4]',
|
1988
|
+
], g3.log
|
1989
|
+
assert_equal [
|
1990
|
+
], g4.log
|
1991
|
+
end
|
1992
|
+
|
1993
|
+
it 'should expand tails that overlap extended heads' do
|
1994
|
+
g1.instantiate :t, [3,3]
|
1995
|
+
g2.instantiate :b, 2
|
1996
|
+
g2.instantiate :t, [3]
|
1997
|
+
arrays = [
|
1998
|
+
[:h]/:t,
|
1999
|
+
[:h,:b]/:t,
|
2000
|
+
[:h,:b]/:t,
|
2001
|
+
[:h]/:t,
|
2002
|
+
]
|
2003
|
+
arrays_goals = goals[0...arrays.size]
|
2004
|
+
|
2005
|
+
assert arrays.all?{|array| has_tail?(array, false) }, 'all arrays should have a tail'
|
2006
|
+
refute arrays.map(&:headtail?).all?, 'not all arrays should be a headtail array'
|
2007
|
+
refute arrays.map(&:headtail?).map(&:!).all?, 'not all arrays should be an array with a tail'
|
2008
|
+
|
2009
|
+
assert_nil unify_headtail_with_tail(arrays, arrays_goals, []), name
|
2010
|
+
|
2011
|
+
assert_equal [
|
2012
|
+
'Cannot unify incompatible values: 3 with 2',
|
2013
|
+
'Cannot unify because Goal1.[3, 3] != [Goal2.:b, *Goal2.:t] (variable/array != array)',
|
2014
|
+
'Cannot unify tails: Goal1.:t with [Goal2.:b, *Goal2.:t]',
|
2015
|
+
], g1.log
|
2016
|
+
assert_equal [
|
2017
|
+
'Cannot unify incompatible values: 3 with 2',
|
2018
|
+
'Cannot unify because Goal1.[3, 3] != [Goal2.:b, *Goal2.:t] (variable/array != array)',
|
2019
|
+
'Cannot unify tails: Goal1.:t with [Goal2.:b, *Goal2.:t]',
|
2020
|
+
], g2.log
|
2021
|
+
assert_equal [
|
2022
|
+
], g3.log
|
2023
|
+
assert_equal [
|
2024
|
+
], g4.log
|
2025
|
+
end
|
2026
|
+
|
2027
|
+
it 'prioritises X over Y when merging' do
|
2028
|
+
# -- atomic over known array over non-array over unknown array/tail --
|
2029
|
+
# atomic over known
|
2030
|
+
# known array over non-array
|
2031
|
+
# non-array over unknown array/tail
|
2032
|
+
# atomic over non-array
|
2033
|
+
# array over unknown array/tail
|
2034
|
+
# atomic over unknown array/tail
|
2035
|
+
|
2036
|
+
g1.instantiate :t, [1,2,3]
|
2037
|
+
arrays = [
|
2038
|
+
:h/:t,
|
2039
|
+
UNKNOWN_ARRAY,
|
2040
|
+
]
|
2041
|
+
arrays_goals = goals[0...arrays.size]
|
2042
|
+
|
2043
|
+
merged, unifications = unify_headtail_with_tail(arrays, arrays_goals, [])
|
2044
|
+
|
2045
|
+
expected_merged = [nil, 1, 2, 3]
|
2046
|
+
expected_unifications = []
|
2047
|
+
|
2048
|
+
assert_equal expected_merged, merged
|
2049
|
+
assert_equal expected_unifications, unifications
|
2050
|
+
end
|
2051
|
+
|
2052
|
+
end
|
2053
|
+
|
2054
|
+
describe '#unify_headtail_with_headtail' do
|
2055
|
+
|
2056
|
+
let(:g1) { new_goal(:p, :x, :y) }
|
2057
|
+
let(:g2) { new_goal(:q, :a, :b) }
|
2058
|
+
let(:g3) { new_goal(:r, :s, :t) }
|
2059
|
+
let(:g4) { new_goal(:j, :k, :l) }
|
2060
|
+
let(:goals) { [g1, g2, g3, g4] }
|
2061
|
+
|
2062
|
+
it 'should reject a non-headtail array' do
|
2063
|
+
arrays = [
|
2064
|
+
[1,Tail.new([2,3])],
|
2065
|
+
[4],
|
2066
|
+
[7,UNKNOWN_TAIL],
|
2067
|
+
]
|
2068
|
+
arrays_goals = goals[0...arrays.size]
|
2069
|
+
|
2070
|
+
refute arrays.all?(&:headtail?)
|
2071
|
+
|
2072
|
+
assert_nil unify_headtail_with_headtail(arrays, arrays_goals, [])
|
2073
|
+
|
2074
|
+
msg = 'Wrong method called to unify [[1, *[2, 3]], [4], [7, ...]]'
|
2075
|
+
|
2076
|
+
arrays_goals.each do |goal|
|
2077
|
+
assert_equal [msg], goal.log
|
2078
|
+
end
|
2079
|
+
end
|
2080
|
+
|
2081
|
+
it 'should not unify unequal heads' do
|
2082
|
+
arrays = [
|
2083
|
+
[1,Tail.new([2,3])],
|
2084
|
+
[4]/:y,
|
2085
|
+
[7,UNKNOWN_TAIL],
|
2086
|
+
]
|
2087
|
+
arrays_goals = goals[0...arrays.size]
|
2088
|
+
|
2089
|
+
assert arrays.all?(&:headtail?), "arrays should all be headtails: #{arrays.reject(&:headtail?).map(&:inspect).join(' and ')}"
|
2090
|
+
|
2091
|
+
assert_nil unify_headtail_with_headtail(arrays, arrays_goals, [])
|
2092
|
+
|
2093
|
+
assert_equal [
|
2094
|
+
'Cannot unify because 1 != 4 (atomic != atomic)',
|
2095
|
+
'Cannot unify headtail heads: "1 with 4"',
|
2096
|
+
], g1.log
|
2097
|
+
assert_equal [
|
2098
|
+
'Cannot unify because 1 != 4 (atomic != atomic)',
|
2099
|
+
'Cannot unify headtail heads: "1 with 4"',
|
2100
|
+
], g2.log
|
2101
|
+
assert_equal [
|
2102
|
+
], g3.log
|
2103
|
+
end
|
2104
|
+
|
2105
|
+
it 'should process more than two arrays that are a headtail' do
|
2106
|
+
arrays = [
|
2107
|
+
[1, Tail.new([2,3])],
|
2108
|
+
[:a]/:f,
|
2109
|
+
[:c, UNKNOWN_TAIL],
|
2110
|
+
]
|
2111
|
+
arrays_goals = goals[0...arrays.size]
|
2112
|
+
|
2113
|
+
assert arrays.all?(&:headtail?)
|
2114
|
+
|
2115
|
+
merged, unifications = unify_headtail_with_headtail(arrays, arrays_goals, [])
|
2116
|
+
|
2117
|
+
expected_merged = [1,2,3]
|
2118
|
+
|
2119
|
+
expected_unifications = [
|
2120
|
+
[:a, 1, g2, g1],
|
2121
|
+
[:f, [2,3], g2, g1],
|
2122
|
+
[:c, 1, g3, g1],
|
2123
|
+
[:a, :c, g2, g3],
|
2124
|
+
[:f, UNKNOWN_TAIL, g2, g3],
|
2125
|
+
]
|
2126
|
+
|
2127
|
+
assert_equal expected_merged, merged
|
2128
|
+
assert_equal expected_unifications, unifications
|
2129
|
+
|
2130
|
+
arrays_goals.each do |goal|
|
2131
|
+
assert_equal [], goal.log
|
2132
|
+
end
|
2133
|
+
end
|
2134
|
+
|
2135
|
+
it 'should unify all combinations of heads and tails' do
|
2136
|
+
arrays = [
|
2137
|
+
[:a]/:b,
|
2138
|
+
[:c]/:d,
|
2139
|
+
[:e]/:f,
|
2140
|
+
[:g]/:h,
|
2141
|
+
]
|
2142
|
+
arrays_goals = goals[0...arrays.size]
|
2143
|
+
|
2144
|
+
assert arrays.all?(&:headtail?)
|
2145
|
+
|
2146
|
+
merged, unifications = unify_headtail_with_headtail(arrays, arrays_goals, [])
|
2147
|
+
|
2148
|
+
expected_merged = [nil, UNKNOWN_TAIL]
|
2149
|
+
|
2150
|
+
expected_unifications = [
|
2151
|
+
[:a, :c, g1, g2],
|
2152
|
+
[:b, :d, g1, g2],
|
2153
|
+
[:a, :e, g1, g3],
|
2154
|
+
[:b, :f, g1, g3],
|
2155
|
+
[:a, :g, g1, g4],
|
2156
|
+
[:b, :h, g1, g4],
|
2157
|
+
[:c, :e, g2, g3],
|
2158
|
+
[:d, :f, g2, g3],
|
2159
|
+
[:c, :g, g2, g4],
|
2160
|
+
[:d, :h, g2, g4],
|
2161
|
+
[:e, :g, g3, g4],
|
2162
|
+
[:f, :h, g3, g4],
|
2163
|
+
]
|
2164
|
+
|
2165
|
+
assert_equal expected_merged, merged
|
2166
|
+
assert_equal expected_unifications, unifications
|
2167
|
+
|
2168
|
+
arrays_goals.each do |goal|
|
2169
|
+
assert_equal [], goal.log
|
2170
|
+
end
|
2171
|
+
end
|
2172
|
+
|
2173
|
+
end
|
2174
|
+
|
67
2175
|
end
|