cauldron 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -0
- data/Rakefile +7 -0
- data/VERSION +1 -1
- data/features/cauldron_generates_runtime_method.feature +3 -2
- data/features/step_definitions/cauldron_steps.rb +0 -1
- data/features/support/method_1.example +3 -0
- data/features/support/method_2.example +6 -0
- data/lib/Chain.rb +140 -264
- data/lib/CodeHandler.rb +0 -4
- data/lib/ScopeDependencies.rb +1 -0
- data/lib/Theory.rb +12 -15
- data/lib/UnifiedChain.rb +265 -8
- data/lib/cauldron.rb +1 -1
- data/lib/cauldron/demos.rb +280 -0
- data/lib/cauldron/pot.rb +56 -30
- data/lib/cauldron/sexp2cauldron.rb +109 -126
- data/lib/cauldron/terminal.rb +5 -74
- data/lib/core/ClassMethodCallContainer.rb +14 -0
- data/lib/core/Container.rb +12 -2
- data/lib/core/InstanceCallContainer.rb +30 -4
- data/lib/core/TheoryGenerator.rb +2 -9
- data/lib/core/assignment/Equal.rb +1 -1
- data/lib/core/assignment/Equivalent.rb +1 -1
- data/lib/core/assignment/NotEqual.rb +1 -1
- data/lib/core/call_container/CallContainer.rb +7 -1
- data/lib/core/instance_call/Chop.rb +0 -9
- data/lib/core/instance_call/instance_calls.rb +8 -0
- data/lib/core/instance_call/length_equal.rb +1 -1
- data/lib/core/requirement/Requirement.rb +1 -0
- data/lib/core/runtime_class/class_names.rb +12 -12
- data/lib/core/runtime_method/ActsAsRuntimeMethod.rb +0 -7
- data/lib/core/runtime_method/RuntimeMethod.rb +59 -45
- data/lib/core/statement/ActsAsStatement.rb +1 -1
- data/lib/core/statement/ArrayAccess.rb +28 -2
- data/lib/core/statement/OpenStatement.rb +7 -0
- data/lib/core/statement/Statement.rb +22 -18
- data/lib/core/statement/TheoryStatement.rb +8 -1
- data/lib/core/syntax/Addition.rb +3 -2
- data/lib/core/syntax/If.rb +8 -0
- data/lib/core/syntax/Return.rb +1 -1
- data/lib/core/variable/BaseVariable.rb +0 -2
- data/lib/core/variable/MethodParameter.rb +4 -31
- data/lib/core/variable/Unknown.rb +1 -5
- data/lib/implemented_chain.rb +3 -2
- data/lib/required.rb +0 -1
- data/lib/ruby_code/String.rb +0 -17
- data/lib/theories.rb +25 -1
- data/lib/theory/TheoryAction.rb +35 -5
- data/lib/theory/TheoryChainValidator.rb +10 -8
- data/lib/theory/TheoryComponent.rb +17 -0
- data/lib/theory/TheoryConnector.rb +76 -9
- data/lib/theory/TheoryDependent.rb +2 -2
- data/lib/theory/TheoryImplementation.rb +7 -7
- data/lib/util/ClassEvaluation.rb +2 -7
- data/lib/util/MethodValidation.rb +10 -6
- data/lib/util/Parser.rb +26 -20
- data/lib/util/StringToTheory.rb +27 -3
- data/spec/cauldron/chain_spec.rb +24 -0
- data/spec/cauldron/demos_spec.rb +30 -0
- data/spec/cauldron/pot_spec.rb +66 -0
- data/spec/cauldron/runtime_method_spec.rb +47 -5
- data/spec/cauldron/sexp_2_cauldron_spec.rb +92 -0
- data/spec/cauldron/terminal_spec.rb +1 -1
- data/spec/cauldron/theory_action_spec.rb +20 -0
- data/spec/cauldron/theory_connector_spec.rb +52 -0
- data/spec/cauldron/theory_spec.rb +59 -0
- data/spec/cauldron/unified_chain_spec.rb +102 -0
- data/spec/spec_helper.rb +10 -1
- data/tasks/theory_tasks.rake +274 -0
- data/test/fixtures/implementation_results/0/dump +0 -0
- data/test/fixtures/theories/0/dump +0 -0
- data/test/fixtures/theories/1/dump +0 -0
- data/test/fixtures/theories/10/dump +0 -0
- data/test/fixtures/theories/11/dump +0 -0
- data/test/fixtures/theories/12/dump +0 -0
- data/test/fixtures/theories/13/declaration.txt +1 -1
- data/test/fixtures/theories/13/desc +1 -1
- data/test/fixtures/theories/13/dump +0 -0
- data/test/fixtures/theories/14/dump +0 -0
- data/test/fixtures/theories/15/dump +0 -0
- data/test/fixtures/theories/16/dump +0 -0
- data/test/fixtures/theories/17/dump +0 -0
- data/test/fixtures/theories/18/dump +0 -0
- data/test/fixtures/theories/19/dump +0 -0
- data/test/fixtures/theories/2/dump +0 -0
- data/test/fixtures/theories/20/declaration.txt +1 -1
- data/test/fixtures/theories/20/desc +1 -1
- data/test/fixtures/theories/20/dump +0 -0
- data/test/fixtures/theories/3/dump +0 -0
- data/test/fixtures/theories/4/dump +0 -0
- data/test/fixtures/theories/5/dump +0 -0
- data/test/fixtures/theories/6/dump +0 -0
- data/test/fixtures/theories/7/dump +0 -0
- data/test/fixtures/theories/8/dump +0 -0
- data/test/fixtures/theories/9/dump +0 -0
- data/test/fixtures/theory_implementations/0/declaration.txt +1 -1
- data/test/fixtures/theory_implementations/0/dump +0 -0
- data/test/fixtures/theory_implementations/1/declaration.txt +11 -0
- data/test/fixtures/theory_implementations/1/dump +0 -0
- data/test/fixtures/theory_implementations/2/declaration.txt +11 -0
- data/test/fixtures/theory_implementations/2/dump +0 -0
- data/test/output/simple_method.txt +0 -1
- data/test/tc_contextual_variables.rb +2 -41
- data/test/tc_describe.rb +1 -2
- data/test/tc_method.rb +2 -5
- data/test/unit/core/runtime_method/tc_realised_runtime_method.rb +5 -3
- data/test/unit/core/runtime_method/tc_runtime_method.rb +34 -56
- data/test/unit/core/statement/tc_block_statement.rb +2 -0
- data/test/unit/core/statement/tc_open_statement.rb +15 -6
- data/test/unit/core/statement/tc_statement.rb +4 -5
- data/test/unit/core/statement/tc_statement_dependencies.rb +1 -0
- data/test/unit/core/statement/tc_theory_statement.rb +2 -0
- data/test/unit/core/syntax/tc_if_container.rb +5 -5
- data/test/unit/core/tc_theory_generator_heavy.rb +1 -1
- data/test/unit/core/tracking/tc_history.rb +3 -1
- data/test/unit/core/variable/tc_method_parameter_variable.rb +2 -2
- data/test/unit/tc_chain_with_case_1.rb +1 -1
- data/test/unit/tc_method_usage.rb +1 -1
- data/test/unit/tc_theory.rb +8 -2
- data/test/unit/theory/tc_theory_action.rb +37 -5
- data/test/unit/theory/tc_theory_chain_validator.rb +3 -3
- data/test/unit/theory/tc_theory_connector.rb +2 -37
- data/test/unit/theory/tc_theory_dependent.rb +2 -0
- data/test/unit/theory/tc_theory_implementation.rb +5 -1
- data/test/unit/theory/tc_theory_result.rb +3 -2
- data/test/unit/util/tc_method_validation.rb +4 -1
- data/test/unit/util/tc_parser.rb +2 -0
- data/test/unit/util/tc_string_to_theory.rb +3 -2
- data/tmp/runtime_method_evaluation.rb +7 -4
- metadata +59 -13
- data/lib/core/syntax/IfContainer.rb +0 -100
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -11,6 +11,12 @@ rescue Bundler::BundlerError => e
|
|
11
11
|
end
|
12
12
|
require 'rake'
|
13
13
|
|
14
|
+
$LOAD_PATH << File.expand_path('../lib',__FILE__)
|
15
|
+
|
16
|
+
require 'lib/cauldron'
|
17
|
+
|
18
|
+
load File.join(File.dirname(__FILE__), 'tasks', 'theory_tasks.rake')
|
19
|
+
|
14
20
|
require 'jeweler'
|
15
21
|
Jeweler::Tasks.new do |gem|
|
16
22
|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
@@ -21,6 +27,7 @@ Jeweler::Tasks.new do |gem|
|
|
21
27
|
gem.description = %Q{Cauldron generates a methd from a number of examples that describe the input and the expected output. It is still at a very early stage of development right now so you're unlikely to get much practical use out of it.}
|
22
28
|
gem.email = "warrensangster@yahoo.com"
|
23
29
|
gem.authors = ["Warren Sangster"]
|
30
|
+
gem.required_ruby_version = '>= 1.6.8'
|
24
31
|
# dependencies defined in Gemfile
|
25
32
|
end
|
26
33
|
Jeweler::RubygemsDotOrgTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
@@ -8,5 +8,6 @@ Feature: Cauldron generates a runtime method
|
|
8
8
|
Then I should receive a runtime method like this <runtime_method>
|
9
9
|
|
10
10
|
Scenarios: example with only one parameter
|
11
|
-
| cases
|
12
|
-
| "'sparky','sparky'*'kel','kel'"
|
11
|
+
| cases | runtime_method | demo_num |
|
12
|
+
| "'sparky','sparky'*'kel','kel'" | "def method_3(var_6)\n\treturn var_6\nend\n" | 1 |
|
13
|
+
| "'fish','animal'*'carrot','vegatable'" | "def method_3(var_0)\n\tif(var_0 == 'fish')\n\t\treturn 'animal'\n\tend\n\treturn 'vegetable'\nend\n" | 2 |
|
@@ -8,7 +8,6 @@ end
|
|
8
8
|
|
9
9
|
Then /^I should receive a runtime method like this "([^"]*)"$/ do |runtime_method_statement|
|
10
10
|
runtime_method_statement = runtime_method_statement.gsub('\\n',"\n").gsub('\\t',"\t")
|
11
|
-
#@terminal.submit('RUN').should == runtime_method_statement
|
12
11
|
@terminal.submit('RUN')
|
13
12
|
output.messages.should include(runtime_method_statement)
|
14
13
|
end
|
data/lib/Chain.rb
CHANGED
@@ -29,7 +29,8 @@ class Chain
|
|
29
29
|
real_method = Parser.run('runtime_method')
|
30
30
|
|
31
31
|
# Add the tail to the nodes list
|
32
|
-
add_link(@tail_theory,{1=>real_method,2=>tc})
|
32
|
+
#add_link(@tail_theory,{1=>real_method,2=>tc})
|
33
|
+
extension_permutaions(@tail_theory,{1=>real_method,2=>tc})
|
33
34
|
|
34
35
|
end
|
35
36
|
|
@@ -102,6 +103,14 @@ class Chain
|
|
102
103
|
end
|
103
104
|
end
|
104
105
|
|
106
|
+
def unmet_dependents_ids
|
107
|
+
collection = TheoryCollection.new(@nodes)
|
108
|
+
return collection.dependents.inject([]) do |total,dependent|
|
109
|
+
total << dependent.theory_component_id unless @chain_mapping.connected_component_ids.include?(dependent.theory_component_id)
|
110
|
+
total
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
105
114
|
# Returns a new chain where they are all using the same respective theory
|
106
115
|
# variables.
|
107
116
|
#
|
@@ -113,7 +122,8 @@ class Chain
|
|
113
122
|
end
|
114
123
|
unified_theories = @nodes.inject([]) do |total,theory|
|
115
124
|
mapping = generate_theory_mapping(theory.theory_instance_id)
|
116
|
-
|
125
|
+
mapped_theory = theory.map_to(mapping)
|
126
|
+
total.push(mapped_theory)
|
117
127
|
end
|
118
128
|
return UnifiedChain.new(unified_theories)
|
119
129
|
end
|
@@ -143,7 +153,6 @@ class Chain
|
|
143
153
|
|
144
154
|
# TODO Really need a method to highlight what is connected to what
|
145
155
|
|
146
|
-
# DEVELOPMENT
|
147
156
|
# Writes out the chain but highlights any of links in the chain weren't connected
|
148
157
|
# to a dependent.
|
149
158
|
#
|
@@ -161,12 +170,7 @@ class Chain
|
|
161
170
|
# Attempts to add a new link to form a complete chain between the head and tail. It starts
|
162
171
|
# by linking to the tail and then head.
|
163
172
|
#
|
164
|
-
|
165
|
-
# could be connected.
|
166
|
-
#
|
167
|
-
# TODO link_permutations mighht be a more appropriate name
|
168
|
-
#
|
169
|
-
def add_link(theory,value_mapping=nil)
|
173
|
+
def extension_permutaions(theory,value_mapping=nil)
|
170
174
|
|
171
175
|
# Give the theory an instance id
|
172
176
|
theory = theory.copy
|
@@ -247,6 +251,80 @@ class Chain
|
|
247
251
|
return res
|
248
252
|
end
|
249
253
|
|
254
|
+
# Returns any number of new chains after adding this link to the position
|
255
|
+
# specified.
|
256
|
+
#
|
257
|
+
# TODO SHould I raise an error if it doesn't connect to anything?
|
258
|
+
#
|
259
|
+
def add_link_to(theory,position,value_mapping)
|
260
|
+
# TODO Down and up are quite similar I should consider refactoring
|
261
|
+
|
262
|
+
# Do through each of the dependents and then find a result with the same structure
|
263
|
+
mappings = [@chain_mapping.copy]
|
264
|
+
upward_links = @nodes[0...position]
|
265
|
+
|
266
|
+
theory.copy.dependents.each do |dependent|
|
267
|
+
each_result(position,upward_links) do |index,link,result|
|
268
|
+
if result.same_structure?(dependent)
|
269
|
+
new_mappings = []
|
270
|
+
mappings.each do |x|
|
271
|
+
new_mappings << x.apply_mapping_update(theory,dependent.theory_component_id,link,result.theory_component_id)
|
272
|
+
end
|
273
|
+
mappings = new_mappings
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# Go down the rest of the chain looking for exisitng links with unmet dependents
|
279
|
+
downward_links = @nodes[position...@nodes.length]
|
280
|
+
theory.copy.results.each do |result|
|
281
|
+
each_unmet(:dependents,position,downward_links) do |index,link,dependent|
|
282
|
+
if dependent.same_structure?(result)
|
283
|
+
new_mappings = []
|
284
|
+
mappings.each do |x|
|
285
|
+
new_mappings << x.apply_mapping_update(link,dependent.theory_component_id,theory,result.theory_component_id)
|
286
|
+
end
|
287
|
+
mappings = new_mappings
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
# Strip out any mappings that are identical to original they are
|
293
|
+
# links that haven't been connected with anything
|
294
|
+
# (don't include the head since it only has one thing to connect to)
|
295
|
+
# => TODO Do I like this? It means I'm including some forced connections
|
296
|
+
unless @nodes.length < 2
|
297
|
+
|
298
|
+
# Identify the mappings that are the same
|
299
|
+
mappings = mappings.select {|x| !@chain_mapping.same?(x) }
|
300
|
+
# => TODO Should inlcude error/warning and exit when there are no new mappings
|
301
|
+
end
|
302
|
+
|
303
|
+
# Identify any orphan variables in the action and give them uniq global ids
|
304
|
+
mappings.each do |mapping|
|
305
|
+
theory.orphan_action_variables.each do |x|
|
306
|
+
mapping.add_mapping(
|
307
|
+
mapping.next_free_global_id,
|
308
|
+
theory.theory_instance_id,
|
309
|
+
x.theory_variable_id
|
310
|
+
)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
# Create a new nodes array with the new theory in place
|
315
|
+
updated_nodes = @nodes.copy
|
316
|
+
updated_nodes.insert(position,theory)
|
317
|
+
|
318
|
+
# Create a new chain for each of the possible mappings
|
319
|
+
extended_chains = []
|
320
|
+
mappings.each do |x|
|
321
|
+
c = self.copy
|
322
|
+
new_chain = c.create!(updated_nodes,x,@uniq_theory_instance_ids.copy,@values.copy)
|
323
|
+
extended_chains << new_chain
|
324
|
+
end
|
325
|
+
return extended_chains
|
326
|
+
end
|
327
|
+
|
250
328
|
# Implements a new the chain where all the theories are implemented. It can
|
251
329
|
# only be implemented if the chain is complete e.g. all the dependents and results
|
252
330
|
# are matched up.
|
@@ -335,6 +413,20 @@ class Chain
|
|
335
413
|
def theory_variables
|
336
414
|
return TheoryCollection.new(@nodes).theory_variables
|
337
415
|
end
|
416
|
+
|
417
|
+
# Returns an array of all the depdendents in the chain that haven't
|
418
|
+
# been met by the front of the chain.
|
419
|
+
#
|
420
|
+
def unmet_dependents
|
421
|
+
results = []
|
422
|
+
return results if self.empty?
|
423
|
+
duplicate_chain = self.copy
|
424
|
+
last_link = duplicate_chain.pop
|
425
|
+
last_link.dependents.each do |dependent|
|
426
|
+
results.push dependent unless dependent_met?(dependent,duplicate_chain.copy)
|
427
|
+
end
|
428
|
+
return results+duplicate_chain.unmet_dependents
|
429
|
+
end
|
338
430
|
|
339
431
|
# TODO Maybe just move this method to the UnfiedChain class
|
340
432
|
# Returns a set containing the intrinsic statements that created the variables. It should look
|
@@ -353,6 +445,7 @@ class Chain
|
|
353
445
|
raise StandardError.new('This should only be called on complete chains') unless complete?
|
354
446
|
res = []
|
355
447
|
unify_chain.theory_variables.each do |var|
|
448
|
+
|
356
449
|
intrinsic_value = global_id_intrinsic_value(var.theory_variable_id)
|
357
450
|
if intrinsic_value.kind_of?(IntrinsicRuntimeMethod)
|
358
451
|
res << {
|
@@ -380,10 +473,22 @@ class Chain
|
|
380
473
|
written_components = unified_components.collect {|x| x.write}
|
381
474
|
written_components = written_components.select {|x| x.include?('var'+var.theory_variable_id.to_s)}
|
382
475
|
|
476
|
+
# => DEV
|
477
|
+
temp_component = written_components.first
|
478
|
+
|
479
|
+
# => MATCH var0.params[var2] in runtime_method.add_statement_at(OpenStatement.new(TheoryStatement.new(If.new, Container.new(var0.params[var2], Equivalent.new, var1[var4][:params][var3]))),var0.statement_id)
|
480
|
+
reg = eval('/[\w\d\.\[\]:]*\['+var.write+'\]/')
|
481
|
+
|
383
482
|
# TODO Should use the Parser to find the statement with the varx in
|
483
|
+
#var_match = /\s.*\[var[\d]\]/
|
484
|
+
#var_match = /^[\s|\(]+(.*\[var[\d]\])/
|
485
|
+
var_match = reg
|
384
486
|
usage_statements = written_components.inject([]) do |total,x|
|
385
|
-
|
386
|
-
|
487
|
+
|
488
|
+
#unless x.write.match(/\s.*\[var[\d]\]/).nil?
|
489
|
+
unless x.write.match(var_match).nil?
|
490
|
+
match = x.write.match(var_match)[0]
|
491
|
+
total << TheoryStatement.new(StringToTheory.run(match))
|
387
492
|
end
|
388
493
|
total
|
389
494
|
end
|
@@ -405,6 +510,27 @@ class Chain
|
|
405
510
|
return res
|
406
511
|
end
|
407
512
|
|
513
|
+
# Returns a hash of all the unmet dependents down the chain (excluding the head)
|
514
|
+
# and the link/theory that it belongs to.
|
515
|
+
#
|
516
|
+
def unmet_dependents_and_link
|
517
|
+
results = []
|
518
|
+
return results if self.empty?
|
519
|
+
duplicate_chain = self.copy
|
520
|
+
|
521
|
+
# Remove the head link from the chain
|
522
|
+
duplicate_chain.shift
|
523
|
+
|
524
|
+
duplicate_chain.length.times do
|
525
|
+
last_link = duplicate_chain.pop
|
526
|
+
last_link.dependents.each do |d|
|
527
|
+
next if dependent_met?(d,duplicate_chain.copy)
|
528
|
+
results.push({:dependent=>d.copy,:theory=>last_link.copy})
|
529
|
+
end
|
530
|
+
end
|
531
|
+
return results
|
532
|
+
end
|
533
|
+
|
408
534
|
protected
|
409
535
|
|
410
536
|
# Returns the intrinsic mapping for the unified chain
|
@@ -449,7 +575,8 @@ protected
|
|
449
575
|
|
450
576
|
if potentential_values.length > 1
|
451
577
|
unless potentential_values.collect {|y| y.write}.uniq.length == 1
|
452
|
-
|
578
|
+
pp potentential_values
|
579
|
+
raise StandardError.new('There is more than one possible value for this('+global_id.to_s+') - it is ok if there the same')
|
453
580
|
end
|
454
581
|
end
|
455
582
|
return potentential_values[0]
|
@@ -468,223 +595,11 @@ protected
|
|
468
595
|
@nodes = obj
|
469
596
|
end
|
470
597
|
|
471
|
-
# Returns any number of new chains after adding this link to the position
|
472
|
-
# specified.
|
473
|
-
#
|
474
|
-
# TODO SHould I raise an error if it doesn't connect to anything?
|
475
|
-
#
|
476
|
-
def add_link_to(theory,position,value_mapping)
|
477
|
-
# TODO Down and up are quite similar I should consider refactoring
|
478
|
-
|
479
|
-
# Do through each of the dependents and then find a result with the same structure
|
480
|
-
mappings = [@chain_mapping.copy]
|
481
|
-
upward_links = @nodes[0...position]
|
482
|
-
# theory.copy.dependents.each do |dependent|
|
483
|
-
# if StandardLogger.instance.level == 0
|
484
|
-
# end
|
485
|
-
# each_unmet(:results,position,upward_links) do |index,link,result|
|
486
|
-
# if result.same_structure?(dependent)
|
487
|
-
# if StandardLogger.instance.level == 0
|
488
|
-
# end
|
489
|
-
# new_mappings = []
|
490
|
-
# mappings.each do |x|
|
491
|
-
# new_mappings << x.apply_mapping_update(theory,dependent.theory_component_id,link,result.theory_component_id)
|
492
|
-
# end
|
493
|
-
# mappings = new_mappings
|
494
|
-
# end
|
495
|
-
# end
|
496
|
-
# end
|
497
|
-
|
498
|
-
theory.copy.dependents.each do |dependent|
|
499
|
-
each_result(position,upward_links) do |index,link,result|
|
500
|
-
if result.same_structure?(dependent)
|
501
|
-
new_mappings = []
|
502
|
-
mappings.each do |x|
|
503
|
-
new_mappings << x.apply_mapping_update(theory,dependent.theory_component_id,link,result.theory_component_id)
|
504
|
-
end
|
505
|
-
mappings = new_mappings
|
506
|
-
end
|
507
|
-
end
|
508
|
-
end
|
509
|
-
|
510
|
-
# Go down the rest of the chain looking for exisitng links with unmet dependents
|
511
|
-
downward_links = @nodes[position...@nodes.length]
|
512
|
-
theory.copy.results.each do |result|
|
513
|
-
each_unmet(:dependents,position,downward_links) do |index,link,dependent|
|
514
|
-
if dependent.same_structure?(result)
|
515
|
-
new_mappings = []
|
516
|
-
mappings.each do |x|
|
517
|
-
new_mappings << x.apply_mapping_update(link,dependent.theory_component_id,theory,result.theory_component_id)
|
518
|
-
end
|
519
|
-
mappings = new_mappings
|
520
|
-
end
|
521
|
-
end
|
522
|
-
end
|
523
|
-
|
524
|
-
# Strip out any mappings that are identical to original they are
|
525
|
-
# links that haven't been connected with anything
|
526
|
-
# (don't include the head since it only has one thing to connect to)
|
527
|
-
unless @nodes.length < 2
|
528
|
-
mappings = mappings.select {|x| !@chain_mapping.same?(x) }
|
529
|
-
end
|
530
|
-
|
531
|
-
# Identify any orphan variables in the action and give them uniq global ids
|
532
|
-
mappings.each do |mapping|
|
533
|
-
theory.orphan_action_variables.each do |x|
|
534
|
-
mapping.add_mapping(mapping.next_free_global_id,theory.theory_instance_id,x.theory_variable_id)
|
535
|
-
end
|
536
|
-
end
|
537
|
-
|
538
|
-
# Create a new nodes array with the new theory in place
|
539
|
-
updated_nodes = @nodes.copy
|
540
|
-
updated_nodes.insert(position,theory)
|
541
|
-
|
542
|
-
# Create a new chain for each of the possible mappings
|
543
|
-
extended_chains = []
|
544
|
-
mappings.each do |x|
|
545
|
-
c = self.copy
|
546
|
-
new_chain = c.create!(updated_nodes,x,@uniq_theory_instance_ids.copy,@values.copy)
|
547
|
-
extended_chains << new_chain
|
548
|
-
end
|
549
|
-
return extended_chains
|
550
|
-
end
|
551
|
-
|
552
598
|
# TODO This could probably be replaced by the normal add_link_to method
|
553
599
|
def add_tail(theory,value_mapping={})
|
554
600
|
@nodes.push(theory.copy)
|
555
601
|
end
|
556
602
|
|
557
|
-
# # TODO I don't think this is used
|
558
|
-
# def update_unified_theory_variables(unified_theory_variables_mapping,chain_front,dependent,theory)
|
559
|
-
#
|
560
|
-
# # TODO Once the mapping is in place for all the theory vairables in the
|
561
|
-
# # in the dependent then the dependent should be mapped, written out
|
562
|
-
# # and compared to the result instead of the same_structure? method.
|
563
|
-
#
|
564
|
-
# # Find all the results that have the same structure as the dependent
|
565
|
-
# # TODO It should probably preference the earliest theories first.
|
566
|
-
# matching_theories = chain_front.select do |t|
|
567
|
-
# t.results.any? {|x| x.same_structure?(dependent)}
|
568
|
-
# end
|
569
|
-
#
|
570
|
-
# # Check that a matching theory was found in the chain
|
571
|
-
# if matching_theories.empty?
|
572
|
-
# # Couldn't find a theory that meets this theories depdenents - add the theory will
|
573
|
-
# # need to add a another link to the chain to connect this theory with the head.
|
574
|
-
# return unified_theory_variables_mapping
|
575
|
-
# end
|
576
|
-
#
|
577
|
-
# # Go through the matching thoeries and find the result that matched the dependent
|
578
|
-
# matching_results = matching_theories.inject([]) do |total,t|
|
579
|
-
# # TODO Presumes there is only one result
|
580
|
-
# res = t.results.select {|x| x.same_structure?(dependent)}.first
|
581
|
-
# total << {:theory_id=>t.theory_id,:result=>res,:theory=>t}
|
582
|
-
# end
|
583
|
-
#
|
584
|
-
# # Check how many results meet the dependents
|
585
|
-
# raise StandardError.new('Currently only handling one result to dependent match') unless matching_results.length == 1
|
586
|
-
# linking_result = matching_results.first
|
587
|
-
#
|
588
|
-
# # Link two theories so that the share the same global mapping
|
589
|
-
# @chain_mapping.connect(
|
590
|
-
# theory,
|
591
|
-
# dependent.theory_component_id,
|
592
|
-
# linking_result[:theory],
|
593
|
-
# linking_result[:result].theory_component_id
|
594
|
-
# )
|
595
|
-
# return unified_theory_variables_mapping
|
596
|
-
#
|
597
|
-
# end
|
598
|
-
|
599
|
-
# def map_to_tail(global_mapping,theory)
|
600
|
-
#
|
601
|
-
# # * Check whether there are any dependents from the back of the chain not met
|
602
|
-
#
|
603
|
-
# # Attempt to connect the theories results to the unmet dependents.
|
604
|
-
# # NOTE: The theories position is always one away from the head so
|
605
|
-
# # [:head]
|
606
|
-
# # [:x] <-----------this is where the new link will go.
|
607
|
-
# # [:linkB]
|
608
|
-
# # [:linkA]
|
609
|
-
# # [:tail]
|
610
|
-
#
|
611
|
-
# possible_mappings = [global_mapping.copy]
|
612
|
-
# valid_mappings = [global_mapping.copy]
|
613
|
-
#
|
614
|
-
# # 1. Find all the unmet dependents down the chain e.g. :tail, :linkA and :linkB
|
615
|
-
# # TODO Need to generate some nice diagrams for what's happing - very har to visualise
|
616
|
-
#
|
617
|
-
# # TEMP: This is the dependent for the tail of the chain - the head doesn't have any dependents
|
618
|
-
# unless unmet_dependents_and_link.empty?
|
619
|
-
# unmet_dependents_and_link.each do |dep_and_link|
|
620
|
-
#
|
621
|
-
# dependent = dep_and_link[:dependent]
|
622
|
-
# # TODO This is very similar to the code above - re-factor
|
623
|
-
# # Do any of the results have the same structure as the dependent?
|
624
|
-
# if theory.results.any? {|x| x.same_structure?(dep_and_link[:dependent])}
|
625
|
-
#
|
626
|
-
# valid_mappings = []
|
627
|
-
#
|
628
|
-
# results = theory.results.select {|x| x.same_structure?(dep_and_link[:dependent])}
|
629
|
-
# possible_mappings.each do |mapping|
|
630
|
-
# results.each do |res|
|
631
|
-
#
|
632
|
-
# begin
|
633
|
-
# new_mapping = potential_tail_mapping(mapping.copy,theory.copy,res.copy,dep_and_link[:dependent].copy,dep_and_link[:theory].copy)
|
634
|
-
# # TODO Create special MappingError
|
635
|
-
# rescue StandardError => e
|
636
|
-
# StandardLogger.instance.error e
|
637
|
-
# next
|
638
|
-
# end
|
639
|
-
# valid_mappings << new_mapping
|
640
|
-
# end
|
641
|
-
# end
|
642
|
-
#
|
643
|
-
# # Make the valid mappings the possible mappings for the next stage
|
644
|
-
# possible_mappings = valid_mappings
|
645
|
-
#
|
646
|
-
# end
|
647
|
-
#
|
648
|
-
# end
|
649
|
-
#
|
650
|
-
# end
|
651
|
-
#
|
652
|
-
# if valid_mappings.empty?
|
653
|
-
# raise StandardError.new('Unable to perform valid mapping')
|
654
|
-
# else
|
655
|
-
# # TODO Should be returning all the potential mapping
|
656
|
-
# return valid_mappings[0]
|
657
|
-
# end
|
658
|
-
#
|
659
|
-
# #return global_mapping
|
660
|
-
# end
|
661
|
-
|
662
|
-
# # Returns the updated mapping if a possible match is found otherwise it raises
|
663
|
-
# # an error.
|
664
|
-
# #
|
665
|
-
# def potential_tail_mapping(global_mapping,new_theory,new_result,existing_dependent,existing_theory)
|
666
|
-
#
|
667
|
-
# # Check that the result and dependent have the same number of theory variables
|
668
|
-
# if new_result.theory_variables.length != existing_dependent.theory_variables.length
|
669
|
-
# raise StandardError.new('The result and dependent that are being linked do not have the same number of theory_variables')
|
670
|
-
# end
|
671
|
-
#
|
672
|
-
# new_result.theory_variables.zip(existing_dependent.theory_variables) do |result_theory_variable,dependent_theory_variable|
|
673
|
-
# # Add the results of the theory to the global variables.
|
674
|
-
#
|
675
|
-
# # So these two variables need the same global variable
|
676
|
-
# # TODO This presumes that the same theory isn't being used in the chain
|
677
|
-
# global_mapping.connect(
|
678
|
-
# new_theory,
|
679
|
-
# new_result.theory_component_id,
|
680
|
-
# existing_theory,
|
681
|
-
# existing_dependent.theory_component_id
|
682
|
-
# )
|
683
|
-
# end
|
684
|
-
# return global_mapping
|
685
|
-
#
|
686
|
-
# end
|
687
|
-
|
688
603
|
# Returns the global id of the variable given the theory id and the variable
|
689
604
|
# id.
|
690
605
|
#
|
@@ -709,10 +624,6 @@ protected
|
|
709
624
|
linking_result = linking_results.first
|
710
625
|
end
|
711
626
|
|
712
|
-
# def front_of_chain
|
713
|
-
# return [@nodes.first.copy]
|
714
|
-
# end
|
715
|
-
|
716
627
|
# Returns a new theory mapping that replace the theories local ids with global
|
717
628
|
# ids.
|
718
629
|
#
|
@@ -752,23 +663,9 @@ protected
|
|
752
663
|
end
|
753
664
|
return false
|
754
665
|
end
|
755
|
-
|
756
|
-
# Returns an array of all the depdendents in the chain that haven't
|
757
|
-
# been met by the front of the chain.
|
758
|
-
#
|
759
|
-
def unmet_dependents
|
760
|
-
results = []
|
761
|
-
return results if self.empty?
|
762
|
-
duplicate_chain = self.copy
|
763
|
-
last_link = duplicate_chain.pop
|
764
|
-
last_link.dependents.each do |dependent|
|
765
|
-
results.push dependent unless dependent_met?(dependent,duplicate_chain.copy)
|
766
|
-
end
|
767
|
-
return results+duplicate_chain.unmet_dependents
|
768
|
-
end
|
769
666
|
|
770
667
|
# Goes up through each theory in the chain from the position
|
771
|
-
# specifies and yeilds any unment
|
668
|
+
# specifies and yeilds any unment dependents or results and the
|
772
669
|
# theory it belongs to.
|
773
670
|
#
|
774
671
|
# @param approach Either :depndents or :results
|
@@ -794,27 +691,6 @@ protected
|
|
794
691
|
end
|
795
692
|
end
|
796
693
|
|
797
|
-
# Returns a hash of all the unmet dependents down the chain (excluding the head)
|
798
|
-
# and the link/theory that it belongs to.
|
799
|
-
#
|
800
|
-
def unmet_dependents_and_link
|
801
|
-
results = []
|
802
|
-
return results if self.empty?
|
803
|
-
duplicate_chain = self.copy
|
804
|
-
|
805
|
-
# Remove the head link from the chain
|
806
|
-
duplicate_chain.shift
|
807
|
-
|
808
|
-
duplicate_chain.length.times do
|
809
|
-
last_link = duplicate_chain.pop
|
810
|
-
last_link.dependents.each do |d|
|
811
|
-
next if dependent_met?(d,duplicate_chain.copy)
|
812
|
-
results.push({:dependent=>d.copy,:theory=>last_link.copy})
|
813
|
-
end
|
814
|
-
end
|
815
|
-
return results
|
816
|
-
end
|
817
|
-
|
818
694
|
# Removes any results from the head that aren't needed to meet
|
819
695
|
# the dependents of the supplied theories.
|
820
696
|
#
|