porolog 0.0.3 → 0.0.4
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 +5 -2
- data/coverage/badge.svg +1 -0
- data/coverage/index.html +7090 -0
- data/doc/Porolog.html +337 -0
- data/doc/_index.html +187 -0
- data/doc/class_list.html +51 -0
- data/doc/file.README.html +250 -0
- data/doc/file_list.html +56 -0
- data/doc/frames.html +17 -0
- data/doc/index.html +250 -0
- data/doc/method_list.html +403 -0
- data/doc/top-level-namespace.html +110 -0
- data/lib/porolog/arguments.rb +173 -0
- data/lib/porolog/predicate.rb +3 -2
- data/lib/porolog/scope.rb +3 -2
- data/lib/porolog.rb +4 -2
- data/test/porolog/arguments_test.rb +790 -0
- data/test/porolog/porolog_test.rb +67 -0
- data/test/porolog/predicate_test.rb +27 -9
- data/test/porolog/scope_test.rb +13 -13
- data/test/test_helper.rb +22 -2
- metadata +20 -3
@@ -0,0 +1,790 @@
|
|
1
|
+
#
|
2
|
+
# test/porolog/arguments_test.rb - Test Suite for Porolog::Arguments
|
3
|
+
#
|
4
|
+
# Luis Esteban 2 May 2018
|
5
|
+
# created
|
6
|
+
#
|
7
|
+
|
8
|
+
require_relative '../test_helper'
|
9
|
+
|
10
|
+
describe 'Porolog' do
|
11
|
+
|
12
|
+
before(:all) do
|
13
|
+
reset
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'Arguments' do
|
17
|
+
|
18
|
+
describe '.reset' do
|
19
|
+
|
20
|
+
it 'should delete/unregister all Arguments' do
|
21
|
+
p = Predicate.new :p
|
22
|
+
|
23
|
+
args1 = Arguments.new p, [1,:x,'word',[2,:y,0.3]]
|
24
|
+
args2 = Arguments.new p, [2]
|
25
|
+
args3 = Arguments.new p, [3,:x,:y,:z]
|
26
|
+
|
27
|
+
assert_equal 'Arguments1', args1.myid
|
28
|
+
assert_equal 'Arguments2', args2.myid
|
29
|
+
assert_equal 'Arguments3', args3.myid
|
30
|
+
|
31
|
+
Arguments.reset
|
32
|
+
|
33
|
+
args4 = Arguments.new p, [4,[1,2,3]]
|
34
|
+
args5 = Arguments.new p, [5,[]]
|
35
|
+
|
36
|
+
assert_equal 'Arguments-999', args1.myid
|
37
|
+
assert_equal 'Arguments-999', args2.myid
|
38
|
+
assert_equal 'Arguments-999', args3.myid
|
39
|
+
assert_equal 'Arguments1', args4.myid
|
40
|
+
assert_equal 'Arguments2', args5.myid
|
41
|
+
|
42
|
+
Arguments.reset
|
43
|
+
|
44
|
+
assert_equal 'Arguments-999', args1.myid
|
45
|
+
assert_equal 'Arguments-999', args2.myid
|
46
|
+
assert_equal 'Arguments-999', args3.myid
|
47
|
+
assert_equal 'Arguments-999', args4.myid
|
48
|
+
assert_equal 'Arguments-999', args5.myid
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '.new' do
|
54
|
+
|
55
|
+
it 'should create a new Arguments' do
|
56
|
+
predicate = Predicate.new :p
|
57
|
+
arguments = Arguments.new predicate, [1,:x,'word',[2,:y,0.3]]
|
58
|
+
|
59
|
+
assert_Arguments arguments, :p, [1,:x,'word',[2,:y,0.3]]
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '.arguments' do
|
65
|
+
|
66
|
+
it 'should return all registered arguments' do
|
67
|
+
assert_equal 0, Arguments.arguments.size
|
68
|
+
|
69
|
+
predicate1 = Predicate.new :p
|
70
|
+
arguments1 = Arguments.new predicate1, [:x,:y,:z]
|
71
|
+
|
72
|
+
assert_equal 1, Arguments.arguments.size
|
73
|
+
assert_Arguments Arguments.arguments.last, :p, [:x,:y,:z]
|
74
|
+
|
75
|
+
predicate2 = Predicate.new :q
|
76
|
+
arguments2 = Arguments.new predicate2, [:a,:b,:c,:d]
|
77
|
+
|
78
|
+
assert_equal 2, Arguments.arguments.size
|
79
|
+
assert_Arguments Arguments.arguments.last, :q, [:a,:b,:c,:d]
|
80
|
+
|
81
|
+
assert_equal [arguments1,arguments2], Arguments.arguments
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#initialize' do
|
87
|
+
|
88
|
+
it 'should initialize predicate and arguments' do
|
89
|
+
predicate = Predicate.new :p
|
90
|
+
arguments = Arguments.new predicate, [:x,:y,:z]
|
91
|
+
|
92
|
+
assert_equal predicate, arguments.predicate
|
93
|
+
assert_equal [:x,:y,:z], arguments.arguments
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should register the arguments' do
|
97
|
+
predicate = Predicate.new :p
|
98
|
+
arguments1 = Arguments.new predicate, [:x]
|
99
|
+
arguments2 = Arguments.new predicate, [:x,:y]
|
100
|
+
arguments3 = Arguments.new predicate, [:x,:y,:z]
|
101
|
+
|
102
|
+
assert_equal [
|
103
|
+
arguments1,
|
104
|
+
arguments2,
|
105
|
+
arguments3,
|
106
|
+
], Arguments.arguments
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '#myid' do
|
112
|
+
|
113
|
+
it 'should return its class and index as a String' do
|
114
|
+
predicate = Predicate.new :p
|
115
|
+
arguments1 = Arguments.new predicate, [:x]
|
116
|
+
arguments2 = Arguments.new predicate, [:x,:y]
|
117
|
+
arguments3 = Arguments.new predicate, [:x,:y,:z]
|
118
|
+
|
119
|
+
assert_equal 'Arguments1', arguments1.myid
|
120
|
+
assert_equal 'Arguments2', arguments2.myid
|
121
|
+
assert_equal 'Arguments3', arguments3.myid
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should return its class and -999 as a String when deleted/reset' do
|
125
|
+
predicate = Predicate.new :p
|
126
|
+
arguments1 = Arguments.new predicate, [:x]
|
127
|
+
arguments2 = Arguments.new predicate, [:x,:y]
|
128
|
+
arguments3 = Arguments.new predicate, [:x,:y,:z]
|
129
|
+
|
130
|
+
Arguments.reset
|
131
|
+
|
132
|
+
assert_equal 'Arguments-999', arguments1.myid
|
133
|
+
assert_equal 'Arguments-999', arguments2.myid
|
134
|
+
assert_equal 'Arguments-999', arguments3.myid
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#inspect' do
|
140
|
+
|
141
|
+
it 'should show the predicate and arguments' do
|
142
|
+
predicate1 = Predicate.new :p
|
143
|
+
predicate2 = Predicate.new :q
|
144
|
+
predicate3 = Predicate.new :generic
|
145
|
+
arguments1 = Arguments.new predicate1, [:x]
|
146
|
+
arguments2 = Arguments.new predicate2, [:list, [1,2,3]]
|
147
|
+
arguments3 = Arguments.new predicate3, [:a,:b,:c]
|
148
|
+
|
149
|
+
assert_equal 'p(:x)', arguments1.inspect
|
150
|
+
assert_equal 'q(:list,[1, 2, 3])', arguments2.inspect
|
151
|
+
assert_equal 'generic(:a,:b,:c)', arguments3.inspect
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
describe '#fact!' do
|
157
|
+
|
158
|
+
it 'should create a fact for its predicate' do
|
159
|
+
skip 'until Rule added'
|
160
|
+
|
161
|
+
predicate1 = Predicate.new :predicate1
|
162
|
+
arguments1 = predicate1.(1,'a',0.1)
|
163
|
+
|
164
|
+
arguments1.fact!
|
165
|
+
|
166
|
+
assert_equal '[ predicate1(1,"a",0.1):- true]', predicate1.rules.inspect
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
describe '#falicy!' do
|
172
|
+
|
173
|
+
it 'should create a falicy for its predicate' do
|
174
|
+
skip 'until Rule added'
|
175
|
+
|
176
|
+
predicate1 = Predicate.new :predicate1
|
177
|
+
arguments1 = predicate1.(1,'a',0.1)
|
178
|
+
|
179
|
+
arguments1.falicy!
|
180
|
+
|
181
|
+
assert_equal '[ predicate1(1,"a",0.1):- false]', predicate1.rules.inspect
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
describe '#cut_fact!' do
|
187
|
+
|
188
|
+
it 'should create a fact for its predicate and terminate solving the goal' do
|
189
|
+
skip 'until Rule added'
|
190
|
+
|
191
|
+
predicate1 = Predicate.new :predicate1
|
192
|
+
arguments1 = predicate1.(1,'a',0.1)
|
193
|
+
|
194
|
+
arguments1.cut_fact!
|
195
|
+
|
196
|
+
assert_equal '[ predicate1(1,"a",0.1):- ! true]', predicate1.rules.inspect
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
200
|
+
|
201
|
+
describe '#cut_falicy!' do
|
202
|
+
|
203
|
+
it 'should create a falicy for its predicate and terminate solving the goal' do
|
204
|
+
skip 'until Rule added'
|
205
|
+
|
206
|
+
predicate1 = Predicate.new :predicate1
|
207
|
+
arguments1 = predicate1.(1,'a',0.1)
|
208
|
+
|
209
|
+
arguments1.cut_falicy!
|
210
|
+
|
211
|
+
assert_equal '[ predicate1(1,"a",0.1):- ! false]', predicate1.rules.inspect
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
describe '#<<' do
|
217
|
+
|
218
|
+
it 'should create a rule for its predicate' do
|
219
|
+
skip 'until Rule added'
|
220
|
+
|
221
|
+
predicate1 = Predicate.new :predicate1
|
222
|
+
arguments1 = predicate1.(1,'a',0.1)
|
223
|
+
|
224
|
+
arguments1 << [
|
225
|
+
1,2,3
|
226
|
+
]
|
227
|
+
|
228
|
+
assert_equal '[ predicate1(1,"a",0.1):- [1, 2, 3]]', predicate1.rules.inspect
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
|
233
|
+
describe '#evaluates' do
|
234
|
+
|
235
|
+
it 'should add a block as a rule to its predicate' do
|
236
|
+
skip 'until Rule added'
|
237
|
+
|
238
|
+
predicate1 = Predicate.new :predicate1
|
239
|
+
arguments1 = predicate1.(1,'a',0.1)
|
240
|
+
|
241
|
+
line = __LINE__ ; arguments2 = arguments1.evaluates do |*args|
|
242
|
+
$stderr.puts "args = #{args.inspect}"
|
243
|
+
end
|
244
|
+
|
245
|
+
assert_instance_of Arguments, arguments2
|
246
|
+
|
247
|
+
part1 = "[ predicate1(1,\"a\",0.1):- #<Proc:0x"
|
248
|
+
part2 = "@#{__FILE__}:#{line}>]"
|
249
|
+
|
250
|
+
matcher = Regexp.new(
|
251
|
+
'\A' +
|
252
|
+
Regexp.escape(part1) +
|
253
|
+
'[[:xdigit:]]+' +
|
254
|
+
Regexp.escape(part2) +
|
255
|
+
'\Z'
|
256
|
+
)
|
257
|
+
assert_match matcher, predicate1.rules.inspect
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
describe '#variables' do
|
262
|
+
|
263
|
+
it 'should find variable arguments' do
|
264
|
+
skip 'until CoreExt added'
|
265
|
+
|
266
|
+
predicate1 = Predicate.new :alpha
|
267
|
+
arguments1 = predicate1.(1,'a',0.1,:a,2.2,:b,'b',:C,1234)
|
268
|
+
variables1 = arguments1.variables
|
269
|
+
|
270
|
+
assert_equal [:a,:b,:C], variables1
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'should find nested variable arguments' do
|
274
|
+
skip 'until CoreExt added'
|
275
|
+
|
276
|
+
predicate1 = Predicate.new :alpha
|
277
|
+
predicate2 = Predicate.new :bravo
|
278
|
+
|
279
|
+
arguments = predicate1.(1,'a',0.1,:a,predicate2.(:P,4,:Q),2.2,:b,'b',:C,1234)
|
280
|
+
variables = arguments.variables
|
281
|
+
|
282
|
+
assert_equal [:a,:P,:Q,:b,:C], variables
|
283
|
+
end
|
284
|
+
|
285
|
+
it 'should find embedded variable arguments' do
|
286
|
+
skip 'until CoreExt added'
|
287
|
+
|
288
|
+
predicate1 = Predicate.new :alpha
|
289
|
+
predicate2 = Predicate.new :bravo
|
290
|
+
|
291
|
+
arguments = predicate1.(1,[:e1],'a',:h/:t,0.1,:a,predicate2.(:P,[6,:r,8]/predicate2.([:z]),4,:Q),2.2,:b,'b',:C,1234)
|
292
|
+
variables = arguments.variables
|
293
|
+
|
294
|
+
assert_equal [:e1,:h,:t,:a,:P,:r,:z,:Q,:b,:C], variables
|
295
|
+
end
|
296
|
+
|
297
|
+
end
|
298
|
+
|
299
|
+
describe '#goal' do
|
300
|
+
|
301
|
+
it 'should return a new goal for solving the arguments' do
|
302
|
+
skip 'until Goal added'
|
303
|
+
|
304
|
+
predicate1 = Predicate.new :alpha
|
305
|
+
arguments1 = predicate1.(1,'a',0.1,:a,2.2,:b,'b',:C,1234)
|
306
|
+
|
307
|
+
goal = arguments1.goal
|
308
|
+
|
309
|
+
assert_instance_of Goal, goal
|
310
|
+
assert_equal arguments1, goal.arguments
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
314
|
+
|
315
|
+
describe '#solutions' do
|
316
|
+
|
317
|
+
it 'should memoize solutions' do
|
318
|
+
skip 'until Rule added'
|
319
|
+
# TODO: it 'should memoize solutions' do
|
320
|
+
end
|
321
|
+
|
322
|
+
end
|
323
|
+
|
324
|
+
describe '#solve' do
|
325
|
+
|
326
|
+
it 'should unify and solve a simple predicate' do
|
327
|
+
skip 'until Rule added'
|
328
|
+
|
329
|
+
alpha = Predicate.new :alpha
|
330
|
+
args1 = Arguments.new alpha, [1,2]
|
331
|
+
args2 = Arguments.new alpha, [:p,:q]
|
332
|
+
|
333
|
+
args1.fact!
|
334
|
+
|
335
|
+
solutions = args2.solve
|
336
|
+
|
337
|
+
assert_equal [{ p: 1, q: 2 }], solutions
|
338
|
+
end
|
339
|
+
|
340
|
+
it 'should unify and solve a simple predicate with multiple solutions' do
|
341
|
+
skip 'until Rule added'
|
342
|
+
|
343
|
+
predicate :alpha
|
344
|
+
|
345
|
+
alpha(1,2).fact!
|
346
|
+
alpha(3,4).fact!
|
347
|
+
|
348
|
+
solutions = alpha(:p,:q).solve
|
349
|
+
|
350
|
+
assert_equal [
|
351
|
+
{ p: 1, q: 2 },
|
352
|
+
{ p: 3, q: 4 },
|
353
|
+
],solutions
|
354
|
+
end
|
355
|
+
|
356
|
+
it 'should unify and solve a simple predicate with multiple solutions involving a head and tail' do
|
357
|
+
skip 'until Rule added'
|
358
|
+
|
359
|
+
predicate :alpha
|
360
|
+
|
361
|
+
alpha([1,2,3]).fact!
|
362
|
+
alpha([3,4,5]).fact!
|
363
|
+
|
364
|
+
solutions = alpha(:p/:q).solve
|
365
|
+
|
366
|
+
assert_equal [
|
367
|
+
{ p: 1, q: [2,3] },
|
368
|
+
{ p: 3, q: [4,5] },
|
369
|
+
],solutions
|
370
|
+
end
|
371
|
+
|
372
|
+
it 'should unify and solve a basic predicate' do
|
373
|
+
skip 'until Rule added'
|
374
|
+
|
375
|
+
predicate :likes
|
376
|
+
|
377
|
+
likes('mary','food').fact!
|
378
|
+
likes('mary','wine').fact!
|
379
|
+
likes('john','wine').fact!
|
380
|
+
likes('john','mary').fact!
|
381
|
+
|
382
|
+
assert_equal true, likes('mary','food').valid?
|
383
|
+
assert_equal true, likes('john','wine').valid?
|
384
|
+
assert_equal false, likes('john','food').valid?
|
385
|
+
|
386
|
+
solutions = likes(:who,:what).solve
|
387
|
+
|
388
|
+
assert_equal [
|
389
|
+
{ who: 'mary', what: 'food' },
|
390
|
+
{ who: 'mary', what: 'wine' },
|
391
|
+
{ who: 'john', what: 'wine' },
|
392
|
+
{ who: 'john', what: 'mary' },
|
393
|
+
],solutions
|
394
|
+
end
|
395
|
+
|
396
|
+
it 'should unify and solve a deeper predicate' do
|
397
|
+
skip 'until Rule added'
|
398
|
+
|
399
|
+
predicate :male, :female, :parent
|
400
|
+
|
401
|
+
male('james1').fact!
|
402
|
+
male('charles1').fact!
|
403
|
+
male('charles2').fact!
|
404
|
+
male('james2').fact!
|
405
|
+
male('george1').fact!
|
406
|
+
|
407
|
+
female('catherine').fact!
|
408
|
+
female('elizabeth').fact!
|
409
|
+
female('sophia').fact!
|
410
|
+
|
411
|
+
parent('charles1', 'james1').fact!
|
412
|
+
parent('elizabeth', 'james1').fact!
|
413
|
+
parent('charles2', 'charles1').fact!
|
414
|
+
parent('catherine', 'charles1').fact!
|
415
|
+
parent('james2', 'charles1').fact!
|
416
|
+
parent('sophia', 'elizabeth').fact!
|
417
|
+
parent('george1', 'sophia').fact!
|
418
|
+
|
419
|
+
assert_equal false, parent('charles1', 'george1').valid?
|
420
|
+
|
421
|
+
solutions = parent('charles1', :X).solve
|
422
|
+
|
423
|
+
assert_equal [
|
424
|
+
{ X: 'james1' }
|
425
|
+
], solutions
|
426
|
+
|
427
|
+
solutions = parent(:X, 'charles1').solve
|
428
|
+
|
429
|
+
assert_equal [
|
430
|
+
{ X: 'charles2' },
|
431
|
+
{ X: 'catherine' },
|
432
|
+
{ X: 'james2' },
|
433
|
+
], solutions
|
434
|
+
|
435
|
+
predicate :mother, :father, :sibling, :isnt
|
436
|
+
|
437
|
+
mother(:X,:M) << [
|
438
|
+
parent(:X,:M),
|
439
|
+
female(:M)
|
440
|
+
]
|
441
|
+
|
442
|
+
father(:X,:F) << [
|
443
|
+
parent(:X,:F),
|
444
|
+
male(:F)
|
445
|
+
]
|
446
|
+
|
447
|
+
isnt(:A,:A) << [:CUT, false]
|
448
|
+
isnt(:A,:B) << [:CUT, true]
|
449
|
+
|
450
|
+
sibling(:X,:Y) << [
|
451
|
+
parent(:X,:P),
|
452
|
+
parent(:Y,:P),
|
453
|
+
isnt(:X,:Y)
|
454
|
+
]
|
455
|
+
|
456
|
+
solutions = mother(:child, :mother).solve
|
457
|
+
|
458
|
+
assert_equal [
|
459
|
+
{ child: 'sophia', mother: 'elizabeth' },
|
460
|
+
{ child: 'george1', mother: 'sophia' },
|
461
|
+
], solutions
|
462
|
+
|
463
|
+
solutions = father(:child, :father).solve
|
464
|
+
|
465
|
+
assert_equal [
|
466
|
+
{ child: 'charles1', father: 'james1' },
|
467
|
+
{ child: 'elizabeth', father: 'james1' },
|
468
|
+
{ child: 'charles2', father: 'charles1'},
|
469
|
+
{ child: 'catherine', father: 'charles1'},
|
470
|
+
{ child: 'james2', father: 'charles1'}
|
471
|
+
], solutions
|
472
|
+
|
473
|
+
solutions = sibling(:s1, :s2).solve
|
474
|
+
|
475
|
+
assert_equal [
|
476
|
+
{ s1: 'charles1', s2: 'elizabeth' },
|
477
|
+
{ s1: 'elizabeth', s2: 'charles1' },
|
478
|
+
{ s1: 'charles2', s2: 'catherine' },
|
479
|
+
{ s1: 'charles2', s2: 'james2' },
|
480
|
+
{ s1: 'catherine', s2: 'charles2' },
|
481
|
+
{ s1: 'catherine', s2: 'james2' },
|
482
|
+
{ s1: 'james2', s2: 'charles2' },
|
483
|
+
{ s1: 'james2', s2: 'catherine' }
|
484
|
+
], solutions
|
485
|
+
end
|
486
|
+
|
487
|
+
it 'should unify and solve a predicate involving a head and tail' do
|
488
|
+
skip 'until Rule added'
|
489
|
+
|
490
|
+
predicate :alpha, :beta, :gamma
|
491
|
+
|
492
|
+
gamma([1,2]).fact!
|
493
|
+
gamma([2,3]).fact!
|
494
|
+
|
495
|
+
gamma([:h/:t]) << [
|
496
|
+
gamma(:h),
|
497
|
+
gamma(:t),
|
498
|
+
]
|
499
|
+
|
500
|
+
alpha(:l) << [
|
501
|
+
gamma(:l)
|
502
|
+
]
|
503
|
+
|
504
|
+
solutions = alpha(:p/:q).solve
|
505
|
+
|
506
|
+
assert_equal [
|
507
|
+
{ p: 1, q: 2 },
|
508
|
+
{ p: 2, q: 3 },
|
509
|
+
],solutions
|
510
|
+
end
|
511
|
+
|
512
|
+
it 'should call a builtin predicate' do
|
513
|
+
skip 'until StandardPredicates added'
|
514
|
+
|
515
|
+
predicate :callwrite
|
516
|
+
|
517
|
+
callwrite(:MESSAGE) << [
|
518
|
+
write(:MESSAGE,"\n")
|
519
|
+
]
|
520
|
+
|
521
|
+
assert_output "hello world\n" do
|
522
|
+
solutions = callwrite('hello world').solve
|
523
|
+
|
524
|
+
assert_equal [
|
525
|
+
{},
|
526
|
+
],solutions
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
530
|
+
it 'should pass on instantiations between goals' do
|
531
|
+
skip 'until Rule added'
|
532
|
+
|
533
|
+
predicate :passon, :copy
|
534
|
+
|
535
|
+
copy(:A,:A).fact!
|
536
|
+
|
537
|
+
passon(1,:A) << [
|
538
|
+
write('1: A=',:A,"\n"),
|
539
|
+
]
|
540
|
+
passon(5,:E) << [
|
541
|
+
write('5: E=',:E,"\n"),
|
542
|
+
copy(:E,:F),
|
543
|
+
write('5: F=',:F,"\n"),
|
544
|
+
passon(1,:F)
|
545
|
+
]
|
546
|
+
|
547
|
+
assert_output "5: E=passed on\n5: F=passed on\n1: A=passed on\n" do
|
548
|
+
solutions = passon(5,'passed on').solve
|
549
|
+
|
550
|
+
assert_equal [
|
551
|
+
{},
|
552
|
+
],solutions
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
it 'should pass on instantiations between goals' do
|
557
|
+
skip 'until StandardPredicates added'
|
558
|
+
|
559
|
+
predicate :count
|
560
|
+
|
561
|
+
count(1) << [
|
562
|
+
write("1: END\n"),
|
563
|
+
:CUT
|
564
|
+
]
|
565
|
+
count(:N) << [
|
566
|
+
write("N = ",:N),
|
567
|
+
is(:M,:N){|n| n - 1 },
|
568
|
+
write(" M = ",:M,"\n"),
|
569
|
+
count(:M),
|
570
|
+
]
|
571
|
+
|
572
|
+
expected_output = [
|
573
|
+
'N = 10 M = 9',
|
574
|
+
'N = 9 M = 8',
|
575
|
+
'N = 8 M = 7',
|
576
|
+
'N = 7 M = 6',
|
577
|
+
'N = 6 M = 5',
|
578
|
+
'N = 5 M = 4',
|
579
|
+
'N = 4 M = 3',
|
580
|
+
'N = 3 M = 2',
|
581
|
+
'N = 2 M = 1',
|
582
|
+
'1: END',
|
583
|
+
].map{|s| "#{s}\n" }.join
|
584
|
+
|
585
|
+
assert_output expected_output do
|
586
|
+
solutions = count(10).solve
|
587
|
+
|
588
|
+
assert_equal [
|
589
|
+
{},
|
590
|
+
],solutions
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
it 'should solve tower of Hanoi' do
|
595
|
+
skip 'until StandardPredicates added'
|
596
|
+
|
597
|
+
predicate :move
|
598
|
+
|
599
|
+
move(1,:X,:Y,:Z) << [
|
600
|
+
write('Move top disk from ', :X, ' to ', :Y, "\n"),
|
601
|
+
]
|
602
|
+
move(:N,:X,:Y,:Z) << [
|
603
|
+
gtr(:N,1),
|
604
|
+
is(:M,:N){|n| n - 1 },
|
605
|
+
move(:M,:X,:Z,:Y),
|
606
|
+
move(1,:X,:Y,:Q),
|
607
|
+
move(:M,:Z,:Y,:X),
|
608
|
+
]
|
609
|
+
|
610
|
+
expected_output = [
|
611
|
+
'Move top disk from left to center',
|
612
|
+
'Move top disk from left to right',
|
613
|
+
'Move top disk from center to right',
|
614
|
+
'Move top disk from left to center',
|
615
|
+
'Move top disk from right to left',
|
616
|
+
'Move top disk from right to center',
|
617
|
+
'Move top disk from left to center',
|
618
|
+
'Move top disk from left to right',
|
619
|
+
'Move top disk from center to right',
|
620
|
+
'Move top disk from center to left',
|
621
|
+
'Move top disk from right to left',
|
622
|
+
'Move top disk from center to right',
|
623
|
+
'Move top disk from left to center',
|
624
|
+
'Move top disk from left to right',
|
625
|
+
'Move top disk from center to right',
|
626
|
+
].map{|s| "#{s}\n" }.join
|
627
|
+
|
628
|
+
assert_output expected_output do
|
629
|
+
solutions = move(4,'left','right','center').solve
|
630
|
+
|
631
|
+
assert_equal [
|
632
|
+
{},
|
633
|
+
],solutions
|
634
|
+
end
|
635
|
+
end
|
636
|
+
|
637
|
+
it 'should solve a peeling off predicate' do
|
638
|
+
skip 'until Rule added'
|
639
|
+
|
640
|
+
predicate :size
|
641
|
+
|
642
|
+
size([],0).cut_fact!
|
643
|
+
size(:H/:T,:N) << [
|
644
|
+
size(:T,:NT),
|
645
|
+
is(:N,:NT){|nt| nt + 1 },
|
646
|
+
]
|
647
|
+
|
648
|
+
solutions = size([],:N).solve
|
649
|
+
|
650
|
+
assert_equal [
|
651
|
+
{ N: 0 }
|
652
|
+
],solutions
|
653
|
+
|
654
|
+
solutions = size([13,17,19,23],:N).solve
|
655
|
+
|
656
|
+
assert_equal [
|
657
|
+
{ N: 4 },
|
658
|
+
],solutions
|
659
|
+
end
|
660
|
+
|
661
|
+
it 'should solve tower of Hanoi with list representation' do
|
662
|
+
skip 'until StandardPredicates added and converted to list representation'
|
663
|
+
# TODO: convert to list representation
|
664
|
+
|
665
|
+
predicate :move
|
666
|
+
|
667
|
+
move(1,:X,:Y,:Z) << [
|
668
|
+
write('Move top disk from ', :X, ' to ', :Y, "\n"),
|
669
|
+
]
|
670
|
+
move(:N,:X,:Y,:Z) << [
|
671
|
+
gtr(:N,1),
|
672
|
+
is(:M,:N){|n| n - 1 },
|
673
|
+
move(:M,:X,:Z,:Y),
|
674
|
+
move(1,:X,:Y,:Q),
|
675
|
+
move(:M,:Z,:Y,:X),
|
676
|
+
]
|
677
|
+
|
678
|
+
expected_output = [
|
679
|
+
'Move top disk from left to center',
|
680
|
+
'Move top disk from left to right',
|
681
|
+
'Move top disk from center to right',
|
682
|
+
'Move top disk from left to center',
|
683
|
+
'Move top disk from right to left',
|
684
|
+
'Move top disk from right to center',
|
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 center to left',
|
689
|
+
'Move top disk from right to left',
|
690
|
+
'Move top disk from center to right',
|
691
|
+
'Move top disk from left to center',
|
692
|
+
'Move top disk from left to right',
|
693
|
+
'Move top disk from center to right',
|
694
|
+
].map{|s| "#{s}\n" }.join
|
695
|
+
|
696
|
+
assert_output expected_output do
|
697
|
+
solutions = move(4,'left','right','center').solve
|
698
|
+
|
699
|
+
assert_equal [
|
700
|
+
{},
|
701
|
+
],solutions
|
702
|
+
end
|
703
|
+
end
|
704
|
+
|
705
|
+
end
|
706
|
+
|
707
|
+
describe '#solve_for' do
|
708
|
+
|
709
|
+
it 'should solve a predicate for specified variables' do
|
710
|
+
skip 'until Rule added'
|
711
|
+
|
712
|
+
predicate :alpha
|
713
|
+
|
714
|
+
alpha(1,2).fact!
|
715
|
+
|
716
|
+
solutions = alpha(:p,:q).solve_for(:p,:q)
|
717
|
+
|
718
|
+
assert_equal [[1,2]], solutions
|
719
|
+
end
|
720
|
+
|
721
|
+
it 'should solve a predicate with multiple solutions for specified variables' do
|
722
|
+
skip 'until Rule added'
|
723
|
+
|
724
|
+
predicate :alpha
|
725
|
+
|
726
|
+
alpha(1,2).fact!
|
727
|
+
alpha(3,4).fact!
|
728
|
+
alpha(5,6).fact!
|
729
|
+
alpha(5,7).fact!
|
730
|
+
|
731
|
+
solutions = alpha(:p,:q).solve_for(:p)
|
732
|
+
|
733
|
+
assert_equal [
|
734
|
+
[1],
|
735
|
+
[3],
|
736
|
+
[5],
|
737
|
+
[5],
|
738
|
+
], solutions
|
739
|
+
end
|
740
|
+
|
741
|
+
end
|
742
|
+
|
743
|
+
describe '#valid?' do
|
744
|
+
|
745
|
+
it 'should return true when a solution is found' do
|
746
|
+
# TODO: it 'should return true when a solution is found' do
|
747
|
+
end
|
748
|
+
|
749
|
+
it 'should return false when no solution is found' do
|
750
|
+
# TODO: it 'should return false when no solution is found' do
|
751
|
+
end
|
752
|
+
|
753
|
+
end
|
754
|
+
|
755
|
+
describe '#dup' do
|
756
|
+
|
757
|
+
it 'should create a duplicate arguments for another goal' do
|
758
|
+
skip 'until HeadTail added'
|
759
|
+
# TODO: it 'should create a duplicate arguments for another goal' do
|
760
|
+
end
|
761
|
+
|
762
|
+
end
|
763
|
+
|
764
|
+
describe '#==' do
|
765
|
+
|
766
|
+
it 'should return true for Arguments with identical predicates and arguments' do
|
767
|
+
predicate1 = Predicate.new :omega
|
768
|
+
arguments1 = predicate1.(1,'a',0.1)
|
769
|
+
|
770
|
+
predicate2 = Predicate.new :omega
|
771
|
+
arguments2 = predicate2.(1,'a',0.1)
|
772
|
+
|
773
|
+
assert arguments1 == arguments2, 'Arguments with identical predicates and arguments should return true'
|
774
|
+
end
|
775
|
+
|
776
|
+
it 'should return false for Arguments with identical predicates and arguments' do
|
777
|
+
predicate1 = Predicate.new :omega
|
778
|
+
arguments1 = predicate1.(1,'a',0.1)
|
779
|
+
|
780
|
+
predicate2 = Predicate.new :omega
|
781
|
+
arguments2 = predicate2.(1,'a',0.2)
|
782
|
+
|
783
|
+
refute arguments1 == arguments2, 'Arguments with non-identical predicates and arguments should return false'
|
784
|
+
end
|
785
|
+
|
786
|
+
end
|
787
|
+
|
788
|
+
end
|
789
|
+
|
790
|
+
end
|