adsl 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -20
  3. data/README.md +14 -21
  4. data/bin/adsl-verify +8 -8
  5. data/lib/adsl.rb +3 -0
  6. data/lib/adsl/adsl.rb +3 -0
  7. data/lib/adsl/ds/data_store_spec.rb +339 -0
  8. data/lib/adsl/extract/instrumenter.rb +206 -0
  9. data/lib/adsl/extract/meta.rb +33 -0
  10. data/lib/adsl/extract/rails/action_block_builder.rb +233 -0
  11. data/lib/adsl/extract/rails/action_instrumenter.rb +400 -0
  12. data/lib/adsl/extract/rails/action_runner.rb +57 -0
  13. data/lib/adsl/extract/rails/active_record_metaclass_generator.rb +555 -0
  14. data/lib/adsl/extract/rails/callback_chain_simulator.rb +135 -0
  15. data/lib/adsl/extract/rails/invariant_extractor.rb +48 -0
  16. data/lib/adsl/extract/rails/invariant_instrumenter.rb +70 -0
  17. data/lib/adsl/extract/rails/other_meta.rb +57 -0
  18. data/lib/adsl/extract/rails/rails_extractor.rb +211 -0
  19. data/lib/adsl/extract/rails/rails_instrumentation_test_case.rb +34 -0
  20. data/lib/adsl/extract/rails/rails_special_gem_instrumentation.rb +120 -0
  21. data/lib/adsl/extract/rails/rails_test_helper.rb +140 -0
  22. data/lib/adsl/extract/sexp_utils.rb +54 -0
  23. data/lib/adsl/fol/first_order_logic.rb +261 -0
  24. data/lib/adsl/parser/adsl_parser.racc +159 -0
  25. data/lib/{parser → adsl/parser}/adsl_parser.rex +4 -4
  26. data/lib/{parser → adsl/parser}/adsl_parser.rex.rb +6 -6
  27. data/lib/adsl/parser/adsl_parser.tab.rb +1031 -0
  28. data/lib/adsl/parser/ast_nodes.rb +1410 -0
  29. data/lib/adsl/railtie.rb +67 -0
  30. data/lib/adsl/spass/bin.rb +230 -0
  31. data/lib/{spass → adsl/spass}/ruby_extensions.rb +0 -0
  32. data/lib/adsl/spass/spass_ds_extensions.rb +931 -0
  33. data/lib/adsl/spass/spass_translator.rb +393 -0
  34. data/lib/adsl/spass/util.rb +13 -0
  35. data/lib/adsl/util/csv_hash_formatter.rb +94 -0
  36. data/lib/adsl/util/general.rb +228 -0
  37. data/lib/adsl/util/test_helper.rb +71 -0
  38. data/lib/adsl/verification/formula_generators.rb +231 -0
  39. data/lib/adsl/verification/instrumentation_filter.rb +50 -0
  40. data/lib/adsl/verification/invariant.rb +19 -0
  41. data/lib/adsl/verification/rails_verification.rb +33 -0
  42. data/lib/adsl/verification/utils.rb +20 -0
  43. data/lib/adsl/verification/verification_case.rb +13 -0
  44. data/test/integration/rails/rails_branch_verification_test.rb +112 -0
  45. data/test/integration/rails/rails_verification_test.rb +253 -0
  46. data/test/integration/spass/basic_translation_test.rb +563 -0
  47. data/test/integration/spass/control_flow_translation_test.rb +421 -0
  48. data/test/unit/adsl/ds/data_store_spec_test.rb +54 -0
  49. data/test/unit/adsl/extract/instrumenter_test.rb +103 -0
  50. data/test/unit/adsl/extract/meta_test.rb +142 -0
  51. data/test/unit/adsl/extract/rails/action_block_builder_test.rb +178 -0
  52. data/test/unit/adsl/extract/rails/action_instrumenter_test.rb +68 -0
  53. data/test/unit/adsl/extract/rails/active_record_metaclass_generator_test.rb +336 -0
  54. data/test/unit/adsl/extract/rails/callback_chain_simulator_test.rb +76 -0
  55. data/test/unit/adsl/extract/rails/invariant_extractor_test.rb +92 -0
  56. data/test/unit/adsl/extract/rails/rails_extractor_test.rb +1380 -0
  57. data/test/unit/adsl/extract/rails/rails_test_helper_test.rb +25 -0
  58. data/test/unit/adsl/extract/sexp_utils_test.rb +100 -0
  59. data/test/unit/adsl/fol/first_order_logic_test.rb +227 -0
  60. data/test/unit/adsl/parser/action_parser_test.rb +1040 -0
  61. data/test/unit/adsl/parser/ast_nodes_test.rb +359 -0
  62. data/test/unit/adsl/parser/class_parser_test.rb +288 -0
  63. data/test/unit/adsl/parser/general_parser_test.rb +67 -0
  64. data/test/unit/adsl/parser/invariant_parser_test.rb +432 -0
  65. data/test/unit/adsl/parser/parser_util_test.rb +126 -0
  66. data/test/unit/adsl/spass/bin_test.rb +65 -0
  67. data/test/unit/adsl/spass/ruby_extensions_test.rb +39 -0
  68. data/test/unit/adsl/spass/spass_ds_extensions_test.rb +7 -0
  69. data/test/unit/adsl/spass/spass_translator_test.rb +342 -0
  70. data/test/unit/adsl/util/csv_hash_formatter_test.rb +68 -0
  71. data/test/unit/adsl/util/general_test.rb +303 -0
  72. data/test/unit/adsl/util/test_helper_test.rb +120 -0
  73. data/test/unit/adsl/verification/formula_generators_test.rb +200 -0
  74. data/test/unit/adsl/verification/instrumentation_filter_test.rb +39 -0
  75. data/test/unit/adsl/verification/utils_test.rb +39 -0
  76. data/test/unit/adsl/verification/verification_case_test.rb +8 -0
  77. metadata +229 -29
  78. data/lib/ds/data_store_spec.rb +0 -292
  79. data/lib/fol/first_order_logic.rb +0 -260
  80. data/lib/parser/adsl_ast.rb +0 -779
  81. data/lib/parser/adsl_parser.racc +0 -151
  82. data/lib/parser/adsl_parser.tab.rb +0 -976
  83. data/lib/parser/dsdl_parser.rex.rb +0 -196
  84. data/lib/parser/dsdl_parser.tab.rb +0 -976
  85. data/lib/spass/bin.rb +0 -164
  86. data/lib/spass/spass_ds_extensions.rb +0 -870
  87. data/lib/spass/spass_translator.rb +0 -388
  88. data/lib/spass/util.rb +0 -11
  89. data/lib/util/csv_hash_formatter.rb +0 -47
  90. data/lib/util/test_helper.rb +0 -33
  91. data/lib/util/util.rb +0 -114
@@ -1,164 +0,0 @@
1
- require 'tempfile'
2
- require 'parser/adsl_parser.tab'
3
- require 'spass/spass_ds_extensions'
4
- require 'spass/util'
5
- require 'colorize'
6
- require 'util/util'
7
- require 'util/csv_hash_formatter'
8
-
9
- module Spass
10
- module Bin
11
- include Spass::Util
12
-
13
- def output(term_msg, csv)
14
- if @verification_output == :terminal
15
- if term_msg
16
- print term_msg
17
- STDOUT.flush
18
- end
19
- elsif @verification_output == :csv
20
- @csv_output << csv if csv
21
- else
22
- raise "Unknown verification output #{@verification_output}"
23
- end
24
- end
25
-
26
- def filter_by_name(elems, names)
27
- return elems if names.nil?
28
- filtered = elems.select{ |elem| names.map{ |name| elem.name.include? name}.include? true }
29
- end
30
-
31
- def verify(input, options={})
32
- parser = ADSL::ADSLParser.new
33
- ds_spec = parser.parse input
34
-
35
- stop_on_incorrect = options[:halt_on_error]
36
- check_satisfiability = options[:check_satisfiability]
37
- timeout = options[:timeout]
38
- actions = filter_by_name ds_spec.actions, options[:actions]
39
- invariants = filter_by_name ds_spec.invariants, options[:invariants]
40
-
41
- @csv_output = ::Util::CSVHashFormatter.new
42
-
43
- @verification_output = options[:csv_output] ? :csv : :terminal
44
- do_stats = @verification_output == :csv
45
-
46
- if check_satisfiability
47
- begin
48
- output "Checking for satisfiability...", nil
49
-
50
- translation = nil
51
- translation_time = Time.time_execution do
52
- translation = ds_spec.translate_action nil
53
- end
54
-
55
- result, stats = exec_spass translation, timeout, true
56
- if do_stats
57
- stats[:translation_time] = translation_time
58
- stats[:action] = '<unsatisfiability>'
59
- stats[:result] = result.to_s
60
- end
61
-
62
- if result == :correct
63
- output "\rSatisfiability check #{ 'failed!'.red }", stats
64
- return
65
- elsif result == :inconclusive
66
- output "\rSatisfiability check #{ 'unconclusive'.yellow } ", stats
67
- else
68
- output "\rSatisfiability check #{ 'passed'.green }. ", stats
69
- end
70
- ensure
71
- output "\n", nil
72
- end
73
- end
74
-
75
- actions.each do |action|
76
- invariants.each do |invariant|
77
- output "Verifying action '#{action.name}' with invariant '#{invariant.name}'...", nil
78
- begin
79
- translation = nil
80
- translation_time = Time.time_execution do
81
- translation = ds_spec.translate_action action.name, invariant
82
- end
83
- result, stats = exec_spass translation, timeout, true
84
- if do_stats
85
- stats[:translation_time] = translation_time
86
- stats[:action] = action.name
87
- stats[:invariant] = invariant.name
88
- stats[:result] = result.to_s
89
- end
90
-
91
- case result
92
- when :correct
93
- output "\rAction '#{action.name}' with invariant '#{invariant.name}': #{ 'correct'.green } ", stats
94
- when :incorrect
95
- output "\rAction '#{action.name}' with invariant '#{invariant.name}': #{ 'incorrect'.red } ", stats
96
- return if stop_on_incorrect
97
- when :inconclusive
98
- output "\rAction '#{action.name}' with invariant '#{invariant.name}': #{ 'inconclusive'.yellow } ", stats
99
- else
100
- raise "Unknown exec_spass result: #{result}"
101
- end
102
- rescue => e
103
- # puts translation
104
- raise e
105
- ensure
106
- output "\n", nil
107
- end
108
- end
109
- end
110
- ensure
111
- puts @csv_output.to_s if @verification_output == :csv
112
- @csv_output = nil
113
- end
114
-
115
- def exec_spass(spass_code, timeout=-1, include_stats = false)
116
- tmp_file = Tempfile.new "spass_temp"
117
- tmp_file.write spass_code
118
- tmp_file.close
119
- arg_combos = ["", "-Sorts=0"]
120
- output = process_race(*arg_combos.map{ |a| "SPASS #{a} -TimeLimit=#{timeout} #{tmp_file.path}" })
121
- result = /^SPASS beiseite: (.+)\.$/.match(output)[1]
122
-
123
- stats = include_stats ? pack_stats(spass_code, output) : nil
124
- verdict = nil
125
-
126
- case result
127
- when 'Proof found'
128
- verdict = :correct
129
- when 'Completion found'
130
- verdict = :incorrect
131
- else
132
- verdict = :inconclusive
133
- end
134
- return stats.nil? ? verdict : [verdict, stats]
135
- ensure
136
- tmp_file.delete unless tmp_file.nil?
137
- end
138
-
139
- def pack_stats(spass_code, spass_output)
140
- spass_output = spass_output.split("\n").last(10).join("\n")
141
- stats = {}
142
- stats[:translation_time] = nil # should be set externally
143
-
144
- identifiers = /predicates\s*\[([^\]]*)\]/.match(spass_code)[1].scan(/\w+/)
145
- stats[:spass_predicate_count] = identifiers.length
146
-
147
- formulae = spass_code.scan(/formula\s*\([^\.]+\)\./)
148
- stats[:spass_formula_count] = formulae.length
149
- stats[:average_formula_length] = formulae.inject(0){ |total, formula| total += formula.length} / formulae.length
150
-
151
- times = spass_output.scan(/(\d):(\d\d):(\d\d)\.(\d\d)/)
152
- raise if times.length != 6
153
- times = times.map{ |time| time[3].to_i*10 + time[2].to_i*1000 + time[1].to_i*60*1000 + time[0].to_i*60*60*1000 }
154
- stats[:spass_preparation_time] = times[1..2].sum
155
- stats[:spass_proof_lookup_time] = times[3..5].sum
156
-
157
- stats[:proof_clause_count] = /^SPASS derived (\d+) clauses.*$/.match(spass_output)[1].to_i
158
-
159
- stats[:memory] = /^\s*SPASS allocated (\d+) KBytes.*$/.match(spass_output)[1].to_i
160
-
161
- stats
162
- end
163
- end
164
- end
@@ -1,870 +0,0 @@
1
- require 'fol/first_order_logic'
2
- require 'spass/spass_translator'
3
-
4
- module DS
5
- class DSNode
6
- def replace_var(from, to); end
7
- end
8
-
9
- class DSSpec < DSNode
10
- def translate_action(action_name, *listed_invariants)
11
- translation = SpassTranslator::Translation.new
12
-
13
- if action_name
14
- action = @actions.select{ |a| a.name == action_name }
15
- raise ArgumentError, "Action '#{action_name}' not found" if action.empty?
16
- action = action.first
17
- end
18
-
19
- translation.classes.concat @classes
20
- @classes.each do |klass|
21
- klass.translate(translation)
22
- end
23
-
24
- relations = @classes.map{ |c| c.relations }.flatten
25
- relations.select{ |r| r.inverse_of.nil? }.each do |relation|
26
- relation.translate(translation)
27
- end
28
- relations.select{ |r| r.inverse_of }.each do |relation|
29
- relation.translate(translation)
30
- end
31
-
32
- action.prepare(translation) if action_name
33
-
34
- translation.create_formula FOL::ForAll.new(:o, FOL::Equiv.new(
35
- translation.is_object[:o],
36
- FOL::Or.new(@classes.map{ |c| c[:o] })
37
- ))
38
- @classes.group_by{ |klass| klass.parent }.each do |common_parent, children|
39
- unless common_parent.nil?
40
- translation.create_formula FOL::ForAll.new(:o, FOL::Implies.new(
41
- FOL::Or.new(children.map{ |c| c[:o] }),
42
- common_parent[:o]
43
- ))
44
- end
45
- if children.length > 1
46
- children.each do |child|
47
- translation.create_formula FOL::ForAll.new(:o, FOL::Implies.new(
48
- child[:o],
49
- FOL::Not.new(children.select{ |c| c != child}.map{ |c| c[:o] })
50
- ))
51
- end
52
- end
53
- end
54
-
55
- relations = @classes.map{ |c| c.relations }.flatten.map{ |rel| rel.type_pred }.uniq
56
- translation.create_formula FOL::ForAll.new(:o, FOL::Equiv.new(
57
- translation.is_tuple[:o],
58
- FOL::Or.new(relations.map{ |r| r[:o] })
59
- ))
60
- if relations.length > 1
61
- relations.each do |relation|
62
- translation.create_formula FOL::ForAll.new(:o, FOL::Implies.new(
63
- relation[:o],
64
- FOL::Not.new(relations.select{ |c| c != relation}.map{ |c| c[:o] })
65
- ))
66
- end
67
- end
68
-
69
- translation.create_formula FOL::ForAll.new(:o, FOL::OneOf.new(
70
- translation.is_object[:o],
71
- translation.is_tuple[:o],
72
- translation.is_either_resolution[:o]
73
- ))
74
- translation.create_formula FOL::ForAll.new(:o, FOL::Implies.new(
75
- translation.existed_initially[:o],
76
- FOL::Or.new(translation.is_object[:o], translation.is_tuple[:o])
77
- ))
78
- translation.create_formula FOL::ForAll.new(:o, FOL::Equiv.new(
79
- translation.existed_initially[:o],
80
- translation.prev_state[:o]
81
- ))
82
-
83
- action.translate(translation) if action_name
84
-
85
- if action_name
86
- translation.invariant_state = translation.existed_initially
87
- pre_invariants = @invariants.map{ |invariant| invariant.formula.resolve_invariant_formula(translation) }
88
-
89
- listed_invariants = @invariants if listed_invariants.empty?
90
- translation.invariant_state = translation.exists_finally
91
- post_invariants = listed_invariants.map{ |invariant| invariant.formula.resolve_invariant_formula(translation) }
92
-
93
- translation.create_conjecture FOL::Implies.new(
94
- FOL::And.new(pre_invariants),
95
- FOL::And.new(post_invariants)
96
- ).resolve_spass
97
- else
98
- # used to check for contradictions in the model
99
- invariants_formulae = invariants.map do |invariant|
100
- formula = invariant.formula
101
- dummy_state = translation.create_predicate 'always_true', 1
102
- translation.create_formula FOL::ForAll.new(:o, dummy_state[:o])
103
- translation.invariant_state = dummy_state
104
- formula.resolve_invariant_formula(translation)
105
- end
106
- translation.create_conjecture FOL::Not.new(FOL::And.new(invariants_formulae))
107
- end
108
-
109
- return translation.to_spass_string
110
- end
111
- end
112
-
113
- class DSAction < DSNode
114
- include FOL
115
-
116
- def prepare(translation)
117
- @args.each do |arg|
118
- arg.define_predicate translation
119
- end
120
- @block.prepare translation
121
- end
122
-
123
- def translate(translation)
124
- translation.context = translation.root_context
125
-
126
- @args.length.times do |i|
127
- cardinality = @cardinalities[i]
128
- arg = @args[i]
129
-
130
- translation.create_formula _for_all(:o, _implies(
131
- arg[:o],
132
- _and(translation.existed_initially[:o], arg.type[:o])
133
- ))
134
-
135
- translation.create_formula _exists(:o, arg[:o]) if cardinality[0] > 0
136
- if cardinality[1] == 1
137
- translation.create_formula _for_all(:o1, :o2, _implies(
138
- _and(arg[:o1], arg[:o2]),
139
- _equal(:o1, :o2)
140
- ))
141
- end
142
- end
143
-
144
- @block.migrate_state_spass translation
145
-
146
- translation.create_formula _for_all(:o, _equiv(
147
- translation.exists_finally[:o],
148
- translation.prev_state[:o]
149
- ))
150
- end
151
- end
152
-
153
- class DSClass < DSNode
154
- def [](variable)
155
- @type_pred[variable]
156
- end
157
-
158
- def translate(translation)
159
- @type_pred = translation.create_predicate "of_#{@name}_type", 1
160
- end
161
- end
162
-
163
- class DSRelation < DSNode
164
- include FOL
165
- attr_reader :type_pred, :left_link, :right_link
166
-
167
- def [](variable)
168
- @type_pred[variable]
169
- end
170
-
171
- def translate(translation)
172
- if @inverse_of
173
- @type_pred = @inverse_of.type_pred
174
- @left_link = @inverse_of.right_link
175
- @right_link = @inverse_of.left_link
176
- else
177
- @type_pred = translation.create_predicate "of_#{@from_class.name}_#{@name}_type", 1
178
- @left_link = translation.create_predicate "left_link_#{@from_class.name}_#{@name}", 2
179
- @right_link = translation.create_predicate "right_link_#{@from_class.name}_#{@name}", 2
180
- translation.create_formula _for_all(:t, :o, _implies(@left_link[:t, :o], _and(@from_class[:o], @type_pred[:t])))
181
- translation.create_formula _for_all(:t, :o, _implies(@right_link[:t, :o], _and(@to_class[:o], @type_pred[:t])))
182
- translation.create_formula _for_all(:t, :o1, :o2, _and(
183
- _implies(_and(@left_link[:t, :o1], @left_link[:t, :o2]), _equal(:o1, :o2)),
184
- _implies(_and(@right_link[:t, :o1], @right_link[:t, :o2]), _equal(:o1, :o2))
185
- ))
186
- translation.create_formula _for_all(:t, _implies(
187
- @type_pred[:t],
188
- _exists(:o1, :o2, _and(@left_link[:t, :o1], @right_link[:t, :o2]))
189
- ))
190
- end
191
-
192
- if @cardinality[0] > 0
193
- translation.create_formula _for_all(:o, _implies(@from_class[:o], _exists(:t, @left_link[:t, :o])))
194
- end
195
- if @cardinality[1] == 1
196
- translation.create_formula _for_all(:o, :t1, :t2, _implies(
197
- _and(@left_link[:t1, :o], @left_link[:t2, :o]),
198
- _equal(:t1, :t2)
199
- ))
200
- end
201
- end
202
- end
203
-
204
- class DSCreateObj < DSNode
205
- include FOL
206
- attr_reader :context_creation_link, :context
207
-
208
- def prepare(translation)
209
- @context = translation.context
210
- translation.create_obj_stmts[@klass] << self
211
- @context_creation_link = translation.create_predicate "created_#{@klass.name}_in_context", context.level + 1
212
- end
213
-
214
- def migrate_state_spass(translation)
215
- state = translation.create_state "post_create_#{@klass.name}"
216
- prev_state = translation.prev_state
217
- translation.gen_formula_for_unique_arg(@context_creation_link, (0..@context.level-1), @context.level)
218
- translation.reserve_names @context.p_names, :o do |ps, o|
219
- created_by_other_create_stmts = translation.create_obj_stmts[@klass].select{|s| s != self}.map do |stmt|
220
- formula = nil
221
- translation.reserve_names stmt.context.p_names do |other_ps|
222
- formula = _exists(other_ps, stmt.context_creation_link[other_ps, o])
223
- end
224
- formula
225
- end
226
- created_by_other_create_stmts << translation.existed_initially[o]
227
- child_classes = translation.classes.select{ |c| c.parent == @klass }
228
- not_of_child_types = child_classes.empty? ? true : _and(child_classes.map{ |c| _not(c[o]) })
229
- translation.create_formula _for_all(ps, o, _implies(
230
- @context_creation_link[ps, o], _and(
231
- context.type_pred(ps),
232
- _not(created_by_other_create_stmts),
233
- @klass[o],
234
- not_of_child_types
235
- )
236
- ))
237
- translation.create_formula _for_all(ps, _implies(@context.type_pred(ps), _exists(o,
238
- @context_creation_link[ps, o]
239
- )))
240
- translation.create_formula _for_all(ps, o,
241
- _if_then_else_eq(
242
- @context_creation_link[ps, o],
243
- _and(_not(prev_state[ps, o]), state[ps, o]),
244
- _equiv(prev_state[ps, o], state[ps, o])
245
- )
246
- )
247
-
248
- relevant_from_relations = translation.classes.map{ |c| c.relations }.flatten.select{ |r| r.from_class == @klass }
249
- relevant_to_relations = translation.classes.map{ |c| c.relations }.flatten.select{ |r| r.to_class == @klass }
250
- translation.reserve_names :r do |r|
251
- translation.create_formula _for_all(ps, o, _implies(
252
- @context_creation_link[ps, o],
253
- _for_all(r, _not(_and(
254
- state[ps, r],
255
- _or(
256
- relevant_from_relations.map{ |rel| rel.left_link[r, o] },
257
- relevant_to_relations.map{ |rel| rel.right_link[r, o] }
258
- )
259
- )))
260
- ))
261
- end
262
- end
263
-
264
- translation.prev_state = state
265
- end
266
- end
267
-
268
- class DSCreateObjset < DSNode
269
- include FOL
270
-
271
- def prepare_action(translation); end
272
-
273
- def resolve_action_objset(translation, ps, var)
274
- return @createobj.context_creation_link[ps, var]
275
- end
276
- end
277
-
278
- class DSDeleteObj < DSNode
279
- include FOL
280
- attr_accessor :context_deletion_link
281
-
282
- def prepare(translation)
283
- @objset.prepare_action translation
284
- end
285
-
286
- def migrate_state_spass(translation)
287
- state = translation.create_state "post_delete_#{@objset.type.name}"
288
- prev_state = translation.prev_state
289
- context = translation.context
290
-
291
- translation.reserve_names context.p_names, :o do |ps, o|
292
- translation.create_formula _for_all(ps, o,
293
- _if_then_else_eq(_and(@objset.resolve_action_objset(translation, ps, o), prev_state[ps, o]),
294
- _and(prev_state[ps, o], _not(state[ps, o])),
295
- _equiv(prev_state[ps, o], state[ps, o])
296
- )
297
- )
298
- end
299
-
300
- translation.prev_state = state
301
- end
302
- end
303
-
304
- class DSCreateTup < DSNode
305
- include FOL
306
-
307
- def prepare(translation)
308
- @objset1.prepare_action translation
309
- @objset2.prepare_action translation
310
- end
311
-
312
- def migrate_state_spass(translation)
313
- state = translation.create_state "post_create_#{@relation.from_class.name}_#{@relation.name}"
314
- prev_state = translation.prev_state
315
- context = translation.context
316
-
317
- translation.reserve_names context.p_names, :r, :o1, :o2 do |ps, r, o1, o2|
318
- objset1 = @objset1.resolve_action_objset(translation, ps, o1)
319
- objset2 = @objset2.resolve_action_objset(translation, ps, o2)
320
- translation.create_formula FOL::ForAll.new(ps, r, FOL::Implies.new(
321
- context.type_pred(ps),
322
- FOL::Equiv.new(
323
- state[ps, r],
324
- FOL::Or.new(
325
- prev_state[ps, r],
326
- FOL::Exists.new(o1, o2, FOL::And.new(
327
- prev_state[ps, o1], prev_state[ps, o2],
328
- @relation.left_link[r, o1], @relation.right_link[r, o2],
329
- objset1, objset2
330
- ))
331
- )
332
- )
333
- ))
334
- translation.create_formula FOL::ForAll.new(ps, o1, o2, FOL::Implies.new(
335
- FOL::And.new(prev_state[ps, o1], prev_state[ps, o2], objset1, objset2),
336
- FOL::Exists.new(r, FOL::And.new(state[ps, r], @relation.left_link[r, o1], @relation.right_link[r, o2]))
337
- ))
338
- end
339
- translation.prev_state = state
340
- end
341
- end
342
-
343
- class DSDeleteTup < DSNode
344
- include FOL
345
-
346
- def prepare(translation)
347
- @objset1.prepare_action translation
348
- @objset2.prepare_action translation
349
- end
350
-
351
- def migrate_state_spass(translation)
352
- state = translation.create_state "post_deleteref_#{@relation.from_class.name}_#{@relation.name}"
353
- prev_state = translation.prev_state
354
- context = translation.context
355
-
356
- translation.reserve_names context.p_names, :r, :o1, :o2 do |ps, r, o1, o2|
357
- objset1 = @objset1.resolve_action_objset(translation, ps, o1)
358
- objset2 = @objset2.resolve_action_objset(translation, ps, o2)
359
- translation.create_formula FOL::ForAll.new(ps, r, FOL::Equiv.new(
360
- state[ps, r],
361
- FOL::And.new(
362
- prev_state[ps, r],
363
- FOL::ForAll.new(o1, o2, FOL::Not.new(FOL::And.new(
364
- objset1, objset2,
365
- prev_state[ps, o1], prev_state[ps, o2],
366
- @relation.left_link[r, o1], @relation.right_link[r, o2]
367
- )))
368
- )
369
- ))
370
- end
371
-
372
- translation.prev_state = state
373
- end
374
- end
375
-
376
- class DSEither < DSNode
377
- include FOL
378
- attr_reader :resolution_link, :is_trues
379
-
380
- def prepare(translation)
381
- context = translation.context
382
- @resolution_link = translation.create_predicate :resolution_link, context.level+1
383
- translation.reserve_names context.p_names, :r do |ps, r|
384
- translation.gen_formula_for_unique_arg(@resolution_link, (0..ps.length-1), ps.length)
385
- translation.create_formula _for_all(ps, r, _implies(@resolution_link[ps, r], _and(
386
- translation.context.type_pred(ps),
387
- translation.is_either_resolution[r]
388
- )))
389
- end
390
- @is_trues = []
391
- @blocks.length.times do |i|
392
- is_trues << translation.create_predicate("either_resolution_#{i}_is_true", 1)
393
- end
394
- @blocks.each do |block|
395
- block.prepare(translation)
396
- end
397
- end
398
-
399
- def migrate_state_spass(translation)
400
- post_state = translation.create_state :post_either
401
- prev_state = translation.prev_state
402
- context = translation.context
403
-
404
- pre_states = []
405
- post_states = []
406
- @blocks.length.times do |i|
407
- pre_states << translation.create_state(:pre_of_either)
408
- end
409
- translation.create_formula FOL::ForAll.new(:r, FOL::Implies.new(
410
- translation.is_either_resolution[:r],
411
- FOL::OneOf.new(is_trues.map{ |pred| pred[:r] })
412
- ))
413
-
414
- translation.reserve_names context.p_names, :resolution, :o do |ps, resolution, o|
415
- translation.create_formula FOL::ForAll.new(ps, FOL::Implies.new(
416
- translation.context.type_pred(ps),
417
- FOL::Exists.new(resolution, FOL::And.new(
418
- @resolution_link[ps, resolution],
419
- FOL::And.new((0..@blocks.length-1).map { |i|
420
- FOL::Equiv.new(is_trues[i][resolution], FOL::ForAll.new(o, FOL::Equiv.new(prev_state[ps, o], pre_states[i][ps, o])))
421
- })
422
- ))
423
- ))
424
- end
425
-
426
- @blocks.length.times do |i|
427
- translation.prev_state = pre_states[i]
428
- @blocks[i].migrate_state_spass translation
429
- post_states << translation.prev_state
430
- end
431
-
432
- translation.reserve_names context.p_names, :resolution, :o do |ps, resolution, o|
433
- translation.create_formula FOL::ForAll.new(ps, FOL::Implies.new(
434
- translation.context.type_pred(ps),
435
- FOL::Exists.new(resolution, FOL::And.new(
436
- @resolution_link[ps, resolution],
437
- FOL::And.new((0..@blocks.length-1).map { |i|
438
- FOL::Equiv.new(is_trues[i][resolution], FOL::ForAll.new(o, FOL::Equiv.new(post_state[ps, o], post_states[i][ps, o])))
439
- })
440
- ))
441
- ))
442
- end
443
-
444
- translation.prev_state = post_state
445
- end
446
- end
447
-
448
- class DSEitherLambdaObjset < DSNode
449
- def prepare_action(translation); end
450
-
451
- def resolve_action_objset(translation, ps, o)
452
- translation.reserve_names :r do |r|
453
- implications = []
454
- @either.blocks.length.times do |i|
455
- implications << FOL::Implies.new(@either.is_trues[i][r], @vars[i].resolve_action_objset(translation, ps, o))
456
- end
457
-
458
- return FOL::ForAll.new(:r, FOL::Implies.new(
459
- @either.resolution_link[ps, r],
460
- FOL::And.new(implications)
461
- ))
462
- end
463
- end
464
- end
465
-
466
- class DSForEachCommon < DSNode
467
- include FOL
468
-
469
- attr_reader :context, :pre_iteration_state, :post_iteration_state, :pre_state, :post_state
470
-
471
- def prepare_with_context(translation, flat_context)
472
- @context = translation.create_context "for_each_context", flat_context, translation.context
473
- @objset.prepare_action translation
474
- translation.context = @context
475
- @block.prepare translation
476
- translation.context = @context.parent
477
- end
478
-
479
- def migrate_state_spass(translation)
480
- @pre_state = translation.prev_state
481
- @post_state = translation.create_state :post_for_each
482
-
483
- translation.reserve_names @context.parent.p_names, :o do |ps, o|
484
- translation.create_formula _for_all(ps, o, _equiv(
485
- _and(@objset.resolve_action_objset(translation, ps, o), @pre_state[ps, o]),
486
- @context.type_pred(ps, o)
487
- ))
488
- end
489
-
490
- translation.context = @context
491
-
492
- @pre_iteration_state = translation.create_state :pre_iteration
493
- @post_iteration_state = translation.create_state :post_iteration
494
-
495
- translation.prev_state = @pre_iteration_state
496
- @block.migrate_state_spass translation
497
-
498
- translation.reserve_names @context.p_names, :o do |ps, o|
499
- translation.create_formula _for_all(ps, o, _equiv(
500
- translation.prev_state[ps, o],
501
- @post_iteration_state[ps, o]
502
- ))
503
- end
504
-
505
- create_iteration_formulae translation
506
- translation.context = @context.parent
507
- translation.prev_state = post_state
508
- end
509
- end
510
-
511
- class DSForEach < DSForEachCommon
512
- def prepare(translation)
513
- prepare_with_context(translation, false)
514
- end
515
-
516
- def create_iteration_formulae(translation)
517
- raise "Not implemented for flexible arities"
518
- translation.create_formula _if_then_else_eq(
519
- _exists(:c, :o, _and(old_state[:c, :o], @objset.resolve_action_objset(translation, :c, :o))),
520
- _for_all(:parent, :c, :o, _implies(@context.parent_of_link[:parent, :c], _and(
521
- _if_then_else(
522
- @context.first[:parent, :c],
523
- _equiv(old_state[:parent, :o], @pre_iteration_state[:c, :o]),
524
- _for_all(:prev, _implies(
525
- @context.just_before[:prev, :c],
526
- _equiv(@post_iteration_state[:prev, :o], @pre_iteration_state[:c, :o])
527
- ))
528
- ),
529
- _implies(
530
- @context.last[:parent, :c],
531
- _equiv(@post_state[:parent, :o], @post_iteration_state[:c, :o])
532
- )
533
- ))),
534
- _for_all(:c, :o, _equiv(@pre_state[:c, :o], @post_state[:c, :o]))
535
- )
536
- end
537
- end
538
-
539
- class DSForEachIteratorObjset < DSNode
540
- def prepare_action(translation); end
541
-
542
- def resolve_action_objset(translation, ps, o)
543
- return FOL::Equal.new(o, ps[@for_each.context.level-1])
544
- end
545
- end
546
-
547
- class DSForEachPreLambdaObjset < DSNode
548
- def prepare_action(translation); end
549
-
550
- def resolve_action_objset(translation, ps, o)
551
- raise "Not implemented for flexible arities"
552
- translation.reserve_names :parent, :prev_context do |parent, prev_context|
553
- return FOL::ForAll.new(parent, FOL::Implies.new(@context.parent_of_pred[parent, :c],
554
- FOL::IfThenElseEq.new(
555
- @context.first[parent, c],
556
- @before_var[c, o],
557
- FOL::Exists.new( prev_context, FOL::And.new(
558
- @context.just_before[prev_context, c],
559
- @inside_var[prev_context, o]
560
- ))
561
- )
562
- ))
563
- end
564
- end
565
- end
566
-
567
- class DSFlatForEach < DSForEachCommon
568
- def prepare(translation)
569
- prepare_with_context(translation, true)
570
- end
571
-
572
- def create_iteration_formulae(translation)
573
- context = translation.context
574
- translation.reserve_names context.p_names, :o, :c1, :c2 do |ps, o, c1, c2|
575
- ps_without_last = ps.first(ps.length - 1)
576
- translation.create_formula _for_all(ps, o, _implies(
577
- @context.type_pred(ps),
578
- _equiv(@pre_state[ps_without_last, o], @pre_iteration_state[ps, o])
579
- ))
580
- translation.create_formula _for_all(ps_without_last, o, _if_then_else(
581
- _not(_exists(ps.last, @context.type_pred(ps))),
582
- _equiv(@pre_state[ps_without_last, o], @post_state[ps_without_last, o]),
583
- _implies(
584
- @context.parent.type_pred(ps_without_last),
585
- _equiv(
586
- @post_state[ps_without_last, o],
587
- _or(
588
- _and(
589
- @pre_state[ps_without_last, o],
590
- _for_all(ps.last, _implies(
591
- @context.type_pred(ps),
592
- @post_iteration_state[ps, o]
593
- ))
594
- ),
595
- _and(
596
- _not(@pre_state[ps_without_last, o]),
597
- _exists(ps.last, @post_iteration_state[ps, o])
598
- )
599
- )
600
- )
601
- )
602
- ))
603
- end
604
- end
605
- end
606
-
607
- class DSBlock < DSNode
608
- def prepare(translation)
609
- @statements.each do |stat|
610
- stat.prepare translation
611
- end
612
- end
613
-
614
- def migrate_state_spass(translation)
615
- @statements.each do |stat|
616
- stat.migrate_state_spass translation
617
- end
618
- end
619
- end
620
-
621
- class DSAssignment < DSNode
622
- def prepare(translation)
623
- @var.define_predicate translation
624
- @objset.prepare_action translation
625
- end
626
-
627
- def migrate_state_spass(translation)
628
- context = translation.context
629
- translation.reserve_names context.p_names, :o do |ps, o|
630
- translation.create_formula FOL::ForAll.new(ps, o, FOL::Equiv.new(
631
- var.resolve_action_objset(translation, ps, o),
632
- FOL::And.new(
633
- translation.prev_state[ps, o],
634
- objset.resolve_action_objset(translation, ps, o)
635
- )
636
- ))
637
- end
638
- end
639
- end
640
-
641
- class DSVariable < DSNode
642
- attr_accessor :context, :pred
643
-
644
- def action_name
645
- "var_#{@name}"
646
- end
647
-
648
- # The predicate is not defined in prepare_action
649
- # as we want the predicate to be defined only when assigning to the variable
650
- # not when using it
651
- # a nil check does not work because it makes the translation non-reusable
652
- def prepare_action(translation); end
653
- def define_predicate(translation)
654
- @context = translation.context
655
- @pred = translation.create_predicate action_name, context.level + 1
656
- end
657
-
658
- def resolve_action_objset(translation, ps, var)
659
- return @pred[ps.first(@context.level), var]
660
- end
661
-
662
- def invariant_name
663
- "invariant_var_#{@name}"
664
- end
665
-
666
- def resolve_invariant_objset(translation, var)
667
- FOL::Equal.new(invariant_name, var)
668
- end
669
-
670
- def [](*args)
671
- @pred[args]
672
- end
673
- end
674
-
675
- class DSAllOf < DSNode
676
- def prepare_action(translation); end
677
-
678
- def resolve_action_objset(translation, ps, var)
679
- return @klass[var]
680
- end
681
-
682
- def resolve_invariant_objset(translation, var)
683
- return @klass[var]
684
- end
685
- end
686
-
687
- class DSDereference < DSNode
688
- def prepare_action(translation)
689
- @objset.prepare_action translation
690
- end
691
-
692
- def resolve_action_objset(translation, ps, var)
693
- translation.reserve_names :temp, :r do |temp, r|
694
- return FOL::Exists.new(temp, r, FOL::And.new(
695
- translation.prev_state[ps, r],
696
- translation.prev_state[ps, temp],
697
- @objset.resolve_action_objset(translation, ps, temp),
698
- @relation.left_link[r, temp],
699
- @relation.right_link[r, var]
700
- ))
701
- end
702
- end
703
-
704
- def resolve_invariant_objset(translation, var)
705
- translation.reserve_names :temp, :r do |temp, r|
706
- return FOL::Exists.new(temp, r, FOL::And.new(
707
- translation.invariant_state[temp],
708
- translation.invariant_state[r],
709
- @objset.resolve_invariant_objset(translation, temp),
710
- @relation.left_link[r, temp],
711
- @relation.right_link[r, var]
712
- ))
713
- end
714
- end
715
- end
716
-
717
- class DSSubset < DSNode
718
- def prepare_action(translation)
719
- @objset.prepare_action translation
720
- end
721
-
722
- def resolve_action_objset(translation, ps, var)
723
- context = translation.context
724
- pred = translation.create_predicate :subset, context.level + 1
725
- translation.reserve_names context.p_names do |ps|
726
- translation.create_formula FOL::ForAll.new(ps, :o,
727
- FOL::Implies.new(pred[ps, :o], @objset.resolve_action_objset(translation, ps, :o))
728
- )
729
- end
730
- return pred[ps, var]
731
- end
732
-
733
- def resolve_invariant_objset(translation, var)
734
- pred = translation.create_predicate :subset, 1
735
- translation.create_formula FOL::ForAll.new(:o,
736
- FOL::Implies.new(pred[:o], @objset.resolve_invariant_objset(translation, :o))
737
- )
738
- return pred[var]
739
- end
740
- end
741
-
742
- class DSOr < DSNode
743
- def resolve_invariant_formula(translation)
744
- FOL::Or.new(@subformulae.map{ |sub| sub.resolve_invariant_formula translation })
745
- end
746
- end
747
-
748
- class DSAnd < DSNode
749
- def resolve_invariant_formula(translation)
750
- FOL::And.new(@subformulae.map{ |sub| sub.resolve_invariant_formula translation })
751
- end
752
- end
753
-
754
- class DSEquiv < DSNode
755
- def resolve_invariant_formula(translation)
756
- FOL::Equiv.new(@subformulae.map{ |sub| sub.resolve_invariant_formula translation })
757
- end
758
- end
759
-
760
- class DSImplies < DSNode
761
- def resolve_invariant_formula(translation)
762
- subformula1 = @subformula1.resolve_invariant_formula translation
763
- subformula2 = @subformula2.resolve_invariant_formula translation
764
- FOL::Implies.new(subformula1, subformula2)
765
- end
766
- end
767
-
768
- class DSOneOf < DSNode
769
- def prepare_action(translation)
770
- @objset.prepare_action translation
771
- end
772
-
773
- def resolve_action_objset(translation, ps, var)
774
- context = translation.context
775
- pred = translation.create_predicate :one_of, context.level + 1
776
- translation.gen_formula_for_unique_arg(pred, context.level)
777
- translation.reserve_names context.p_names, :o do |subps, o|
778
- co_in_objset = @objset.resolve_action_objset(translation, subps, o)
779
- translation.create_formula FOL::ForAll.new(subps, FOL::Equiv.new(
780
- FOL::Exists.new(o, FOL::And.new(translation.prev_state[subps, o], pred[subps, o])),
781
- FOL::Exists.new(o, FOL::And.new(translation.prev_state[subps, o], co_in_objset))
782
- ))
783
- translation.create_formula FOL::ForAll.new(subps, o,
784
- FOL::Implies.new(pred[subps, o], FOL::And.new(translation.prev_state[subps, o], co_in_objset))
785
- )
786
- end
787
- return pred[ps, var]
788
- end
789
- end
790
-
791
- class DSNot < DSNode
792
- def resolve_invariant_formula(translation)
793
- subformula = @subformula.resolve_invariant_formula translation
794
- return FOL::Not.new(subformula)
795
- end
796
- end
797
-
798
- class DSBoolean < DSNode
799
- def resolve_invariant_formula(translation)
800
- return @bool_value.resolve_spass
801
- end
802
- end
803
-
804
- class DSForAll < DSNode
805
- def resolve_invariant_formula(translation)
806
- subformula = @subformula.resolve_invariant_formula translation
807
- var_constraints = []
808
- @vars.length.times do |index|
809
- var_constraints << @objsets[index].resolve_invariant_objset(translation, @vars[index].invariant_name)
810
- end
811
- return FOL::ForAll.new(@vars.map{ |v| v.invariant_name }, FOL::Implies.new(
812
- FOL::And.new(
813
- @vars.map{ |v| translation.invariant_state[v.invariant_name] },
814
- var_constraints
815
- ),
816
- subformula
817
- )).resolve_spass
818
- end
819
- end
820
-
821
- class DSExists < DSNode
822
- def resolve_invariant_formula(translation)
823
- subformula = @subformula.nil? ? true : @subformula.resolve_invariant_formula(translation)
824
- subformula ||= true
825
- return FOL::Exists.new(@vars.map{ |v| v.invariant_name }, FOL::And.new(
826
- @vars.map{ |v| translation.invariant_state[v.invariant_name] },
827
- @vars.map{ |v| v.type[v.invariant_name] },
828
- @vars.map{ |v| v.resolve_invariant_objset(translation, v.invariant_name) },
829
- subformula
830
- )).resolve_spass
831
- end
832
- end
833
-
834
- class DSEqual < DSNode
835
- def resolve_invariant_formula(translation)
836
- translation.reserve_names :temp do |temp|
837
- objsets = @objsets.map{ |o| o.resolve_invariant_objset translation, temp }
838
- return FOL::ForAll.new(temp, FOL::Implies.new(
839
- translation.invariant_state[temp],
840
- FOL::Equiv.new(objsets)
841
- )).resolve_spass
842
- end
843
- end
844
- end
845
-
846
- class DSIn < DSNode
847
- def resolve_invariant_formula(translation)
848
- translation.reserve_names :temp do |temp|
849
- return FOL::ForAll.new(temp, FOL::Implies.new(
850
- translation.invariant_state[temp],
851
- FOL::Implies.new(
852
- @objset1.resolve_invariant_objset(translation, temp),
853
- @objset2.resolve_invariant_objset(translation, temp)
854
- )
855
- ))
856
- end
857
- end
858
- end
859
-
860
- class DSEmpty < DSNode
861
- def resolve_invariant_formula(translation)
862
- translation.reserve_names :temp do |temp|
863
- return FOL::ForAll.new(temp, FOL::Implies.new(
864
- translation.invariant_state[temp],
865
- FOL::Not.new(@objset.resolve_invariant_objset(translation, temp))
866
- ))
867
- end
868
- end
869
- end
870
- end