porolog 0.0.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +30 -5
  3. data/Rakefile +7 -2
  4. data/bin/porolog +58 -1
  5. data/coverage/badge.svg +1 -1
  6. data/coverage/index.html +76733 -2638
  7. data/doc/Array.html +1066 -0
  8. data/doc/Object.html +674 -0
  9. data/doc/Porolog.html +4153 -74
  10. data/doc/Symbol.html +501 -0
  11. data/doc/_index.html +280 -6
  12. data/doc/class_list.html +1 -1
  13. data/doc/file.README.html +34 -39
  14. data/doc/index.html +34 -39
  15. data/doc/method_list.html +1337 -57
  16. data/doc/top-level-namespace.html +4 -2
  17. data/lib/porolog.rb +1144 -4
  18. data/lib/porolog/arguments.rb +28 -24
  19. data/lib/porolog/core_ext.rb +188 -0
  20. data/lib/porolog/error.rb +9 -0
  21. data/lib/porolog/goal.rb +357 -0
  22. data/lib/porolog/instantiation.rb +346 -0
  23. data/lib/porolog/predicate.rb +74 -31
  24. data/lib/porolog/predicate/builtin.rb +825 -0
  25. data/lib/porolog/rule.rb +162 -0
  26. data/lib/porolog/scope.rb +4 -4
  27. data/lib/porolog/tail.rb +57 -0
  28. data/lib/porolog/value.rb +105 -0
  29. data/lib/porolog/variable.rb +325 -0
  30. data/test/porolog/arguments_test.rb +244 -195
  31. data/test/porolog/core_ext_test.rb +290 -0
  32. data/test/porolog/goal_test.rb +891 -0
  33. data/test/porolog/instantiation_test.rb +910 -0
  34. data/test/porolog/porolog_test.rb +2376 -13
  35. data/test/porolog/predicate/builtin_test.rb +1340 -0
  36. data/test/porolog/predicate_test.rb +84 -30
  37. data/test/porolog/rule_test.rb +527 -0
  38. data/test/porolog/scope_test.rb +0 -2
  39. data/test/porolog/tail_test.rb +127 -0
  40. data/test/porolog/value_test.rb +315 -0
  41. data/test/porolog/variable_test.rb +1614 -0
  42. data/test/samples_test.rb +277 -0
  43. data/test/test_helper.rb +115 -0
  44. metadata +34 -7
@@ -13,16 +13,19 @@ describe 'Porolog' do
13
13
  reset
14
14
  end
15
15
 
16
+ let(:pred_name) { :pred }
17
+ let(:pred) { Predicate.new pred_name }
18
+ let(:pred1) { Predicate.new :p }
19
+ let(:pred2) { Predicate.new :q }
20
+
16
21
  describe 'Arguments' do
17
22
 
18
23
  describe '.reset' do
19
24
 
20
25
  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
+ args1 = Arguments.new pred, [1,:x,'word',[2,:y,0.3]]
27
+ args2 = Arguments.new pred, [2]
28
+ args3 = Arguments.new pred, [3,:x,:y,:z]
26
29
 
27
30
  assert_equal 'Arguments1', args1.myid
28
31
  assert_equal 'Arguments2', args2.myid
@@ -30,8 +33,8 @@ describe 'Porolog' do
30
33
 
31
34
  Arguments.reset
32
35
 
33
- args4 = Arguments.new p, [4,[1,2,3]]
34
- args5 = Arguments.new p, [5,[]]
36
+ args4 = Arguments.new pred, [4,[1,2,3]]
37
+ args5 = Arguments.new pred, [5,[]]
35
38
 
36
39
  assert_equal 'Arguments-999', args1.myid
37
40
  assert_equal 'Arguments-999', args2.myid
@@ -53,10 +56,9 @@ describe 'Porolog' do
53
56
  describe '.new' do
54
57
 
55
58
  it 'should create a new Arguments' do
56
- predicate = Predicate.new :p
57
- arguments = Arguments.new predicate, [1,:x,'word',[2,:y,0.3]]
59
+ arguments = Arguments.new pred, [1, :x, 'word', [2, :y, 0.3]]
58
60
 
59
- assert_Arguments arguments, :p, [1,:x,'word',[2,:y,0.3]]
61
+ assert_Arguments arguments, :pred, [1, :x, 'word', [2, :y, 0.3]]
60
62
  end
61
63
 
62
64
  end
@@ -64,21 +66,23 @@ describe 'Porolog' do
64
66
  describe '.arguments' do
65
67
 
66
68
  it 'should return all registered arguments' do
67
- assert_equal 0, Arguments.arguments.size
69
+ # -- No Arguments --
70
+ assert_equal 0, Arguments.arguments.size
68
71
 
69
- predicate1 = Predicate.new :p
70
- arguments1 = Arguments.new predicate1, [:x,:y,:z]
72
+ # -- One Arguments --
73
+ arguments1 = Arguments.new pred1, [:x,:y,:z]
71
74
 
72
- assert_equal 1, Arguments.arguments.size
75
+ assert_equal 1, Arguments.arguments.size
73
76
  assert_Arguments Arguments.arguments.last, :p, [:x,:y,:z]
74
77
 
75
- predicate2 = Predicate.new :q
76
- arguments2 = Arguments.new predicate2, [:a,:b,:c,:d]
78
+ # -- Two Arguments --
79
+ arguments2 = Arguments.new pred2, [:a,:b,:c,:d]
77
80
 
78
- assert_equal 2, Arguments.arguments.size
81
+ assert_equal 2, Arguments.arguments.size
79
82
  assert_Arguments Arguments.arguments.last, :q, [:a,:b,:c,:d]
80
83
 
81
- assert_equal [arguments1,arguments2], Arguments.arguments
84
+
85
+ assert_equal [arguments1, arguments2], Arguments.arguments
82
86
  end
83
87
 
84
88
  end
@@ -86,18 +90,16 @@ describe 'Porolog' do
86
90
  describe '#initialize' do
87
91
 
88
92
  it 'should initialize predicate and arguments' do
89
- predicate = Predicate.new :p
90
- arguments = Arguments.new predicate, [:x,:y,:z]
93
+ arguments = Arguments.new pred, [:x,:y,:z]
91
94
 
92
- assert_equal predicate, arguments.predicate
95
+ assert_equal pred, arguments.predicate
93
96
  assert_equal [:x,:y,:z], arguments.arguments
94
97
  end
95
98
 
96
99
  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]
100
+ arguments1 = Arguments.new pred, [:x]
101
+ arguments2 = Arguments.new pred, [:x,:y]
102
+ arguments3 = Arguments.new pred, [:x,:y,:z]
101
103
 
102
104
  assert_equal [
103
105
  arguments1,
@@ -111,10 +113,9 @@ describe 'Porolog' do
111
113
  describe '#myid' do
112
114
 
113
115
  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]
116
+ arguments1 = Arguments.new pred, [:x]
117
+ arguments2 = Arguments.new pred, [:x,:y]
118
+ arguments3 = Arguments.new pred, [:x,:y,:z]
118
119
 
119
120
  assert_equal 'Arguments1', arguments1.myid
120
121
  assert_equal 'Arguments2', arguments2.myid
@@ -122,10 +123,9 @@ describe 'Porolog' do
122
123
  end
123
124
 
124
125
  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]
126
+ arguments1 = Arguments.new pred, [:x]
127
+ arguments2 = Arguments.new pred, [:x,:y]
128
+ arguments3 = Arguments.new pred, [:x,:y,:z]
129
129
 
130
130
  Arguments.reset
131
131
 
@@ -142,6 +142,7 @@ describe 'Porolog' do
142
142
  predicate1 = Predicate.new :p
143
143
  predicate2 = Predicate.new :q
144
144
  predicate3 = Predicate.new :generic
145
+
145
146
  arguments1 = Arguments.new predicate1, [:x]
146
147
  arguments2 = Arguments.new predicate2, [:list, [1,2,3]]
147
148
  arguments3 = Arguments.new predicate3, [:a,:b,:c]
@@ -156,14 +157,11 @@ describe 'Porolog' do
156
157
  describe '#fact!' do
157
158
 
158
159
  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)
160
+ arguments1 = pred.(1,'a',0.1)
163
161
 
164
162
  arguments1.fact!
165
163
 
166
- assert_equal '[ predicate1(1,"a",0.1):- true]', predicate1.rules.inspect
164
+ assert_equal '[ pred(1,"a",0.1):- true]', pred.rules.inspect
167
165
  end
168
166
 
169
167
  end
@@ -171,14 +169,11 @@ describe 'Porolog' do
171
169
  describe '#falicy!' do
172
170
 
173
171
  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)
172
+ arguments1 = pred.(1,'a',0.1)
178
173
 
179
174
  arguments1.falicy!
180
175
 
181
- assert_equal '[ predicate1(1,"a",0.1):- false]', predicate1.rules.inspect
176
+ assert_equal '[ pred(1,"a",0.1):- false]', pred.rules.inspect
182
177
  end
183
178
 
184
179
  end
@@ -186,14 +181,11 @@ describe 'Porolog' do
186
181
  describe '#cut_fact!' do
187
182
 
188
183
  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)
184
+ arguments1 = pred.(1,'a',0.1)
193
185
 
194
186
  arguments1.cut_fact!
195
187
 
196
- assert_equal '[ predicate1(1,"a",0.1):- ! true]', predicate1.rules.inspect
188
+ assert_equal '[ pred(1,"a",0.1):- [:CUT, true]]', pred.rules.inspect
197
189
  end
198
190
 
199
191
  end
@@ -201,14 +193,11 @@ describe 'Porolog' do
201
193
  describe '#cut_falicy!' do
202
194
 
203
195
  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)
196
+ arguments1 = pred.(1,'a',0.1)
208
197
 
209
198
  arguments1.cut_falicy!
210
199
 
211
- assert_equal '[ predicate1(1,"a",0.1):- ! false]', predicate1.rules.inspect
200
+ assert_equal '[ pred(1,"a",0.1):- [:CUT, false]]', pred.rules.inspect
212
201
  end
213
202
 
214
203
  end
@@ -216,16 +205,13 @@ describe 'Porolog' do
216
205
  describe '#<<' do
217
206
 
218
207
  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)
208
+ arguments1 = pred.(1,'a',0.1)
223
209
 
224
210
  arguments1 << [
225
- 1,2,3
211
+ pred1.(1,2,3)
226
212
  ]
227
213
 
228
- assert_equal '[ predicate1(1,"a",0.1):- [1, 2, 3]]', predicate1.rules.inspect
214
+ assert_equal '[ pred(1,"a",0.1):- [p(1,2,3)]]', pred.rules.inspect
229
215
  end
230
216
 
231
217
  end
@@ -233,18 +219,17 @@ describe 'Porolog' do
233
219
  describe '#evaluates' do
234
220
 
235
221
  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)
222
+ arguments1 = pred.(1,'a',0.1)
240
223
 
241
224
  line = __LINE__ ; arguments2 = arguments1.evaluates do |*args|
225
+ #:nocov:
242
226
  $stderr.puts "args = #{args.inspect}"
227
+ #:nocov:
243
228
  end
244
229
 
245
230
  assert_instance_of Arguments, arguments2
246
231
 
247
- part1 = "[ predicate1(1,\"a\",0.1):- #<Proc:0x"
232
+ part1 = "[ pred(1,\"a\",0.1):- #<Proc:0x"
248
233
  part2 = "@#{__FILE__}:#{line}>]"
249
234
 
250
235
  matcher = Regexp.new(
@@ -254,41 +239,28 @@ describe 'Porolog' do
254
239
  Regexp.escape(part2) +
255
240
  '\Z'
256
241
  )
257
- assert_match matcher, predicate1.rules.inspect
242
+ assert_match matcher, pred.rules.inspect
258
243
  end
259
244
  end
260
245
 
261
246
  describe '#variables' do
262
247
 
263
248
  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)
249
+ arguments1 = pred.(1,'a',0.1,:a,2.2,:b,'b',:C,1234)
268
250
  variables1 = arguments1.variables
269
251
 
270
252
  assert_equal [:a,:b,:C], variables1
271
253
  end
272
254
 
273
255
  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)
256
+ arguments = pred1.(1, 'a', 0.1, :a, pred2.(:P, 4, :Q), 2.2, :b, 'b', :C, 1234)
280
257
  variables = arguments.variables
281
258
 
282
259
  assert_equal [:a,:P,:Q,:b,:C], variables
283
260
  end
284
261
 
285
262
  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)
263
+ arguments = pred1.(1, [:e1], 'a', :h/:t, 0.1, :a, pred2.(:P, [6, :r, 8]/pred2.([:z]), 4, :Q), 2.2, :b, 'b', :C, 1234)
292
264
  variables = arguments.variables
293
265
 
294
266
  assert_equal [:e1,:h,:t,:a,:P,:r,:z,:Q,:b,:C], variables
@@ -299,15 +271,11 @@ describe 'Porolog' do
299
271
  describe '#goal' do
300
272
 
301
273
  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)
274
+ arguments1 = pred1.(1, 'a', 0.1, :a, 2.2, :b, 'b', :C, 1234)
306
275
 
307
276
  goal = arguments1.goal
308
277
 
309
- assert_instance_of Goal, goal
310
- assert_equal arguments1, goal.arguments
278
+ assert_Goal goal, :p, [1, 'a', 0.1, :a, 2.2, :b, 'b', :C, 1234]
311
279
  end
312
280
 
313
281
  end
@@ -315,8 +283,20 @@ describe 'Porolog' do
315
283
  describe '#solutions' do
316
284
 
317
285
  it 'should memoize solutions' do
318
- skip 'until Rule added'
319
- # TODO: it 'should memoize solutions' do
286
+ args1 = Arguments.new pred, [1,2]
287
+ args2 = Arguments.new pred, [:p,:q]
288
+
289
+ args1.fact!
290
+
291
+ solve_spy = Spy.on(args2, :solve).and_call_through
292
+
293
+ assert_equal [{ p: 1, q: 2 }], args2.solutions
294
+ assert_equal [{ p: 1, q: 2 }], args2.solutions
295
+ assert_equal [{ p: 1, q: 2 }], args2.solutions
296
+ assert_equal [{ p: 1, q: 2 }], args2.solutions
297
+ assert_equal [{ p: 1, q: 2 }], args2.solutions
298
+
299
+ assert_equal 1, solve_spy.calls.size
320
300
  end
321
301
 
322
302
  end
@@ -324,11 +304,8 @@ describe 'Porolog' do
324
304
  describe '#solve' do
325
305
 
326
306
  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]
307
+ args1 = Arguments.new pred, [1,2]
308
+ args2 = Arguments.new pred, [:p,:q]
332
309
 
333
310
  args1.fact!
334
311
 
@@ -338,14 +315,12 @@ describe 'Porolog' do
338
315
  end
339
316
 
340
317
  it 'should unify and solve a simple predicate with multiple solutions' do
341
- skip 'until Rule added'
342
-
343
- predicate :alpha
318
+ predicate :simple
344
319
 
345
- alpha(1,2).fact!
346
- alpha(3,4).fact!
320
+ simple(1,2).fact!
321
+ simple(3,4).fact!
347
322
 
348
- solutions = alpha(:p,:q).solve
323
+ solutions = simple(:p,:q).solve
349
324
 
350
325
  assert_equal [
351
326
  { p: 1, q: 2 },
@@ -354,14 +329,12 @@ describe 'Porolog' do
354
329
  end
355
330
 
356
331
  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
332
+ predicate :basic
360
333
 
361
- alpha([1,2,3]).fact!
362
- alpha([3,4,5]).fact!
334
+ basic([1,2,3]).fact!
335
+ basic([3,4,5]).fact!
363
336
 
364
- solutions = alpha(:p/:q).solve
337
+ solutions = basic(:p/:q).solve
365
338
 
366
339
  assert_equal [
367
340
  { p: 1, q: [2,3] },
@@ -369,9 +342,7 @@ describe 'Porolog' do
369
342
  ],solutions
370
343
  end
371
344
 
372
- it 'should unify and solve a basic predicate' do
373
- skip 'until Rule added'
374
-
345
+ it 'should unify and solve a normal predicate' do
375
346
  predicate :likes
376
347
 
377
348
  likes('mary','food').fact!
@@ -385,17 +356,28 @@ describe 'Porolog' do
385
356
 
386
357
  solutions = likes(:who,:what).solve
387
358
 
388
- assert_equal [
359
+ assert_equal [
389
360
  { who: 'mary', what: 'food' },
390
361
  { who: 'mary', what: 'wine' },
391
362
  { who: 'john', what: 'wine' },
392
363
  { who: 'john', what: 'mary' },
393
- ],solutions
364
+ ], solutions
394
365
  end
395
366
 
396
- it 'should unify and solve a deeper predicate' do
397
- skip 'until Rule added'
367
+ it 'should allow isnt to be defined' do
368
+ predicate :isnt
398
369
 
370
+ isnt(:A,:A) << [:CUT, false]
371
+ isnt(:A,:B) << [:CUT, true]
372
+
373
+ solutions = isnt(123,123).solve
374
+ assert_equal [], solutions
375
+
376
+ solutions = isnt(123,124).solve
377
+ assert_equal [{}], solutions
378
+ end
379
+
380
+ it 'should unify and solve a deeper predicate' do
399
381
  predicate :male, :female, :parent
400
382
 
401
383
  male('james1').fact!
@@ -432,6 +414,7 @@ describe 'Porolog' do
432
414
  { X: 'james2' },
433
415
  ], solutions
434
416
 
417
+
435
418
  predicate :mother, :father, :sibling, :isnt
436
419
 
437
420
  mother(:X,:M) << [
@@ -485,33 +468,43 @@ describe 'Porolog' do
485
468
  end
486
469
 
487
470
  it 'should unify and solve a predicate involving a head and tail' do
488
- skip 'until Rule added'
471
+ predicate :join, :split, :head, :tail
489
472
 
490
- predicate :alpha, :beta, :gamma
473
+ head(1).fact!
474
+ head(4).fact!
475
+ tail([2,3]).fact!
476
+ tail([5,6]).fact!
491
477
 
492
- gamma([1,2]).fact!
493
- gamma([2,3]).fact!
494
-
495
- gamma([:h/:t]) << [
496
- gamma(:h),
497
- gamma(:t),
478
+ split(:h/:t) << [
479
+ head(:h),
480
+ tail(:t),
498
481
  ]
499
482
 
500
- alpha(:l) << [
501
- gamma(:l)
483
+ join(:l) << [
484
+ split(:l)
502
485
  ]
503
486
 
504
- solutions = alpha(:p/:q).solve
487
+ solutions = join(:l).solve
505
488
 
506
489
  assert_equal [
507
- { p: 1, q: 2 },
508
- { p: 2, q: 3 },
490
+ { l: [1,2,3] },
491
+ { l: [1,5,6] },
492
+ { l: [4,2,3] },
493
+ { l: [4,5,6] },
494
+ ],solutions
495
+
496
+ solutions = join(:p/:q).solve
497
+
498
+ assert_equal [
499
+ { p: 1, q: [2,3] },
500
+ { p: 1, q: [5,6] },
501
+ { p: 4, q: [2,3] },
502
+ { p: 4, q: [5,6] },
509
503
  ],solutions
510
504
  end
511
505
 
512
506
  it 'should call a builtin predicate' do
513
- skip 'until StandardPredicates added'
514
-
507
+ builtin :write
515
508
  predicate :callwrite
516
509
 
517
510
  callwrite(:MESSAGE) << [
@@ -528,8 +521,7 @@ describe 'Porolog' do
528
521
  end
529
522
 
530
523
  it 'should pass on instantiations between goals' do
531
- skip 'until Rule added'
532
-
524
+ builtin :write
533
525
  predicate :passon, :copy
534
526
 
535
527
  copy(:A,:A).fact!
@@ -553,9 +545,8 @@ describe 'Porolog' do
553
545
  end
554
546
  end
555
547
 
556
- it 'should pass on instantiations between goals' do
557
- skip 'until StandardPredicates added'
558
-
548
+ it 'should implement simple recursion' do
549
+ builtin :write, :is, :gtr
559
550
  predicate :count
560
551
 
561
552
  count(1) << [
@@ -563,10 +554,12 @@ describe 'Porolog' do
563
554
  :CUT
564
555
  ]
565
556
  count(:N) << [
557
+ gtr(:N,1),
566
558
  write("N = ",:N),
567
559
  is(:M,:N){|n| n - 1 },
568
560
  write(" M = ",:M,"\n"),
569
561
  count(:M),
562
+ :CUT
570
563
  ]
571
564
 
572
565
  expected_output = [
@@ -592,8 +585,7 @@ describe 'Porolog' do
592
585
  end
593
586
 
594
587
  it 'should solve tower of Hanoi' do
595
- skip 'until StandardPredicates added'
596
-
588
+ builtin :gtr, :is, :write
597
589
  predicate :move
598
590
 
599
591
  move(1,:X,:Y,:Z) << [
@@ -635,23 +627,22 @@ describe 'Porolog' do
635
627
  end
636
628
 
637
629
  it 'should solve a peeling off predicate' do
638
- skip 'until Rule added'
639
-
640
- predicate :size
630
+ builtin :is
631
+ predicate :peel
641
632
 
642
- size([],0).cut_fact!
643
- size(:H/:T,:N) << [
644
- size(:T,:NT),
633
+ peel([],0).cut_fact!
634
+ peel(:H/:T,:N) << [
635
+ peel(:T,:NT),
645
636
  is(:N,:NT){|nt| nt + 1 },
646
637
  ]
647
638
 
648
- solutions = size([],:N).solve
639
+ solutions = peel([],:N).solve
649
640
 
650
641
  assert_equal [
651
642
  { N: 0 }
652
643
  ],solutions
653
644
 
654
- solutions = size([13,17,19,23],:N).solve
645
+ solutions = peel([13,17,19,23],:N).solve
655
646
 
656
647
  assert_equal [
657
648
  { N: 4 },
@@ -659,47 +650,65 @@ describe 'Porolog' do
659
650
  end
660
651
 
661
652
  it 'should solve tower of Hanoi with list representation' do
662
- skip 'until StandardPredicates added and converted to list representation'
663
653
  # TODO: convert to list representation
664
654
 
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) << [
655
+ builtin :gtr, :is, :append, :write
656
+ predicate :tower, :move
657
+
658
+ tower(1, :X, :Y, :Z, [[:X,:Z]]).fact!
659
+ tower(:N, :X, :Y, :Z, :S) << [
671
660
  gtr(:N,1),
672
661
  is(:M,:N){|n| n - 1 },
673
- move(:M,:X,:Z,:Y),
674
- move(1,:X,:Y,:Q),
675
- move(:M,:Z,:Y,:X),
662
+ tower(:M, :X, :Z, :Y, :S1),
663
+ tower( 1, :X, :Y, :Z, :S2),
664
+ tower(:M, :Y, :X, :Z, :S3),
665
+ append(:S1, :S2, :S12),
666
+ append(:S12, :S3, :S),
676
667
  ]
677
668
 
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
669
+ solutions = tower(3, 'left', 'middle', 'right', :moves).solve
670
+
671
+ expected_solutions = [
672
+ {
673
+ moves: [
674
+ ['left', 'right'],
675
+ ['left', 'middle'],
676
+ ['right', 'middle'],
677
+ ['left', 'right'],
678
+ ['middle', 'left'],
679
+ ['middle', 'right'],
680
+ ['left', 'right']
681
+ ]
682
+ }
683
+ ]
695
684
 
696
- assert_output expected_output do
697
- solutions = move(4,'left','right','center').solve
698
-
699
- assert_equal [
700
- {},
701
- ],solutions
702
- end
685
+ assert_equal expected_solutions, solutions
686
+
687
+ solutions = tower(4, 'left', 'middle', 'right', :moves).solve
688
+
689
+ expected_solutions = [
690
+ {
691
+ moves: [
692
+ ['left', 'middle'],
693
+ ['left', 'right'],
694
+ ['middle', 'right'],
695
+ ['left', 'middle'],
696
+ ['right', 'left'],
697
+ ['right', 'middle'],
698
+ ['left', 'middle'],
699
+ ['left', 'right'],
700
+ ['middle', 'right'],
701
+ ['middle', 'left'],
702
+ ['right', 'left'],
703
+ ['middle', 'right'],
704
+ ['left', 'middle'],
705
+ ['left', 'right'],
706
+ ['middle', 'right']
707
+ ]
708
+ }
709
+ ]
710
+
711
+ assert_equal expected_solutions, solutions
703
712
  end
704
713
 
705
714
  end
@@ -707,20 +716,27 @@ describe 'Porolog' do
707
716
  describe '#solve_for' do
708
717
 
709
718
  it 'should solve a predicate for specified variables' do
710
- skip 'until Rule added'
719
+ predicate :alpha
711
720
 
721
+ alpha(1,2).fact!
722
+
723
+ solutions = alpha(:p,:q).solve_for(:q,:p)
724
+
725
+ assert_equal [[2,1]], solutions
726
+ end
727
+
728
+ it 'should solve a predicate for a specified variable' do
712
729
  predicate :alpha
713
730
 
714
731
  alpha(1,2).fact!
732
+ alpha(3,5).fact!
715
733
 
716
- solutions = alpha(:p,:q).solve_for(:p,:q)
734
+ solutions = alpha(:p,:q).solve_for(:q)
717
735
 
718
- assert_equal [[1,2]], solutions
736
+ assert_equal [2,5], solutions
719
737
  end
720
738
 
721
739
  it 'should solve a predicate with multiple solutions for specified variables' do
722
- skip 'until Rule added'
723
-
724
740
  predicate :alpha
725
741
 
726
742
  alpha(1,2).fact!
@@ -730,12 +746,7 @@ describe 'Porolog' do
730
746
 
731
747
  solutions = alpha(:p,:q).solve_for(:p)
732
748
 
733
- assert_equal [
734
- [1],
735
- [3],
736
- [5],
737
- [5],
738
- ], solutions
749
+ assert_equal [1,3,5,5], solutions
739
750
  end
740
751
 
741
752
  end
@@ -743,20 +754,48 @@ describe 'Porolog' do
743
754
  describe '#valid?' do
744
755
 
745
756
  it 'should return true when a solution is found' do
746
- # TODO: it 'should return true when a solution is found' do
757
+ predicate :f
758
+
759
+ f(3).fact!
760
+
761
+ assert f(3).valid?, name
747
762
  end
748
763
 
749
764
  it 'should return false when no solution is found' do
750
- # TODO: it 'should return false when no solution is found' do
765
+ predicate :f
766
+
767
+ f(1).fact!
768
+ f(2).fact!
769
+ f(4).fact!
770
+ f(5).fact!
771
+
772
+ refute f(3).valid?, name
773
+ end
774
+
775
+ it 'should return false when a falicy is found' do
776
+ predicate :f
777
+
778
+ f(3).falicy!
779
+
780
+ refute f(3).valid?, name
751
781
  end
752
782
 
753
783
  end
754
784
 
755
785
  describe '#dup' do
756
786
 
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
787
+ let(:args1) { pred.(1,'a',0.1,:a,2.2,:b,'b',:C,1234) }
788
+ let(:goal) { args1.goal }
789
+ let(:args2) { args1.dup(goal) }
790
+
791
+ it 'should create a new Arguments' do
792
+ assert_Arguments args1, :pred, [1,'a',0.1,:a,2.2,:b,'b',:C,1234]
793
+
794
+ refute_equal args2.__id__, args1.__id__
795
+ end
796
+
797
+ it 'should variablise the arguments for the goal' do
798
+ assert_Arguments args2, :pred, [1, 'a', 0.1, goal.variable(:a), 2.2, goal.variable(:b), 'b', goal.variable(:C), 1234]
760
799
  end
761
800
 
762
801
  end
@@ -773,14 +812,24 @@ describe 'Porolog' do
773
812
  assert arguments1 == arguments2, 'Arguments with identical predicates and arguments should return true'
774
813
  end
775
814
 
776
- it 'should return false for Arguments with identical predicates and arguments' do
815
+ it 'should return false for Arguments with non-identical arguments' do
777
816
  predicate1 = Predicate.new :omega
778
817
  arguments1 = predicate1.(1,'a',0.1)
779
818
 
780
819
  predicate2 = Predicate.new :omega
781
820
  arguments2 = predicate2.(1,'a',0.2)
782
821
 
783
- refute arguments1 == arguments2, 'Arguments with non-identical predicates and arguments should return false'
822
+ refute arguments1 == arguments2, 'Arguments with non-identical arguments should return false'
823
+ end
824
+
825
+ it 'should return false for Arguments with non-identical predicates' do
826
+ predicate1 = Predicate.new :omega
827
+ arguments1 = predicate1.(1,'a',0.1)
828
+
829
+ predicate2 = Predicate.new :omegb
830
+ arguments2 = predicate2.(1,'a',0.1)
831
+
832
+ refute arguments1 == arguments2, 'Arguments with non-identical predicates should return false'
784
833
  end
785
834
 
786
835
  end