mini_kraken 0.2.02 → 0.3.02
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/.rubocop.yml +378 -333
- data/CHANGELOG.md +52 -0
- data/README.md +19 -19
- data/lib/mini_kraken.rb +0 -1
- data/lib/mini_kraken/atomic/all_atomic.rb +5 -0
- data/lib/mini_kraken/atomic/atomic_term.rb +96 -0
- data/lib/mini_kraken/atomic/k_boolean.rb +42 -0
- data/lib/mini_kraken/{core → atomic}/k_integer.rb +2 -5
- data/lib/mini_kraken/atomic/k_string.rb +17 -0
- data/lib/mini_kraken/{core → atomic}/k_symbol.rb +4 -8
- data/lib/mini_kraken/composite/all_composite.rb +4 -0
- data/lib/mini_kraken/composite/composite_term.rb +27 -0
- data/lib/mini_kraken/composite/cons_cell.rb +299 -0
- data/lib/mini_kraken/composite/cons_cell_visitor.rb +50 -0
- data/lib/mini_kraken/composite/list.rb +32 -0
- data/lib/mini_kraken/core/all_core.rb +8 -0
- data/lib/mini_kraken/core/any_value.rb +31 -7
- data/lib/mini_kraken/core/arity.rb +69 -0
- data/lib/mini_kraken/core/association.rb +29 -4
- data/lib/mini_kraken/core/association_copy.rb +50 -0
- data/lib/mini_kraken/core/base_term.rb +13 -0
- data/lib/mini_kraken/core/blackboard.rb +315 -0
- data/lib/mini_kraken/core/bookmark.rb +46 -0
- data/lib/mini_kraken/core/context.rb +492 -0
- data/lib/mini_kraken/core/duck_fiber.rb +21 -19
- data/lib/mini_kraken/core/entry.rb +40 -0
- data/lib/mini_kraken/core/fail.rb +20 -18
- data/lib/mini_kraken/core/fusion.rb +29 -0
- data/lib/mini_kraken/core/goal.rb +20 -29
- data/lib/mini_kraken/core/log_var.rb +22 -0
- data/lib/mini_kraken/core/log_var_ref.rb +108 -0
- data/lib/mini_kraken/core/nullary_relation.rb +2 -9
- data/lib/mini_kraken/core/parametrized_term.rb +61 -0
- data/lib/mini_kraken/core/relation.rb +14 -28
- data/lib/mini_kraken/core/scope.rb +67 -0
- data/lib/mini_kraken/core/solver_adapter.rb +58 -0
- data/lib/mini_kraken/core/specification.rb +48 -0
- data/lib/mini_kraken/core/succeed.rb +21 -17
- data/lib/mini_kraken/core/symbol_table.rb +137 -0
- data/lib/mini_kraken/core/term.rb +15 -4
- data/lib/mini_kraken/glue/dsl.rb +45 -81
- data/lib/mini_kraken/glue/run_star_expression.rb +28 -30
- data/lib/mini_kraken/rela/all_rela.rb +8 -0
- data/lib/mini_kraken/rela/binary_relation.rb +30 -0
- data/lib/mini_kraken/rela/conde.rb +143 -0
- data/lib/mini_kraken/rela/conj2.rb +65 -0
- data/lib/mini_kraken/rela/def_relation.rb +93 -0
- data/lib/mini_kraken/rela/disj2.rb +70 -0
- data/lib/mini_kraken/rela/fresh.rb +98 -0
- data/lib/mini_kraken/{core → rela}/goal_relation.rb +7 -9
- data/lib/mini_kraken/rela/unify.rb +258 -0
- data/lib/mini_kraken/version.rb +1 -1
- data/mini_kraken.gemspec +2 -2
- data/spec/.rubocop.yml +1 -1
- data/spec/atomic/atomic_term_spec.rb +98 -0
- data/spec/{core → atomic}/k_boolean_spec.rb +19 -34
- data/spec/{core → atomic}/k_symbol_spec.rb +3 -16
- data/spec/composite/cons_cell_spec.rb +225 -0
- data/spec/composite/cons_cell_visitor_spec.rb +158 -0
- data/spec/composite/list_spec.rb +50 -0
- data/spec/core/any_value_spec.rb +52 -0
- data/spec/core/arity_spec.rb +92 -0
- data/spec/core/association_copy_spec.rb +69 -0
- data/spec/core/association_spec.rb +31 -4
- data/spec/core/blackboard_spec.rb +287 -0
- data/spec/core/bookmark_spec.rb +40 -0
- data/spec/core/context_spec.rb +245 -0
- data/spec/core/core_spec.rb +40 -0
- data/spec/core/duck_fiber_spec.rb +16 -46
- data/spec/core/fail_spec.rb +5 -6
- data/spec/core/goal_spec.rb +24 -14
- data/spec/core/log_var_ref_spec.rb +105 -0
- data/spec/core/log_var_spec.rb +64 -0
- data/spec/core/nullary_relation_spec.rb +33 -0
- data/spec/core/parametrized_tem_spec.rb +39 -0
- data/spec/core/relation_spec.rb +33 -0
- data/spec/core/scope_spec.rb +73 -0
- data/spec/core/solver_adapter_spec.rb +70 -0
- data/spec/core/specification_spec.rb +43 -0
- data/spec/core/succeed_spec.rb +5 -5
- data/spec/core/symbol_table_spec.rb +142 -0
- data/spec/glue/dsl_chap1_spec.rb +96 -144
- data/spec/glue/dsl_chap2_spec.rb +350 -0
- data/spec/glue/run_star_expression_spec.rb +82 -906
- data/spec/rela/conde_spec.rb +153 -0
- data/spec/rela/conj2_spec.rb +123 -0
- data/spec/rela/def_relation_spec.rb +119 -0
- data/spec/rela/disj2_spec.rb +117 -0
- data/spec/rela/fresh_spec.rb +147 -0
- data/spec/rela/unify_spec.rb +369 -0
- data/spec/support/factory_atomic.rb +29 -0
- data/spec/support/factory_composite.rb +21 -0
- data/spec/support/factory_methods.rb +11 -26
- metadata +100 -64
- data/lib/mini_kraken/core/association_walker.rb +0 -183
- data/lib/mini_kraken/core/atomic_term.rb +0 -67
- data/lib/mini_kraken/core/base_arg.rb +0 -10
- data/lib/mini_kraken/core/binary_relation.rb +0 -63
- data/lib/mini_kraken/core/composite_goal.rb +0 -46
- data/lib/mini_kraken/core/composite_term.rb +0 -41
- data/lib/mini_kraken/core/conde.rb +0 -143
- data/lib/mini_kraken/core/conj2.rb +0 -79
- data/lib/mini_kraken/core/cons_cell.rb +0 -82
- data/lib/mini_kraken/core/def_relation.rb +0 -50
- data/lib/mini_kraken/core/designation.rb +0 -55
- data/lib/mini_kraken/core/disj2.rb +0 -72
- data/lib/mini_kraken/core/environment.rb +0 -73
- data/lib/mini_kraken/core/equals.rb +0 -156
- data/lib/mini_kraken/core/formal_arg.rb +0 -22
- data/lib/mini_kraken/core/formal_ref.rb +0 -25
- data/lib/mini_kraken/core/freshness.rb +0 -45
- data/lib/mini_kraken/core/goal_arg.rb +0 -12
- data/lib/mini_kraken/core/goal_template.rb +0 -62
- data/lib/mini_kraken/core/k_boolean.rb +0 -35
- data/lib/mini_kraken/core/outcome.rb +0 -53
- data/lib/mini_kraken/core/variable.rb +0 -41
- data/lib/mini_kraken/core/variable_ref.rb +0 -78
- data/lib/mini_kraken/core/vocabulary.rb +0 -442
- data/lib/mini_kraken/glue/fresh_env.rb +0 -75
- data/spec/core/association_walker_spec.rb +0 -192
- data/spec/core/conde_spec.rb +0 -147
- data/spec/core/conj2_spec.rb +0 -114
- data/spec/core/cons_cell_spec.rb +0 -107
- data/spec/core/def_relation_spec.rb +0 -96
- data/spec/core/disj2_spec.rb +0 -99
- data/spec/core/environment_spec.rb +0 -142
- data/spec/core/equals_spec.rb +0 -304
- data/spec/core/goal_template_spec.rb +0 -74
- data/spec/core/outcome_spec.rb +0 -48
- data/spec/core/variable_ref_spec.rb +0 -27
- data/spec/core/variable_spec.rb +0 -35
- data/spec/core/vocabulary_spec.rb +0 -219
- data/spec/glue/fresh_env_spec.rb +0 -62
@@ -0,0 +1,147 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/all_core'
|
5
|
+
|
6
|
+
require_relative '../support/factory_atomic'
|
7
|
+
require_relative '../support/factory_composite'
|
8
|
+
require_relative '../../lib/mini_kraken/rela/all_rela'
|
9
|
+
|
10
|
+
# Load the class under test
|
11
|
+
require_relative '../../lib/mini_kraken/rela/fresh'
|
12
|
+
|
13
|
+
module MiniKraken
|
14
|
+
module Rela
|
15
|
+
describe Fresh do
|
16
|
+
include MiniKraken::FactoryAtomic # Use mix-in module
|
17
|
+
include MiniKraken::FactoryComposite # Use mix-in module
|
18
|
+
subject { Fresh.instance }
|
19
|
+
|
20
|
+
|
21
|
+
def var(aName)
|
22
|
+
Core::LogVar.new(aName)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Convenience method to factor out repeated statements
|
26
|
+
def solve(arg1, arg2)
|
27
|
+
solver = subject.solver_for([arg1, arg2], ctx)
|
28
|
+
solver.resume
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'Initialization:' do
|
32
|
+
it 'should know its relation name' do
|
33
|
+
expect(subject.name).to eq('fresh')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should know its arity (binary)' do
|
37
|
+
expect(subject.arity).to be_binary
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should be frozen' do
|
41
|
+
expect(subject).to be_frozen
|
42
|
+
end
|
43
|
+
end # context
|
44
|
+
|
45
|
+
context 'Provided services:' do
|
46
|
+
let(:ctx) { Core::Context.new }
|
47
|
+
let(:bean) { k_symbol(:bean) }
|
48
|
+
let(:pea) { k_symbol(:pea) }
|
49
|
+
let(:corn) { k_symbol(:corn) }
|
50
|
+
let(:meal) { k_symbol(:meal) }
|
51
|
+
let(:red) { k_symbol(:red) }
|
52
|
+
let(:soup) { k_symbol(:soup) }
|
53
|
+
let(:split) { k_symbol(:split) }
|
54
|
+
let(:fails) { Core::Goal.new(Core::Fail.instance, []) }
|
55
|
+
let(:succeeds) { Core::Goal.new(Core::Succeed.instance, []) }
|
56
|
+
let(:var_q) { var('q') }
|
57
|
+
let(:ref_q) { Core::LogVarRef.new('q') }
|
58
|
+
let(:ref_r) { Core::LogVarRef.new('r') }
|
59
|
+
let(:ref_x) { Core::LogVarRef.new('x') }
|
60
|
+
let(:ref_y) { Core::LogVarRef.new('y') }
|
61
|
+
|
62
|
+
def unify(term1, term2)
|
63
|
+
Core::Goal.new(Unify.instance, [term1, term2])
|
64
|
+
end
|
65
|
+
|
66
|
+
def conj2(term1, term2)
|
67
|
+
Core::Goal.new(Conj2.instance, [term1, term2])
|
68
|
+
end
|
69
|
+
|
70
|
+
def disj2(term1, term2)
|
71
|
+
Core::Goal.new(Disj2.instance, [term1, term2])
|
72
|
+
end
|
73
|
+
|
74
|
+
before(:each) { ctx.add_vars('q') }
|
75
|
+
|
76
|
+
it 'should create a solver' do
|
77
|
+
subgoal = unify(ref_x, ref_q)
|
78
|
+
fresh_goal = Core::Goal.new(subject, [k_string('x'), subgoal])
|
79
|
+
solver = subject.solver_for(fresh_goal.actuals, ctx)
|
80
|
+
expect(solver.resume(ctx)).to be_success
|
81
|
+
current_scope = ctx.symbol_table.current_scope
|
82
|
+
expect(current_scope.defns.include?('x')).to be_truthy
|
83
|
+
expect(current_scope.parent.defns.include?('q')).to be_truthy
|
84
|
+
fusion = ctx.blackboard.move_queue.last
|
85
|
+
expect(fusion).to be_kind_of(Core::Fusion)
|
86
|
+
expect(solver.resume(ctx)).to be_nil
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should allow the nesting of fresh goals' do
|
90
|
+
ref_y = Core::LogVarRef.new('y')
|
91
|
+
subsubgoal = unify(ref_y, ref_q)
|
92
|
+
fresh_subgoal = Core::Goal.new(subject, [k_string('y'), subsubgoal])
|
93
|
+
fresh_goal = Core::Goal.new(subject, [k_string('x'), fresh_subgoal])
|
94
|
+
solver = subject.solver_for(fresh_goal.actuals, ctx)
|
95
|
+
expect(solver.resume(ctx)).to be_success
|
96
|
+
current_scope = ctx.symbol_table.current_scope
|
97
|
+
expect(current_scope.defns.include?('y')).to be_truthy
|
98
|
+
expect(current_scope.parent.defns.include?('x')).to be_truthy
|
99
|
+
expect(current_scope.parent.parent.defns.include?('q')).to be_truthy
|
100
|
+
fusion = ctx.blackboard.move_queue.last
|
101
|
+
expect(fusion).to be_kind_of(Core::Fusion)
|
102
|
+
expect(solver.resume(ctx)).to be_nil
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should create a simple goal' do
|
106
|
+
# Covers frame 1:21
|
107
|
+
# (run* q (fresh (x) (== 'pea q))) ;; => (pea)
|
108
|
+
subgoal = unify(pea, ref_q)
|
109
|
+
goal = Fresh.build_goal('x', subgoal)
|
110
|
+
|
111
|
+
expect(goal).to be_kind_of(Core::Goal)
|
112
|
+
expect(goal.relation).to be_kind_of(Fresh)
|
113
|
+
expect(goal.actuals[0]).to eq('x') # Name of local variable
|
114
|
+
expect(goal.actuals[1]).to eq(subgoal)
|
115
|
+
solver = subject.solver_for(goal.actuals, ctx)
|
116
|
+
expect(solver.resume(ctx)).to be_success
|
117
|
+
result = ctx.build_solution
|
118
|
+
expect(result['q']).to eq(pea)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should create a goal with conjuncted sub-goals' do
|
122
|
+
# Covers inner part of frame 1:78
|
123
|
+
# (fresh (x y)
|
124
|
+
# (disj2
|
125
|
+
# (conj2 (== 'split x) (== 'pea y))
|
126
|
+
# (conj2 (== 'red x) (== 'bean y)))
|
127
|
+
# (== '(,x ,y soup) r)))
|
128
|
+
|
129
|
+
subgoals = [disj2(
|
130
|
+
conj2(unify(split, ref_x), unify(pea, ref_y)),
|
131
|
+
conj2(unify(red, ref_x), unify(bean, ref_y))),
|
132
|
+
unify(cons(ref_x, cons(ref_y, cons(soup))), ref_r)]
|
133
|
+
goal = Fresh.build_goal(%w[x y], subgoals)
|
134
|
+
expect(goal).to be_kind_of(Core::Goal)
|
135
|
+
expect(goal.relation).to be_kind_of(Fresh)
|
136
|
+
expect(goal.actuals[0]).to eq(%w[x y]) # local variable names
|
137
|
+
expect(goal.actuals[1]).to be_kind_of(Core::Goal)
|
138
|
+
|
139
|
+
# Check that the created Conj2 is correct
|
140
|
+
expect(goal.actuals[1].relation).to eq(Conj2.instance)
|
141
|
+
expect(goal.actuals[1].actuals[0]).to eq(subgoals[0])
|
142
|
+
expect(goal.actuals[1].actuals[1]).to eq(subgoals[1])
|
143
|
+
end
|
144
|
+
end # context
|
145
|
+
end # describe
|
146
|
+
end # module
|
147
|
+
end # module
|
@@ -0,0 +1,369 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require_relative '../../lib/mini_kraken/core/log_var'
|
5
|
+
require_relative '../../lib/mini_kraken/core/log_var_ref'
|
6
|
+
|
7
|
+
require_relative '../support/factory_atomic'
|
8
|
+
require_relative '../support/factory_composite'
|
9
|
+
|
10
|
+
# Load the class under test
|
11
|
+
require_relative '../../lib/mini_kraken/rela/unify'
|
12
|
+
|
13
|
+
module MiniKraken
|
14
|
+
module Rela
|
15
|
+
describe Unify do
|
16
|
+
include MiniKraken::FactoryAtomic # Use mix-in module
|
17
|
+
include MiniKraken::FactoryComposite # Use mix-in module
|
18
|
+
|
19
|
+
let(:pea) { k_symbol(:pea) }
|
20
|
+
let(:pea2) { k_symbol(:pea) } # Same value but distinct object
|
21
|
+
let(:pod) { k_symbol(:pod) }
|
22
|
+
let(:null) { cons(nil, nil) }
|
23
|
+
let(:q_ref) { Core::LogVarRef.new('q') }
|
24
|
+
let(:ctx) { Core::Context.new }
|
25
|
+
subject { Unify.instance }
|
26
|
+
|
27
|
+
def var(aName)
|
28
|
+
Core::LogVar.new(aName)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Convenience method to factor out repeated statements
|
32
|
+
def solve(arg1, arg2)
|
33
|
+
solver = subject.solver_for([arg1, arg2], ctx)
|
34
|
+
solver.resume(ctx)
|
35
|
+
end
|
36
|
+
|
37
|
+
before(:each) do
|
38
|
+
ctx.insert(var('q'))
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'Initialization:' do
|
42
|
+
it 'should know its relation name' do
|
43
|
+
expect(subject.name).to eq('unify')
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should know its arity (binary)' do
|
47
|
+
expect(subject.arity).to be_binary
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should be frozen' do
|
51
|
+
expect(subject).to be_frozen
|
52
|
+
end
|
53
|
+
end # context
|
54
|
+
|
55
|
+
context 'Unifying identical or nil terms:' do
|
56
|
+
it 'should succeed for identical arguments' do
|
57
|
+
term = double('anything')
|
58
|
+
result = solve(term, term)
|
59
|
+
|
60
|
+
expect(result).to be_kind_of(Core::Context)
|
61
|
+
expect(result).to be_success
|
62
|
+
expect(result.blackboard).to be_empty
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should succeed for two nil arguments' do
|
66
|
+
result = solve(nil, nil)
|
67
|
+
expect(result).to be_success
|
68
|
+
expect(result.blackboard).to be_empty
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should fail for one nil and one non-nil argument' do
|
72
|
+
term = double('anything')
|
73
|
+
result = solve(term, nil)
|
74
|
+
expect(result).to be_failure
|
75
|
+
|
76
|
+
# Check symmetry
|
77
|
+
result = solve(nil, term)
|
78
|
+
expect(result).to be_failure
|
79
|
+
end
|
80
|
+
end # context
|
81
|
+
|
82
|
+
context 'Unifying atomic terms:' do
|
83
|
+
it 'should unify symbols of same value' do
|
84
|
+
# Identical literals
|
85
|
+
result = solve(pea, pea)
|
86
|
+
expect(result).to be_success
|
87
|
+
|
88
|
+
pea_bis = k_symbol(:pea)
|
89
|
+
result = solve(pea, pea_bis)
|
90
|
+
expect(result).to be_success
|
91
|
+
expect(result.blackboard).to be_empty
|
92
|
+
|
93
|
+
true_a = k_boolean(false)
|
94
|
+
true_b = k_boolean(false)
|
95
|
+
result = solve(true_a, true_b)
|
96
|
+
expect(result).to be_success
|
97
|
+
expect(result.blackboard).to be_empty
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should fail for atomic terms with different values' do
|
101
|
+
result = solve(pea, pod)
|
102
|
+
expect(result).to be_failure
|
103
|
+
|
104
|
+
true_t = k_boolean(true)
|
105
|
+
false_t = k_boolean(false)
|
106
|
+
result = solve(true_t, false_t)
|
107
|
+
expect(result).to be_failure
|
108
|
+
end
|
109
|
+
end # context
|
110
|
+
|
111
|
+
context 'Unifying composite with atomic term:' do
|
112
|
+
it 'should fail to unify a composite to an atomic term' do
|
113
|
+
pair = cons(double('car-fake'), double('cdr-fake'))
|
114
|
+
|
115
|
+
result = solve(pair, pea)
|
116
|
+
expect(result).to be_failure
|
117
|
+
expect(result.blackboard).to be_empty
|
118
|
+
|
119
|
+
# Check symmetry
|
120
|
+
result = solve(pea, pair)
|
121
|
+
expect(result).to be_failure
|
122
|
+
expect(result.blackboard).to be_empty
|
123
|
+
end
|
124
|
+
end # context
|
125
|
+
|
126
|
+
context 'Unifying null list with a term:' do
|
127
|
+
it 'should unify two null lists' do
|
128
|
+
null2 = cons(nil, nil)
|
129
|
+
|
130
|
+
result = solve(null, null2)
|
131
|
+
expect(result).to be_success
|
132
|
+
expect(result.blackboard).to be_empty
|
133
|
+
end
|
134
|
+
|
135
|
+
it "shouldn't unify a null list with any non null composite" do
|
136
|
+
# Fail to unify null with a non-null list
|
137
|
+
list1 = make_list(double('dummy'))
|
138
|
+
result = solve(null, list1)
|
139
|
+
|
140
|
+
expect(result).to be_failure
|
141
|
+
|
142
|
+
# Check symmetry
|
143
|
+
result = solve(list1, null)
|
144
|
+
expect(result).to be_failure
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'should unify null list with fresh variable' do
|
148
|
+
result = solve(null, q_ref)
|
149
|
+
|
150
|
+
expect(result).to be_success
|
151
|
+
expect(result.blackboard).not_to be_empty
|
152
|
+
expect(result.associations_for('q').first.value).to eq(null)
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'should unify null list with variable bound to null list' do
|
156
|
+
solve(null, q_ref) # q is bound to null list
|
157
|
+
|
158
|
+
# Attempting to unify again null list with same variable is OK
|
159
|
+
result = solve(null, q_ref)
|
160
|
+
expect(result).to be_success
|
161
|
+
|
162
|
+
# Success, but no redundant association is created...
|
163
|
+
expect(result.blackboard.move_queue.size).to eq(1)
|
164
|
+
end
|
165
|
+
|
166
|
+
it "shouldn't unify a null list with a variable bound to atomic" do
|
167
|
+
ctx.associate('q', pea)
|
168
|
+
result = solve(null, q_ref)
|
169
|
+
expect(result).to be_failure
|
170
|
+
end
|
171
|
+
|
172
|
+
it "shouldn't unify a null list with a variable bound to composite" do
|
173
|
+
ctx.associate('q', cons(pea))
|
174
|
+
result = solve(null, q_ref)
|
175
|
+
expect(result).to be_failure
|
176
|
+
end
|
177
|
+
end # context
|
178
|
+
|
179
|
+
context 'Unifying two non-null composite terms:' do
|
180
|
+
it 'should unify two one-element lists with same atomic terms' do
|
181
|
+
list_pea = cons(pea)
|
182
|
+
list_pea2 = cons(pea2)
|
183
|
+
result = solve(list_pea, list_pea2)
|
184
|
+
|
185
|
+
expect(result).to be_success
|
186
|
+
expect(result.blackboard).to be_empty
|
187
|
+
end
|
188
|
+
|
189
|
+
it "shoudn't unify two one-element lists with unequal atomic terms" do
|
190
|
+
list_pea = cons(pea)
|
191
|
+
list_pod = cons(pod)
|
192
|
+
result = solve(list_pea, list_pod)
|
193
|
+
|
194
|
+
expect(result).to be_failure
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'should unify two pairs with same atomic terms' do
|
198
|
+
pair1 = cons(pea, pea)
|
199
|
+
pair2 = cons(pea, pea2)
|
200
|
+
result = solve(pair1, pair2)
|
201
|
+
|
202
|
+
expect(result).to be_success
|
203
|
+
expect(result.blackboard).to be_empty
|
204
|
+
end
|
205
|
+
|
206
|
+
it "shoudn't unify two pairs with unequal atomic terms" do
|
207
|
+
pair_a = cons(pea, pea)
|
208
|
+
pair_b = cons(pea, pod)
|
209
|
+
result = solve(pair_a, pair_b)
|
210
|
+
|
211
|
+
expect(result).to be_failure
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'should unify two element lists with same atomic terms' do
|
215
|
+
# Two element lists
|
216
|
+
list_a = make_list(pea, pea)
|
217
|
+
list_b = make_list(pea, pea2)
|
218
|
+
result = solve(list_a, list_b)
|
219
|
+
|
220
|
+
expect(result).to be_success
|
221
|
+
expect(result.blackboard).to be_empty
|
222
|
+
end
|
223
|
+
|
224
|
+
it "shoudn't unify two element lists with with unequal atomic terms" do
|
225
|
+
# Two element lists
|
226
|
+
list_a = make_list(pea, pea)
|
227
|
+
list_b = make_list(pea, pod)
|
228
|
+
result = solve(list_a, list_b)
|
229
|
+
|
230
|
+
expect(result).to be_failure
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'should unify composites with one fresh variable' do
|
234
|
+
list_a = make_list(pea, pod)
|
235
|
+
list_b = make_list(pea, q_ref)
|
236
|
+
result = solve(list_a, list_b)
|
237
|
+
|
238
|
+
expect(result).to be_success
|
239
|
+
expect(result.blackboard.move_queue.size).to eq(1)
|
240
|
+
expect(ctx.associations_for('q').first.value).to eq(pod)
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'should unify composites with redundant unification' do
|
244
|
+
list_a = make_list(pea, pea2, pod)
|
245
|
+
|
246
|
+
# Twist: q is paired twice to :pea, which is OK
|
247
|
+
list_b = make_list(q_ref, q_ref, pod)
|
248
|
+
result = solve(list_a, list_b)
|
249
|
+
|
250
|
+
expect(result).to be_success
|
251
|
+
|
252
|
+
# Only one association is created...
|
253
|
+
expect(result.blackboard.move_queue.size).to eq(1)
|
254
|
+
expect(ctx.associations_for('q').first.value).to eq(pea)
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'should unify composites with same variables at same positions' do
|
258
|
+
# Case: q is a fresh variable
|
259
|
+
q_ref2 = Core::LogVarRef.new('q') # Other ref to same variable
|
260
|
+
list_a = make_list(pea, pod, q_ref)
|
261
|
+
list_b = make_list(pea, pod, q_ref2)
|
262
|
+
result = solve(list_a, list_b)
|
263
|
+
|
264
|
+
expect(result).to be_success
|
265
|
+
expect(result.blackboard).to be_empty # No association created
|
266
|
+
|
267
|
+
# Case: q is a bound variable
|
268
|
+
ctx.associate('q', pea)
|
269
|
+
expect(ctx.blackboard.move_queue.size).to eq(1)
|
270
|
+
result = solve(list_a, list_b)
|
271
|
+
|
272
|
+
expect(result).to be_success
|
273
|
+
expect(ctx.blackboard.move_queue.size).to eq(1) # No new association
|
274
|
+
end
|
275
|
+
end # context
|
276
|
+
|
277
|
+
|
278
|
+
context 'Unifying variable with atomic term:' do
|
279
|
+
it 'should unify a fresh variable to an atomic term' do
|
280
|
+
result = solve(q_ref, pea)
|
281
|
+
|
282
|
+
expect(result).to be_success
|
283
|
+
expect(result.blackboard).not_to be_empty
|
284
|
+
expect(ctx.associations_for('q').size).to eq(1)
|
285
|
+
expect(ctx.associations_for('q').first.value).to eq(pea)
|
286
|
+
end
|
287
|
+
|
288
|
+
it 'should unify a left-handed bound variable to the same atomic t.' do
|
289
|
+
solve(q_ref, pea)
|
290
|
+
result = solve(q_ref, pea) # Try to associate with 'pea' again...
|
291
|
+
expect(result).to be_success
|
292
|
+
|
293
|
+
# But no redundant association is created...
|
294
|
+
expect(ctx.associations_for('q').size).to eq(1)
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'should unify a right-handed bound variable to the same atomic t.' do
|
298
|
+
solve(pea, q_ref)
|
299
|
+
result = solve(pea, q_ref) # Try to associate with 'pea' again...
|
300
|
+
expect(result).to be_success
|
301
|
+
|
302
|
+
# No redundant association was added...
|
303
|
+
expect(ctx.associations_for('q').size).to eq(1)
|
304
|
+
end
|
305
|
+
|
306
|
+
it "shouldn't unify a variable bound to another atomic term" do
|
307
|
+
solve(q_ref, pea) # q will be bound to :pea
|
308
|
+
|
309
|
+
# Trying a second time with another value should fail...
|
310
|
+
result = solve(q_ref, pod)
|
311
|
+
expect(result).to be_failure # Side effect: associations are removed
|
312
|
+
expect(result.blackboard).to be_empty
|
313
|
+
end
|
314
|
+
end # context
|
315
|
+
|
316
|
+
|
317
|
+
context 'Unifying variable with composite term:' do
|
318
|
+
it 'should unify a fresh variable to a composite term' do
|
319
|
+
list = make_list(pea, pod)
|
320
|
+
result = solve(q_ref, list)
|
321
|
+
|
322
|
+
expect(result).to be_success
|
323
|
+
expect(result.blackboard).not_to be_empty
|
324
|
+
expect(ctx.associations_for('q').size).to eq(1)
|
325
|
+
expect(ctx.associations_for('q').first.value).to eq(list)
|
326
|
+
end
|
327
|
+
|
328
|
+
it 'should unify a bound variable again with equal composite' do
|
329
|
+
list_a = make_list(cons(pea, pod), pea2)
|
330
|
+
list_b = make_list(cons(pea2, pod), pea)
|
331
|
+
result = solve(q_ref, list_a)
|
332
|
+
|
333
|
+
expect(result).to be_success
|
334
|
+
expect(result.blackboard).not_to be_empty
|
335
|
+
expect(ctx.associations_for('q').first.value).to eq(list_a)
|
336
|
+
|
337
|
+
result = solve(q_ref, list_b)
|
338
|
+
expect(result).to be_success
|
339
|
+
expect(ctx.associations_for('q').size).to eq(1)
|
340
|
+
end
|
341
|
+
|
342
|
+
it "shouldn't unify a bound variable to something different" do
|
343
|
+
list_a = make_list(cons(pea, pod), pea2)
|
344
|
+
solve(q_ref, list_a)
|
345
|
+
|
346
|
+
list_b = make_list(cons(pod, pod), pea)
|
347
|
+
result = solve(q_ref, list_b)
|
348
|
+
expect(result).to be_failure
|
349
|
+
end
|
350
|
+
end # context
|
351
|
+
|
352
|
+
context 'Unifying variable with another one:' do
|
353
|
+
it 'should unify one left-handed fresh variable to a bound variable' do
|
354
|
+
liste = make_list(cons(pea, pod), pea2)
|
355
|
+
solve(q_ref, liste)
|
356
|
+
|
357
|
+
ctx.add_vars('x')
|
358
|
+
x_ref = Core::LogVarRef.new('x')
|
359
|
+
result = solve(x_ref, q_ref)
|
360
|
+
queue = result.blackboard.move_queue
|
361
|
+
|
362
|
+
expect(queue[-2]).to be_kind_of(Core::Fusion)
|
363
|
+
expect(queue[-1]).to be_kind_of(Core::AssociationCopy)
|
364
|
+
expect(queue[-1].value).to be_equal(liste)
|
365
|
+
end
|
366
|
+
end # context
|
367
|
+
end # describe
|
368
|
+
end # module
|
369
|
+
end # module
|