mini_kraken 0.2.04 → 0.3.00

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/README.md +16 -16
  4. data/lib/mini_kraken/atomic/all_atomic.rb +1 -0
  5. data/lib/mini_kraken/atomic/atomic_term.rb +32 -17
  6. data/lib/mini_kraken/atomic/k_integer.rb +0 -4
  7. data/lib/mini_kraken/atomic/k_string.rb +17 -0
  8. data/lib/mini_kraken/atomic/k_symbol.rb +0 -6
  9. data/lib/mini_kraken/composite/all_composite.rb +4 -0
  10. data/lib/mini_kraken/composite/composite_term.rb +2 -18
  11. data/lib/mini_kraken/composite/cons_cell.rb +178 -11
  12. data/lib/mini_kraken/composite/cons_cell_visitor.rb +12 -64
  13. data/lib/mini_kraken/composite/list.rb +32 -0
  14. data/lib/mini_kraken/core/all_core.rb +8 -0
  15. data/lib/mini_kraken/core/any_value.rb +31 -7
  16. data/lib/mini_kraken/core/arity.rb +69 -0
  17. data/lib/mini_kraken/core/association.rb +29 -4
  18. data/lib/mini_kraken/core/association_copy.rb +50 -0
  19. data/lib/mini_kraken/core/base_term.rb +13 -0
  20. data/lib/mini_kraken/core/blackboard.rb +315 -0
  21. data/lib/mini_kraken/core/bookmark.rb +46 -0
  22. data/lib/mini_kraken/core/context.rb +624 -0
  23. data/lib/mini_kraken/core/duck_fiber.rb +21 -19
  24. data/lib/mini_kraken/core/entry.rb +40 -0
  25. data/lib/mini_kraken/core/fail.rb +20 -18
  26. data/lib/mini_kraken/core/fusion.rb +29 -0
  27. data/lib/mini_kraken/core/goal.rb +20 -29
  28. data/lib/mini_kraken/core/log_var.rb +4 -30
  29. data/lib/mini_kraken/core/log_var_ref.rb +72 -48
  30. data/lib/mini_kraken/core/nullary_relation.rb +2 -9
  31. data/lib/mini_kraken/core/parametrized_term.rb +61 -0
  32. data/lib/mini_kraken/core/relation.rb +14 -28
  33. data/lib/mini_kraken/core/scope.rb +67 -0
  34. data/lib/mini_kraken/core/solver_adapter.rb +58 -0
  35. data/lib/mini_kraken/core/specification.rb +48 -0
  36. data/lib/mini_kraken/core/succeed.rb +21 -17
  37. data/lib/mini_kraken/core/symbol_table.rb +137 -0
  38. data/lib/mini_kraken/core/term.rb +15 -4
  39. data/lib/mini_kraken/glue/dsl.rb +35 -69
  40. data/lib/mini_kraken/glue/run_star_expression.rb +28 -30
  41. data/lib/mini_kraken/rela/all_rela.rb +8 -0
  42. data/lib/mini_kraken/rela/binary_relation.rb +30 -0
  43. data/lib/mini_kraken/rela/conde.rb +146 -0
  44. data/lib/mini_kraken/rela/conj2.rb +65 -0
  45. data/lib/mini_kraken/rela/def_relation.rb +64 -0
  46. data/lib/mini_kraken/rela/disj2.rb +70 -0
  47. data/lib/mini_kraken/rela/fresh.rb +98 -0
  48. data/lib/mini_kraken/{core → rela}/goal_relation.rb +6 -8
  49. data/lib/mini_kraken/rela/unify.rb +258 -0
  50. data/lib/mini_kraken/version.rb +1 -1
  51. data/spec/atomic/atomic_term_spec.rb +23 -20
  52. data/spec/atomic/k_symbol_spec.rb +0 -5
  53. data/spec/composite/cons_cell_spec.rb +116 -0
  54. data/spec/composite/cons_cell_visitor_spec.rb +16 -3
  55. data/spec/composite/list_spec.rb +50 -0
  56. data/spec/core/any_value_spec.rb +52 -0
  57. data/spec/core/arity_spec.rb +91 -0
  58. data/spec/core/association_copy_spec.rb +69 -0
  59. data/spec/core/association_spec.rb +25 -0
  60. data/spec/core/blackboard_spec.rb +287 -0
  61. data/spec/core/bookmark_spec.rb +40 -0
  62. data/spec/core/context_spec.rb +221 -0
  63. data/spec/core/core_spec.rb +40 -0
  64. data/spec/core/duck_fiber_spec.rb +22 -46
  65. data/spec/core/fail_spec.rb +5 -6
  66. data/spec/core/goal_spec.rb +20 -11
  67. data/spec/core/log_var_ref_spec.rb +80 -5
  68. data/spec/core/log_var_spec.rb +35 -6
  69. data/spec/core/nullary_relation_spec.rb +33 -0
  70. data/spec/core/parametrized_tem_spec.rb +39 -0
  71. data/spec/core/relation_spec.rb +33 -0
  72. data/spec/core/scope_spec.rb +73 -0
  73. data/spec/core/solver_adapter_spec.rb +70 -0
  74. data/spec/core/specification_spec.rb +43 -0
  75. data/spec/core/succeed_spec.rb +5 -5
  76. data/spec/core/symbol_table_spec.rb +142 -0
  77. data/spec/glue/dsl_chap1_spec.rb +88 -99
  78. data/spec/glue/dsl_chap2_spec.rb +59 -41
  79. data/spec/glue/run_star_expression_spec.rb +69 -896
  80. data/spec/{core → rela}/conde_spec.rb +50 -46
  81. data/spec/rela/conj2_spec.rb +123 -0
  82. data/spec/rela/def_relation_spec.rb +119 -0
  83. data/spec/rela/disj2_spec.rb +117 -0
  84. data/spec/rela/fresh_spec.rb +147 -0
  85. data/spec/rela/unify_spec.rb +369 -0
  86. data/spec/support/factory_atomic.rb +7 -0
  87. data/spec/support/factory_composite.rb +21 -0
  88. metadata +71 -48
  89. data/lib/mini_kraken/core/association_walker.rb +0 -183
  90. data/lib/mini_kraken/core/base_arg.rb +0 -10
  91. data/lib/mini_kraken/core/binary_relation.rb +0 -63
  92. data/lib/mini_kraken/core/composite_goal.rb +0 -46
  93. data/lib/mini_kraken/core/conde.rb +0 -143
  94. data/lib/mini_kraken/core/conj2.rb +0 -79
  95. data/lib/mini_kraken/core/def_relation.rb +0 -53
  96. data/lib/mini_kraken/core/designation.rb +0 -55
  97. data/lib/mini_kraken/core/disj2.rb +0 -72
  98. data/lib/mini_kraken/core/environment.rb +0 -73
  99. data/lib/mini_kraken/core/equals.rb +0 -191
  100. data/lib/mini_kraken/core/formal_arg.rb +0 -22
  101. data/lib/mini_kraken/core/formal_ref.rb +0 -25
  102. data/lib/mini_kraken/core/freshness.rb +0 -45
  103. data/lib/mini_kraken/core/goal_arg.rb +0 -12
  104. data/lib/mini_kraken/core/goal_template.rb +0 -102
  105. data/lib/mini_kraken/core/outcome.rb +0 -63
  106. data/lib/mini_kraken/core/tap.rb +0 -46
  107. data/lib/mini_kraken/core/vocabulary.rb +0 -446
  108. data/lib/mini_kraken/glue/fresh_env.rb +0 -108
  109. data/lib/mini_kraken/glue/fresh_env_factory.rb +0 -83
  110. data/spec/core/association_walker_spec.rb +0 -194
  111. data/spec/core/conj2_spec.rb +0 -116
  112. data/spec/core/def_relation_spec.rb +0 -99
  113. data/spec/core/disj2_spec.rb +0 -100
  114. data/spec/core/environment_spec.rb +0 -144
  115. data/spec/core/equals_spec.rb +0 -319
  116. data/spec/core/goal_template_spec.rb +0 -74
  117. data/spec/core/outcome_spec.rb +0 -56
  118. data/spec/core/vocabulary_spec.rb +0 -220
  119. data/spec/glue/fresh_env_factory_spec.rb +0 -99
  120. data/spec/glue/fresh_env_spec.rb +0 -62
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require_relative '../support/factory_atomic'
5
+ require_relative '../../lib/mini_kraken/core/context'
6
+ require_relative '../../lib/mini_kraken/core/log_var'
7
+ require_relative '../../lib/mini_kraken/core/log_var_ref'
8
+
9
+ # Load the class under test
10
+ require_relative '../../lib/mini_kraken/core/association_copy'
11
+
12
+ module MiniKraken
13
+ module Core
14
+ describe AssociationCopy do
15
+ include MiniKraken::FactoryAtomic # Use mix-in module
16
+
17
+ let(:pea) { k_symbol(:pea) }
18
+ let(:q_assoc) { Association.new('q', pea) }
19
+ subject { AssociationCopy.new('q_x', q_assoc) }
20
+
21
+ context 'Initialization:' do
22
+ it 'should be initialized with a name and an association' do
23
+ expect { AssociationCopy.new('q_x', q_assoc) }.not_to raise_error
24
+ end
25
+
26
+ it 'should be initialized with a variable and an association' do
27
+ q_x_var = LogVar.new('q_x')
28
+ expect { AssociationCopy.new(q_x_var, q_assoc) }.not_to raise_error
29
+ end
30
+
31
+ it 'should know the internal variable name' do
32
+ expect(subject.i_name).to eq('q_x')
33
+ end
34
+
35
+ it 'should know the associated value' do
36
+ expect(subject.value).to eq(pea)
37
+ end
38
+ end # context
39
+
40
+ context 'Provided services:' do
41
+ let(:ctx) { Context.new }
42
+
43
+ it 'should tell whether the associated value is pinned' do
44
+ ctx.add_vars(%w[q x q_x])
45
+ expect(subject).to be_pinned(ctx)
46
+
47
+ a = Association.new(ctx.lookup('q'), LogVarRef.new('x'))
48
+ instance = AssociationCopy.new(ctx.lookup('q_x'), a)
49
+ expect(instance).not_to be_pinned(ctx)
50
+ end
51
+
52
+ it 'should tell whether the associated value is floating' do
53
+ ctx.add_vars(%w[q x q_x])
54
+
55
+ expect(subject).not_to be_floating(ctx)
56
+ end
57
+
58
+ it 'should retrieve the dependencies in its value' do
59
+ expect(subject.dependencies(ctx)).to be_empty
60
+
61
+ ctx.add_vars(%w[q x q_x])
62
+ a = Association.new(ctx.lookup('q'), LogVarRef.new('x'))
63
+ instance = AssociationCopy.new(ctx.lookup('q_x'), a)
64
+ expect(instance.dependencies(ctx).size).to eq(1)
65
+ end
66
+ end # context
67
+ end # describe
68
+ end # module
69
+ end # module
@@ -2,7 +2,9 @@
2
2
 
3
3
  require_relative '../spec_helper' # Use the RSpec framework
4
4
  require_relative '../support/factory_atomic'
5
+ require_relative '../../lib/mini_kraken/core/context'
5
6
  require_relative '../../lib/mini_kraken/core/log_var'
7
+ require_relative '../../lib/mini_kraken/core/log_var_ref'
6
8
 
7
9
  # Load the class under test
8
10
  require_relative '../../lib/mini_kraken/core/association'
@@ -34,6 +36,29 @@ module MiniKraken
34
36
  end # context
35
37
 
36
38
  context 'Provided services:' do
39
+ let(:ctx) { Context.new }
40
+
41
+ it 'should tell whether the associated value is pinned' do
42
+ ctx.add_vars(%w[q x])
43
+
44
+ expect(subject).to be_pinned(ctx)
45
+ instance = Association.new(ctx.lookup('q'), LogVarRef.new('x'))
46
+ expect(instance).not_to be_pinned(ctx)
47
+ end
48
+
49
+ it 'should tell whether the associated value is floating' do
50
+ ctx.add_vars(%w[q x])
51
+
52
+ expect(subject).not_to be_floating(ctx)
53
+ end
54
+
55
+ it 'should retrieve the dependencies in its value' do
56
+ expect(subject.dependencies(ctx)).to be_empty
57
+
58
+ ctx.add_vars(%w[q x])
59
+ instance = Association.new(ctx.lookup('q'), LogVarRef.new('x'))
60
+ expect(instance.dependencies(ctx).size).to eq(1)
61
+ end
37
62
  end # context
38
63
  end # describe
39
64
  end # module
@@ -0,0 +1,287 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require_relative '../support/factory_atomic'
5
+ require_relative '../../lib/mini_kraken/core/log_var_ref'
6
+ require_relative '../../lib/mini_kraken/core/scope'
7
+ require_relative '../../lib/mini_kraken/composite/cons_cell'
8
+
9
+ # Load the class under test
10
+ require_relative '../../lib/mini_kraken/core/blackboard'
11
+
12
+ module MiniKraken
13
+ module Core
14
+ describe Blackboard do
15
+ include MiniKraken::FactoryAtomic # Use mix-in module
16
+ subject { Blackboard.new }
17
+
18
+ context 'Initialization:' do
19
+ it 'should be initialized without argument' do
20
+ expect { Blackboard.new }.not_to raise_error
21
+ end
22
+
23
+ it "shouldn't have internal name entry at initialization" do
24
+ expect(subject.i_name2moves).to be_empty
25
+ end
26
+
27
+ it 'should have an empty association queue at initialization' do
28
+ expect(subject.move_queue).to be_empty
29
+ end
30
+
31
+ it 'should be empty at initialization' do
32
+ expect(subject).to be_empty
33
+ end
34
+
35
+ it 'should be ready to assign a serial number' do
36
+ expect(subject.next_serial_num).to be_zero
37
+ end
38
+
39
+ it 'should have its resultant attribute un-initialized' do
40
+ expect(subject.resultant).to be_nil
41
+ end
42
+ end # context
43
+
44
+ context 'Provided services:' do
45
+ let(:a_ser_num) { 42 }
46
+ let(:pea) { k_symbol(:pea) }
47
+ let(:pod) { k_symbol(:pod) }
48
+ let(:x_assoc) { Core::Association.new('x', pea) }
49
+ let(:y_assoc) { Core::Association.new('y', pod) }
50
+ let(:z_assoc) { Core::Association.new('z', pea) }
51
+
52
+ def var_ref(aName)
53
+ LogVarRef.new(aName)
54
+ end
55
+
56
+ def cons(car, cdr = nil)
57
+ Composite::ConsCell.new(car, cdr)
58
+ end
59
+
60
+ it 'should allow the enqueuing of one association' do
61
+ expect { subject.enqueue_association(x_assoc) }.not_to raise_error
62
+ expect(subject.i_name2moves).not_to be_empty
63
+ expect(subject.move_queue).not_to be_empty
64
+ expect(subject.i_name2moves['x']).to be_kind_of(Array)
65
+ expect(subject.i_name2moves['x'].first).to eq(0)
66
+ expect(subject.last_move).to eq(x_assoc)
67
+ end
68
+
69
+ it 'should allow the enqueuing of multiple associations' do
70
+ expect(subject.enqueue_association(x_assoc)).to eq(x_assoc)
71
+ expect { subject.enqueue_association(y_assoc) }.not_to raise_error
72
+ expect(subject.i_name2moves.size).to eq(2)
73
+ expect(subject.move_queue.size).to eq(2)
74
+ expect(subject.i_name2moves['y']).to be_kind_of(Array)
75
+ expect(subject.i_name2moves['y'].first).to eq(1)
76
+ expect(subject.last_move).to eq(y_assoc)
77
+ end
78
+
79
+ it 'should allow the enqueuing of multiple associations for same i_name' do
80
+ subject.enqueue_association(x_assoc)
81
+
82
+ x_assoc_b = Core::Association.new('x', double('something'))
83
+ expect { subject.enqueue_association(x_assoc_b) }.not_to raise_error
84
+ expect(subject.i_name2moves.size).to eq(1)
85
+ expect(subject.move_queue.size).to eq(2)
86
+ expect(subject.i_name2moves['x']).to be_kind_of(Array)
87
+ expect(subject.i_name2moves['x'].size).to eq(2)
88
+ expect(subject.i_name2moves['x'].last).to eq(1)
89
+ expect(subject.move_queue.pop).to eq(x_assoc_b)
90
+ end
91
+
92
+ it 'should allow the removal of the association at TOS position' do
93
+ subject.enqueue_association(x_assoc)
94
+ x_assoc_b = Core::Association.new('x', double('something'))
95
+ subject.enqueue_association(x_assoc_b)
96
+ expect(subject.move_queue.size).to eq(2)
97
+ expect(subject.i_name2moves.size).to eq(1)
98
+
99
+ expect { subject.send(:dequeue_item) }.not_to raise_error
100
+ expect(subject.move_queue.size).to eq(1)
101
+ expect(subject.i_name2moves.size).to eq(1)
102
+
103
+ subject.send(:dequeue_item)
104
+ expect(subject.move_queue).to be_empty
105
+ expect(subject.i_name2moves).to be_empty
106
+ end
107
+
108
+ it 'should allow the enqueuing of a backtrack bookmark' do
109
+ subject.enqueue_association(x_assoc)
110
+
111
+ expect { subject.place_bt_point }.not_to raise_error
112
+ expect(subject.i_name2moves.size).to eq(1)
113
+ expect(subject.move_queue.size).to eq(2)
114
+ expect(subject.i_name2moves['x']).to be_kind_of(Array)
115
+ expect(subject.i_name2moves['x'].size).to eq(1)
116
+ expect(subject.last_move).to be_kind_of(Bookmark)
117
+ end
118
+
119
+ it 'should allow the enqueuing of a scope bookmark' do
120
+ subject.enqueue_association(x_assoc)
121
+
122
+ expect { subject.enter_scope }.not_to raise_error
123
+ expect(subject.i_name2moves.size).to eq(1)
124
+ expect(subject.move_queue.size).to eq(2)
125
+ expect(subject.i_name2moves['x']).to be_kind_of(Array)
126
+ expect(subject.i_name2moves['x'].size).to eq(1)
127
+ expect(subject.last_move).to be_kind_of(Bookmark)
128
+ end
129
+
130
+ it 'should allow the fusion of two unbound variables' do
131
+ q_var = LogVar.new('q')
132
+ x_var = LogVar.new('x')
133
+ q_x_var = LogVar.new('q_x')
134
+ fusion = Fusion.new(q_x_var.i_name, [q_var.i_name, x_var.i_name])
135
+ pre_size = subject.move_queue.size
136
+ subject.enqueue_fusion(fusion)
137
+
138
+ expect(subject.move_queue.size).to eq(pre_size + 1)
139
+ expect(subject.i_name2moves).to be_include(q_x_var.i_name)
140
+ expect(subject.vars2cv[q_var.i_name]).to eq(q_x_var.i_name)
141
+ expect(subject.vars2cv[x_var.i_name]).to eq(q_x_var.i_name)
142
+ end
143
+
144
+ it 'should allow the fusion of one unbound and one floating variable' do
145
+ q_var = LogVar.new('q')
146
+ x_var = LogVar.new('x')
147
+ assoc_x = Association.new('x', cons(LogVarRef.new('y'), pea))
148
+ subject.enqueue_association(assoc_x)
149
+ q_x_var = LogVar.new('q_x')
150
+ fusion = Fusion.new(q_x_var.i_name, [q_var.i_name, x_var.i_name])
151
+ pre_size = subject.move_queue.size
152
+
153
+ subject.enqueue_fusion(fusion)
154
+ expect(subject.move_queue.size).to eq(pre_size + 2)
155
+ expect(subject.i_name2moves).to be_include(q_x_var.i_name)
156
+ indices = subject.i_name2moves[q_x_var.i_name]
157
+ expect(indices.size).to eq(2) # 2 = 1 Fusion + 1 AssocCopy
158
+ new_assoc = subject.move_queue[indices.last]
159
+ expect(new_assoc.value).to eq(assoc_x.value)
160
+ end
161
+
162
+ it 'should allow the fusion of two floating variables' do
163
+ q_var = LogVar.new('q')
164
+ x_var = LogVar.new('x')
165
+ assoc_q = Association.new('x', cons(pod, var_ref('z')))
166
+ subject.enqueue_association(assoc_q)
167
+ assoc_x = Association.new('x', cons(var_ref('y'), pea))
168
+ subject.enqueue_association(assoc_x)
169
+ q_x_var = LogVar.new('q_x')
170
+ fusion = Fusion.new(q_x_var.i_name, [q_var.i_name, x_var.i_name])
171
+ pre_size = subject.move_queue.size
172
+
173
+ subject.enqueue_fusion(fusion)
174
+ expect(subject.move_queue.size).to eq(pre_size + 3)
175
+ expect(subject.i_name2moves).to be_include(q_x_var.i_name)
176
+ indices = subject.i_name2moves[q_x_var.i_name]
177
+ expect(indices.size).to eq(3)
178
+ new_move1 = subject.move_queue[indices[0]]
179
+ expect(new_move1).to be_kind_of(Core::Fusion)
180
+ new_move2 = subject.move_queue[indices[1]]
181
+ expect(new_move2.value).to eq(assoc_q.value)
182
+ new_move3 = subject.move_queue[indices[2]]
183
+ expect(new_move3.value).to eq(assoc_x.value)
184
+ end
185
+
186
+ it 'should allow the removal of a fusion object at TOS position' do
187
+ q_var = LogVar.new('q')
188
+ x_var = LogVar.new('x')
189
+ q_x_var = LogVar.new('q_x')
190
+ fusion = Fusion.new(q_x_var.i_name, [q_var.i_name, x_var.i_name])
191
+ pre_size = subject.move_queue.size
192
+ subject.enqueue_fusion(fusion)
193
+
194
+ expect(subject.move_queue.size).to eq(pre_size + 1)
195
+ expect(subject.i_name2moves).to be_include(q_x_var.i_name)
196
+ expect(subject.vars2cv[q_var.i_name]).to eq(q_x_var.i_name)
197
+ expect(subject.vars2cv[x_var.i_name]).to eq(q_x_var.i_name)
198
+
199
+ expect { subject.send(:dequeue_item) }.not_to raise_error
200
+ expect(subject.move_queue.size).to eq(pre_size)
201
+ expect(subject.i_name2moves).not_to be_include(q_x_var.i_name)
202
+ expect(subject.vars2cv[q_var.i_name]).to be_nil
203
+ expect(subject.vars2cv[x_var.i_name]).to be_nil
204
+ end
205
+
206
+ it 'should retrieve association for a given i_name (0 fusion)' do
207
+ subject.enqueue_association(x_assoc)
208
+ subject.enqueue_association(y_assoc)
209
+
210
+ x_assoc_b = Core::Association.new('x', double('something'))
211
+ subject.enqueue_association(x_assoc_b)
212
+ expect(subject.associations_for('z')).to be_empty
213
+ expect(subject.associations_for('y').size).to eq(1)
214
+ expect(subject.associations_for('x').size).to eq(2)
215
+ expect(subject.associations_for('x').last).to eq(x_assoc_b)
216
+ end
217
+
218
+ it 'should retrieve association for a given i_name (1 fusion)' do
219
+ subject.enqueue_association(x_assoc)
220
+ expect(subject.associations_for('x').size).to eq(1)
221
+ expect(subject.associations_for('z').size).to eq(0)
222
+ expect(subject.associations_for('z', true).size).to eq(0)
223
+
224
+ x_z_var = LogVar.new('x_z')
225
+ fusion = Fusion.new(x_z_var.i_name, %w[x z])
226
+ subject.enqueue_fusion(fusion)
227
+ expect(subject.associations_for('z', true).size).to eq(1)
228
+ x_z_assoc = Core::Association.new(x_z_var.i_name, var_ref('y'))
229
+ subject.enqueue_association(x_z_assoc)
230
+ expect(subject.associations_for('z', false).size).to eq(0)
231
+ expect(subject.associations_for('z', true).size).to eq(2)
232
+ expect(subject.associations_for('x', false).size).to eq(1)
233
+ expect(subject.associations_for('x', true).size).to eq(2)
234
+ end
235
+
236
+ it 'should accept the succeeded notification' do
237
+ subject.enqueue_association(x_assoc)
238
+ subject.enqueue_association(y_assoc)
239
+ subject.succeeded!
240
+ expect(subject).to be_success
241
+ expect(subject.move_queue.size).to eq(2)
242
+ end
243
+
244
+ it 'should accept the failed notification in absence of bookmarks' do
245
+ subject.enqueue_association(x_assoc)
246
+ subject.enqueue_association(y_assoc)
247
+ subject.failed!
248
+ expect(subject).to be_failure
249
+ expect(subject.move_queue).to be_empty
250
+ expect(subject.i_name2moves).to be_empty
251
+ end
252
+
253
+ it 'should accept the failed notification with backtrack' do
254
+ x_assoc2 = Core::Association.new('x', pea)
255
+
256
+ subject.enqueue_association(x_assoc)
257
+ subject.enqueue_association(y_assoc)
258
+ subject.place_bt_point
259
+ subject.enqueue_association(z_assoc)
260
+ subject.enqueue_association(x_assoc2)
261
+ expect(subject.i_name2moves['x'].size).to eq(2)
262
+
263
+ subject.failed!
264
+ expect(subject.resultant).to eq(:"#u")
265
+ expect(subject.last_move).to be_kind_of(Core::Bookmark)
266
+ expect(subject.i_name2moves.include?('z')).to be_falsey
267
+ expect(subject.i_name2moves['x'].size).to eq(1)
268
+ end
269
+
270
+ it 'should accept the failed notification on a bookmark' do
271
+ subject.enqueue_association(x_assoc)
272
+ subject.enqueue_association(y_assoc)
273
+ subject.place_bt_point # Backtrack point bookmark added...
274
+
275
+ subject.enqueue_association(z_assoc)
276
+ subject.enter_scope # Scope bookmark
277
+
278
+ expect(subject.move_queue.size).to eq(5)
279
+
280
+ subject.failed!
281
+ expect(subject.resultant).to eq(:"#u")
282
+ expect(subject.move_queue.size).to eq(3) # 3 = 2 assocs + 1 bookmark
283
+ end
284
+ end # context
285
+ end # describe
286
+ end # module
287
+ end # module
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+
5
+ # Load the class under test
6
+ require_relative '../../lib/mini_kraken/core/bookmark'
7
+
8
+ module MiniKraken
9
+ module Core
10
+ describe Bookmark do
11
+ let(:one_ser_num) { 42 }
12
+ let(:a_kind) { :scope }
13
+ subject { Bookmark.new(a_kind, one_ser_num) }
14
+
15
+ context 'Initialization:' do
16
+ it 'should be initialized with a Symbol and an Integer' do
17
+ expect { Bookmark.new(a_kind, one_ser_num) }.not_to raise_error
18
+ end
19
+
20
+ it 'should know its kind' do
21
+ expect(subject.kind).to eq(a_kind)
22
+ end
23
+
24
+ it 'should know its serial number' do
25
+ expect(subject.ser_num).to eq(one_ser_num)
26
+ end
27
+ end # context
28
+
29
+ context 'Provided services:' do
30
+ it 'should compare to another instance' do
31
+ same = Bookmark.new(a_kind, one_ser_num)
32
+ expect(subject).to eq(same)
33
+
34
+ distinct = Bookmark.new(a_kind, 3)
35
+ expect(subject).not_to eq(distinct)
36
+ end
37
+ end # context
38
+ end # describe
39
+ end # module
40
+ end # module
@@ -0,0 +1,221 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require_relative '../../lib/mini_kraken/core/association'
5
+ require_relative '../../lib/mini_kraken/core/log_var'
6
+ require_relative '../../lib/mini_kraken/composite/all_composite'
7
+
8
+ require_relative '../support/factory_atomic'
9
+ require_relative '../support/factory_methods'
10
+
11
+ # Load the class under test
12
+ require_relative '../../lib/mini_kraken/core/context'
13
+
14
+ module MiniKraken
15
+ module Core
16
+ describe Context do
17
+ include MiniKraken::FactoryAtomic # Use mix-in module
18
+ subject { Context.new }
19
+
20
+ context 'Initialization:' do
21
+ it 'should be initialized without argument' do
22
+ expect { Context.new }.not_to raise_error
23
+ end
24
+
25
+ it 'should have an empty symbol table' do
26
+ expect(subject.symbol_table).to be_empty
27
+ end
28
+
29
+ it 'should have an empty blackboard' do
30
+ expect(subject.blackboard).to be_empty
31
+ end
32
+ end # context
33
+
34
+ context 'Initialization:' do
35
+ def var(aName)
36
+ LogVar.new(aName)
37
+ end
38
+
39
+ it 'should accept the addition of an entry in symbol table' do
40
+ subject.insert(var('x'))
41
+ expect(subject.symbol_table).not_to be_empty
42
+ expect(subject.symbol_table.current_scope.defns['x']).to be_kind_of(LogVar)
43
+ end
44
+
45
+ it 'should create one or more variables from name(s)' do
46
+ # Case: single name
47
+ subject.add_vars('x')
48
+ expect(subject.symbol_table).not_to be_empty
49
+ expect(subject.symbol_table.current_scope.defns['x']).to be_kind_of(LogVar)
50
+
51
+ # Case: multiple names
52
+ subject.add_vars(%w[y z])
53
+ expect(subject.symbol_table.current_scope.defns['y']).to be_kind_of(LogVar)
54
+ expect(subject.symbol_table.current_scope.defns['z']).to be_kind_of(LogVar)
55
+ end
56
+
57
+ it 'should accept the addition of an association to a given i_name' do
58
+ i_name_x = subject.insert(var('x'))
59
+ i_name_y = subject.insert(var('y'))
60
+
61
+ expect(subject.associations_for('x')).to be_empty
62
+ something = double('something')
63
+ assoc_x = subject.associate('x', something)
64
+ expect(subject.associations_for('x')).to eq([assoc_x])
65
+
66
+ thing = double('thing')
67
+ assoc_y = Association.new(i_name_y, thing)
68
+ subject.enqueue_association(assoc_y)
69
+ expect(subject.associations_for('y')).to eq([assoc_y])
70
+
71
+ blob = double('blob')
72
+ assoc2_x = Association.new(i_name_x, blob)
73
+ subject.enqueue_association(assoc2_x)
74
+ expect(subject.associations_for('x')).to eq([assoc_x, assoc2_x])
75
+
76
+ var_y = subject.lookup('y')
77
+ foo = double('bar')
78
+ assoc2_y = subject.associate(var_y, foo)
79
+ expect(subject.associations_for('y')).to eq([assoc_y, assoc2_y])
80
+ end
81
+
82
+ it 'should allow the fusion of two variables' do
83
+ symb_tbl = subject.symbol_table
84
+ i_name_q = subject.insert(var('q'))
85
+ symb_tbl.enter_scope(Core::Scope.new)
86
+ i_name_x = subject.insert(var('x'))
87
+
88
+ expect(subject.associations_for('q')).to be_empty
89
+ something = double('something')
90
+ assoc_x = subject.associate('x', something)
91
+ expect(subject.associations_for('x')).to eq([assoc_x])
92
+ pre_queue_size = subject.blackboard.move_queue.size
93
+ fusion = subject.fuse(%w[q x])
94
+
95
+ expect(fusion).to be_kind_of(Fusion)
96
+ expect(fusion.elements).to eq(%w[q x].map { |e| subject.lookup(e).i_name })
97
+ expect(subject.blackboard.move_queue.size).to eq(pre_queue_size + 2)
98
+ expect(subject.cv2vars).to be_include(fusion.i_name)
99
+ expect(subject.cv2vars[fusion.i_name]).to eq(fusion.elements)
100
+ expect(subject.blackboard.vars2cv[i_name_q]).to eq(fusion.i_name)
101
+ expect(subject.blackboard.vars2cv[i_name_x]).to eq(fusion.i_name)
102
+ expect(subject.associations_for('q')).not_to be_empty
103
+ end
104
+
105
+ it 'should allow the search of an entry based on its name' do
106
+ symb_tbl = subject.symbol_table
107
+ subject.add_vars(%w[q x])
108
+ symb_tbl.enter_scope(Core::Scope.new)
109
+ subject.add_vars(%w[q y])
110
+
111
+ # Search for unknown name
112
+ expect(subject.lookup('z')).to be_nil
113
+
114
+ # Search for existing unique names
115
+ expect(subject.lookup('y')).to eq(symb_tbl.current_scope.defns['y'])
116
+ expect(subject.lookup('x')).to eq(symb_tbl.root.defns['x'])
117
+
118
+ # Search for redefined name
119
+ expect(subject.lookup('q')).to eq(symb_tbl.current_scope.defns['q'])
120
+ end
121
+
122
+ it 'should determine the ranks of fresh variables' do
123
+ subject.add_vars(%w[x y z])
124
+
125
+ ref_y = LogVarRef.new('y')
126
+ subject.associate('x', ref_y)
127
+ subject.send(:calc_ranking)
128
+ expect(subject.ranking.size).to eq(2)
129
+ i_name_y = subject.lookup('y').i_name
130
+ expect(subject.ranking[i_name_y]).to eq(0)
131
+ i_name_z = subject.lookup('z').i_name
132
+ expect(subject.ranking[i_name_z]).to eq(1)
133
+ end
134
+
135
+ it 'should allow entering in a new scope' do
136
+ new_scope = Scope.new
137
+ expect { subject.enter_scope(new_scope) }.not_to raise_error
138
+ expect(subject.symbol_table.current_scope).to eq(new_scope)
139
+ end
140
+
141
+ it 'should allow leaving out current scope' do
142
+ subject.add_vars(%w[q x])
143
+ x_val = k_symbol(:foo)
144
+ assoc_x = subject.associate('x', x_val) # x => :foo
145
+ expect(subject.blackboard.move_queue.size).to eq(1)
146
+ new_scope = Scope.new
147
+ subject.enter_scope(new_scope) # Adds one bookmark
148
+ expect(subject.blackboard.move_queue.size).to eq(2)
149
+ subject.add_vars(%w[w x y z])
150
+
151
+ q_val = LogVarRef.new('x')
152
+ assoc_q = subject.associate('q', q_val)
153
+ w_val = k_symbol(:bar)
154
+ subject.associate('w', w_val)
155
+ x2_val = LogVarRef.new('z')
156
+ assoc2_x = subject.associate('x', x2_val)
157
+ y_val = k_symbol(:foobar)
158
+ subject.associate('y', y_val)
159
+ # x => :foo
160
+ # ------
161
+ # q => x
162
+ # w => :bar
163
+ # x => z
164
+ # y => :foobar
165
+ expect(subject.blackboard.i_name2moves.keys.size).to eq(5)
166
+ expect(subject.blackboard.move_queue.size).to eq(6)
167
+ # require 'debug'
168
+ expect { subject.leave_scope }.not_to raise_error
169
+ # Expected state:
170
+ # x => :foo
171
+ # q => x'
172
+ # x' => z
173
+ expect(subject.blackboard.move_queue.size).to eq(3)
174
+ symb_table = subject.symbol_table
175
+ expect(symb_table.current_scope).to eq(symb_table.root)
176
+ expect(subject.blackboard.i_name2moves.keys.size).to eq(3)
177
+ expect(subject.blackboard.move_queue).to eq([assoc_x, assoc_q, assoc2_x])
178
+ end
179
+
180
+ it 'should substitute values of associations (if needed)' do
181
+ subject.add_vars(%w[q x y z])
182
+
183
+ x_ref = LogVarRef.new('x')
184
+ foobar = Composite::ConsCell.new(k_symbol(:foo), k_symbol(:bar))
185
+ q_val = Composite::ConsCell.new(x_ref, foobar)
186
+ assoc_q = subject.associate('q', q_val)
187
+ subject.send(:calc_ranking)
188
+
189
+ expect(subject.send(:substitute, assoc_q).to_s).to eq('(_0 :foo . :bar)')
190
+ end
191
+
192
+ it 'should build a solution' do
193
+ subject.add_vars(%w[x y z])
194
+
195
+ subject.succeeded!
196
+ sol = subject.build_solution
197
+ expect(sol.size).to eq(3)
198
+ expect(sol['x']).to eq(:_0)
199
+ expect(sol['y']).to eq(:_1)
200
+ expect(sol['z']).to eq(:_2)
201
+
202
+ foo = k_symbol(:foo)
203
+ subject.associate('x', foo)
204
+ sol = subject.build_solution
205
+ expect(sol.size).to eq(3)
206
+ expect(sol['x']).to eq(foo)
207
+ expect(sol['y']).to eq(:_0)
208
+ expect(sol['z']).to eq(:_1)
209
+
210
+ bar = k_symbol(:bar)
211
+ subject.associate('y', bar)
212
+ sol = subject.build_solution
213
+ expect(sol.size).to eq(3)
214
+ expect(sol['x']).to eq(foo)
215
+ expect(sol['y']).to eq(bar)
216
+ expect(sol['z']).to eq(:_0)
217
+ end
218
+ end
219
+ end # describe
220
+ end # module
221
+ end # module