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.
- checksums.yaml +4 -4
- data/README.md +30 -5
- data/Rakefile +7 -2
- data/bin/porolog +58 -1
- data/coverage/badge.svg +1 -1
- data/coverage/index.html +76733 -2638
- data/doc/Array.html +1066 -0
- data/doc/Object.html +674 -0
- data/doc/Porolog.html +4153 -74
- data/doc/Symbol.html +501 -0
- data/doc/_index.html +280 -6
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +34 -39
- data/doc/index.html +34 -39
- data/doc/method_list.html +1337 -57
- data/doc/top-level-namespace.html +4 -2
- data/lib/porolog.rb +1144 -4
- data/lib/porolog/arguments.rb +28 -24
- data/lib/porolog/core_ext.rb +188 -0
- data/lib/porolog/error.rb +9 -0
- data/lib/porolog/goal.rb +357 -0
- data/lib/porolog/instantiation.rb +346 -0
- data/lib/porolog/predicate.rb +74 -31
- data/lib/porolog/predicate/builtin.rb +825 -0
- data/lib/porolog/rule.rb +162 -0
- data/lib/porolog/scope.rb +4 -4
- data/lib/porolog/tail.rb +57 -0
- data/lib/porolog/value.rb +105 -0
- data/lib/porolog/variable.rb +325 -0
- data/test/porolog/arguments_test.rb +244 -195
- data/test/porolog/core_ext_test.rb +290 -0
- data/test/porolog/goal_test.rb +891 -0
- data/test/porolog/instantiation_test.rb +910 -0
- data/test/porolog/porolog_test.rb +2376 -13
- data/test/porolog/predicate/builtin_test.rb +1340 -0
- data/test/porolog/predicate_test.rb +84 -30
- data/test/porolog/rule_test.rb +527 -0
- data/test/porolog/scope_test.rb +0 -2
- data/test/porolog/tail_test.rb +127 -0
- data/test/porolog/value_test.rb +315 -0
- data/test/porolog/variable_test.rb +1614 -0
- data/test/samples_test.rb +277 -0
- data/test/test_helper.rb +115 -0
- 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
|
-
|
22
|
-
|
23
|
-
|
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
|
34
|
-
args5 = Arguments.new
|
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
|
-
|
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
|
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
|
-
|
69
|
+
# -- No Arguments --
|
70
|
+
assert_equal 0, Arguments.arguments.size
|
68
71
|
|
69
|
-
|
70
|
-
arguments1 = Arguments.new
|
72
|
+
# -- One Arguments --
|
73
|
+
arguments1 = Arguments.new pred1, [:x,:y,:z]
|
71
74
|
|
72
|
-
assert_equal 1,
|
75
|
+
assert_equal 1, Arguments.arguments.size
|
73
76
|
assert_Arguments Arguments.arguments.last, :p, [:x,:y,:z]
|
74
77
|
|
75
|
-
|
76
|
-
arguments2 = Arguments.new
|
78
|
+
# -- Two Arguments --
|
79
|
+
arguments2 = Arguments.new pred2, [:a,:b,:c,:d]
|
77
80
|
|
78
|
-
assert_equal 2,
|
81
|
+
assert_equal 2, Arguments.arguments.size
|
79
82
|
assert_Arguments Arguments.arguments.last, :q, [:a,:b,:c,:d]
|
80
83
|
|
81
|
-
|
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
|
-
|
90
|
-
arguments = Arguments.new predicate, [:x,:y,:z]
|
93
|
+
arguments = Arguments.new pred, [:x,:y,:z]
|
91
94
|
|
92
|
-
assert_equal
|
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
|
-
|
98
|
-
|
99
|
-
|
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
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
126
|
-
|
127
|
-
|
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
|
-
|
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 '[
|
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
|
-
|
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 '[
|
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
|
-
|
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 '[
|
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
|
-
|
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 '[
|
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
|
-
|
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 '[
|
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
|
-
|
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 = "[
|
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,
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
319
|
-
|
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
|
-
|
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
|
-
|
342
|
-
|
343
|
-
predicate :alpha
|
318
|
+
predicate :simple
|
344
319
|
|
345
|
-
|
346
|
-
|
320
|
+
simple(1,2).fact!
|
321
|
+
simple(3,4).fact!
|
347
322
|
|
348
|
-
solutions =
|
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
|
-
|
358
|
-
|
359
|
-
predicate :alpha
|
332
|
+
predicate :basic
|
360
333
|
|
361
|
-
|
362
|
-
|
334
|
+
basic([1,2,3]).fact!
|
335
|
+
basic([3,4,5]).fact!
|
363
336
|
|
364
|
-
solutions =
|
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
|
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
|
397
|
-
|
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
|
-
|
471
|
+
predicate :join, :split, :head, :tail
|
489
472
|
|
490
|
-
|
473
|
+
head(1).fact!
|
474
|
+
head(4).fact!
|
475
|
+
tail([2,3]).fact!
|
476
|
+
tail([5,6]).fact!
|
491
477
|
|
492
|
-
|
493
|
-
|
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
|
-
|
501
|
-
|
483
|
+
join(:l) << [
|
484
|
+
split(:l)
|
502
485
|
]
|
503
486
|
|
504
|
-
solutions =
|
487
|
+
solutions = join(:l).solve
|
505
488
|
|
506
489
|
assert_equal [
|
507
|
-
{
|
508
|
-
{
|
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
|
-
|
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
|
-
|
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
|
557
|
-
|
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
|
-
|
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
|
-
|
639
|
-
|
640
|
-
predicate :size
|
630
|
+
builtin :is
|
631
|
+
predicate :peel
|
641
632
|
|
642
|
-
|
643
|
-
|
644
|
-
|
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 =
|
639
|
+
solutions = peel([],:N).solve
|
649
640
|
|
650
641
|
assert_equal [
|
651
642
|
{ N: 0 }
|
652
643
|
],solutions
|
653
644
|
|
654
|
-
solutions =
|
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
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
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
|
-
|
674
|
-
|
675
|
-
|
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
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
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
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
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
|
-
|
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(:
|
734
|
+
solutions = alpha(:p,:q).solve_for(:q)
|
717
735
|
|
718
|
-
assert_equal [
|
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
|
-
|
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
|
-
|
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
|
-
|
758
|
-
|
759
|
-
|
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
|
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
|
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
|