adsl 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -20
- data/README.md +14 -21
- data/bin/adsl-verify +8 -8
- data/lib/adsl.rb +3 -0
- data/lib/adsl/adsl.rb +3 -0
- data/lib/adsl/ds/data_store_spec.rb +339 -0
- data/lib/adsl/extract/instrumenter.rb +206 -0
- data/lib/adsl/extract/meta.rb +33 -0
- data/lib/adsl/extract/rails/action_block_builder.rb +233 -0
- data/lib/adsl/extract/rails/action_instrumenter.rb +400 -0
- data/lib/adsl/extract/rails/action_runner.rb +57 -0
- data/lib/adsl/extract/rails/active_record_metaclass_generator.rb +555 -0
- data/lib/adsl/extract/rails/callback_chain_simulator.rb +135 -0
- data/lib/adsl/extract/rails/invariant_extractor.rb +48 -0
- data/lib/adsl/extract/rails/invariant_instrumenter.rb +70 -0
- data/lib/adsl/extract/rails/other_meta.rb +57 -0
- data/lib/adsl/extract/rails/rails_extractor.rb +211 -0
- data/lib/adsl/extract/rails/rails_instrumentation_test_case.rb +34 -0
- data/lib/adsl/extract/rails/rails_special_gem_instrumentation.rb +120 -0
- data/lib/adsl/extract/rails/rails_test_helper.rb +140 -0
- data/lib/adsl/extract/sexp_utils.rb +54 -0
- data/lib/adsl/fol/first_order_logic.rb +261 -0
- data/lib/adsl/parser/adsl_parser.racc +159 -0
- data/lib/{parser → adsl/parser}/adsl_parser.rex +4 -4
- data/lib/{parser → adsl/parser}/adsl_parser.rex.rb +6 -6
- data/lib/adsl/parser/adsl_parser.tab.rb +1031 -0
- data/lib/adsl/parser/ast_nodes.rb +1410 -0
- data/lib/adsl/railtie.rb +67 -0
- data/lib/adsl/spass/bin.rb +230 -0
- data/lib/{spass → adsl/spass}/ruby_extensions.rb +0 -0
- data/lib/adsl/spass/spass_ds_extensions.rb +931 -0
- data/lib/adsl/spass/spass_translator.rb +393 -0
- data/lib/adsl/spass/util.rb +13 -0
- data/lib/adsl/util/csv_hash_formatter.rb +94 -0
- data/lib/adsl/util/general.rb +228 -0
- data/lib/adsl/util/test_helper.rb +71 -0
- data/lib/adsl/verification/formula_generators.rb +231 -0
- data/lib/adsl/verification/instrumentation_filter.rb +50 -0
- data/lib/adsl/verification/invariant.rb +19 -0
- data/lib/adsl/verification/rails_verification.rb +33 -0
- data/lib/adsl/verification/utils.rb +20 -0
- data/lib/adsl/verification/verification_case.rb +13 -0
- data/test/integration/rails/rails_branch_verification_test.rb +112 -0
- data/test/integration/rails/rails_verification_test.rb +253 -0
- data/test/integration/spass/basic_translation_test.rb +563 -0
- data/test/integration/spass/control_flow_translation_test.rb +421 -0
- data/test/unit/adsl/ds/data_store_spec_test.rb +54 -0
- data/test/unit/adsl/extract/instrumenter_test.rb +103 -0
- data/test/unit/adsl/extract/meta_test.rb +142 -0
- data/test/unit/adsl/extract/rails/action_block_builder_test.rb +178 -0
- data/test/unit/adsl/extract/rails/action_instrumenter_test.rb +68 -0
- data/test/unit/adsl/extract/rails/active_record_metaclass_generator_test.rb +336 -0
- data/test/unit/adsl/extract/rails/callback_chain_simulator_test.rb +76 -0
- data/test/unit/adsl/extract/rails/invariant_extractor_test.rb +92 -0
- data/test/unit/adsl/extract/rails/rails_extractor_test.rb +1380 -0
- data/test/unit/adsl/extract/rails/rails_test_helper_test.rb +25 -0
- data/test/unit/adsl/extract/sexp_utils_test.rb +100 -0
- data/test/unit/adsl/fol/first_order_logic_test.rb +227 -0
- data/test/unit/adsl/parser/action_parser_test.rb +1040 -0
- data/test/unit/adsl/parser/ast_nodes_test.rb +359 -0
- data/test/unit/adsl/parser/class_parser_test.rb +288 -0
- data/test/unit/adsl/parser/general_parser_test.rb +67 -0
- data/test/unit/adsl/parser/invariant_parser_test.rb +432 -0
- data/test/unit/adsl/parser/parser_util_test.rb +126 -0
- data/test/unit/adsl/spass/bin_test.rb +65 -0
- data/test/unit/adsl/spass/ruby_extensions_test.rb +39 -0
- data/test/unit/adsl/spass/spass_ds_extensions_test.rb +7 -0
- data/test/unit/adsl/spass/spass_translator_test.rb +342 -0
- data/test/unit/adsl/util/csv_hash_formatter_test.rb +68 -0
- data/test/unit/adsl/util/general_test.rb +303 -0
- data/test/unit/adsl/util/test_helper_test.rb +120 -0
- data/test/unit/adsl/verification/formula_generators_test.rb +200 -0
- data/test/unit/adsl/verification/instrumentation_filter_test.rb +39 -0
- data/test/unit/adsl/verification/utils_test.rb +39 -0
- data/test/unit/adsl/verification/verification_case_test.rb +8 -0
- metadata +229 -29
- data/lib/ds/data_store_spec.rb +0 -292
- data/lib/fol/first_order_logic.rb +0 -260
- data/lib/parser/adsl_ast.rb +0 -779
- data/lib/parser/adsl_parser.racc +0 -151
- data/lib/parser/adsl_parser.tab.rb +0 -976
- data/lib/parser/dsdl_parser.rex.rb +0 -196
- data/lib/parser/dsdl_parser.tab.rb +0 -976
- data/lib/spass/bin.rb +0 -164
- data/lib/spass/spass_ds_extensions.rb +0 -870
- data/lib/spass/spass_translator.rb +0 -388
- data/lib/spass/util.rb +0 -11
- data/lib/util/csv_hash_formatter.rb +0 -47
- data/lib/util/test_helper.rb +0 -33
- data/lib/util/util.rb +0 -114
@@ -0,0 +1,393 @@
|
|
1
|
+
require 'adsl/spass/ruby_extensions'
|
2
|
+
require 'adsl/fol/first_order_logic'
|
3
|
+
|
4
|
+
module ADSL
|
5
|
+
module Spass
|
6
|
+
module SpassTranslator
|
7
|
+
|
8
|
+
def replace_conjecture(input, conjecture)
|
9
|
+
input.gsub(/list_of_formulae\s*\(\s*conjectures\s*\)\s*\..*?end_of_list\./m, <<-SPASS)
|
10
|
+
list_of_formulae(conjectures).
|
11
|
+
formula(#{conjecture.resolve_spass}).
|
12
|
+
end_of_list.
|
13
|
+
SPASS
|
14
|
+
end
|
15
|
+
|
16
|
+
class Predicate
|
17
|
+
attr_accessor :name, :arity
|
18
|
+
|
19
|
+
include FOL
|
20
|
+
|
21
|
+
def initialize(name, arity)
|
22
|
+
@name = name
|
23
|
+
@arity = arity
|
24
|
+
end
|
25
|
+
|
26
|
+
def [](*args)
|
27
|
+
args = args.flatten
|
28
|
+
return "#{@name}(#{ (1..@arity).map{ |i| "${#{i}}"}.join(", ") })".resolve_params(*args)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class ContextCommon
|
33
|
+
attr_accessor :parent, :level
|
34
|
+
|
35
|
+
def type_pred(*args)
|
36
|
+
return @level == 0 ? 'true' : @type_pred[*args.flatten]
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize(translation, name, parent)
|
40
|
+
@level = parent.nil? ? 0 : parent.level + 1
|
41
|
+
@translation = translation
|
42
|
+
@parent = parent
|
43
|
+
|
44
|
+
unless parent.nil?
|
45
|
+
@type_pred = translation.create_predicate(name, @level)
|
46
|
+
|
47
|
+
translation.reserve_names @parent.p_names do |ps|
|
48
|
+
translation.create_formula FOL::ForAll.new(ps, :c, FOL::Implies.new(
|
49
|
+
type_pred(ps, :c), @parent.type_pred(ps)
|
50
|
+
))
|
51
|
+
end
|
52
|
+
translation.reserve_names @parent.p_names, @parent.p_names, :c do |p1s, p2s, c|
|
53
|
+
translation.create_formula FOL::ForAll.new(p1s, p2s, :c, FOL::Implies.new(
|
54
|
+
FOL::And.new(type_pred(p1s, c), type_pred(p2s, c)),
|
55
|
+
FOL::PairwiseEqual.new(p1s, p2s)
|
56
|
+
))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def same_level_before_formula(parents, c1, c2)
|
62
|
+
raise 'To be implemented'
|
63
|
+
end
|
64
|
+
|
65
|
+
def p_names(num = level)
|
66
|
+
num.times.map{ |i| "p#{i+1}".to_sym }
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.get_common_context(c1, c2)
|
70
|
+
while c1.level > c2.level
|
71
|
+
c1 = c1.parent
|
72
|
+
end
|
73
|
+
while c2.level > c1.level
|
74
|
+
c2 = c2.parent
|
75
|
+
end
|
76
|
+
while c1 != c2
|
77
|
+
c1 = c1.parent
|
78
|
+
c2 = c2.parent
|
79
|
+
end
|
80
|
+
return c1
|
81
|
+
end
|
82
|
+
|
83
|
+
def before(c2, c1var, c2var, executed_before)
|
84
|
+
c1 = self
|
85
|
+
@translation.reserve_names((1..c1.level-1).map{|i| "parent_a#{i}"}) do |context1_names|
|
86
|
+
@translation.reserve_names((1..c2.level-1).map{|i| "parent_b#{i}"}) do |context2_names|
|
87
|
+
context1_names << c1var
|
88
|
+
context2_names << c2var
|
89
|
+
common_context = ContextCommon.get_common_context c1, c2
|
90
|
+
prereq_formulae = FOL::And.new(c1.type_pred(context1_names), c2.type_pred(context2_names))
|
91
|
+
|
92
|
+
solution = executed_before
|
93
|
+
parent_args = context1_names.first(common_context.level)
|
94
|
+
parent_args.pop
|
95
|
+
while common_context.parent
|
96
|
+
c1_name = context1_names[common_context.level-1]
|
97
|
+
c2_name = context2_names[common_context.level-1]
|
98
|
+
solution = FOL::And.new(
|
99
|
+
FOL::Implies.new(common_context.same_level_before_formula(parent_args, c1_name, c2_name), true),
|
100
|
+
FOL::Implies.new(common_context.same_level_before_formula(parent_args, c2_name, c1_name), false),
|
101
|
+
FOL::Implies.new(
|
102
|
+
FOL::Not.new(
|
103
|
+
common_context.same_level_before_formula(parent_args, c1_name, c2_name),
|
104
|
+
common_context.same_level_before_formula(parent_args, c2_name, c1_name)
|
105
|
+
),
|
106
|
+
solution
|
107
|
+
)
|
108
|
+
)
|
109
|
+
common_context = common_context.parent
|
110
|
+
parent_args.pop
|
111
|
+
end
|
112
|
+
solution = FOL::Implies.new(FOL::And.new(prereq_formulae), solution)
|
113
|
+
if context1_names.length > 1 or context2_names.length > 1
|
114
|
+
solution = FOL::ForAll.new([context1_names[0..-2], context2_names[0..-2]], solution)
|
115
|
+
end
|
116
|
+
return solution
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
class FlatContext < ContextCommon
|
123
|
+
def initialize(translation, name, parent)
|
124
|
+
super
|
125
|
+
end
|
126
|
+
|
127
|
+
def same_level_before_formula(ps, c1, c2)
|
128
|
+
false
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class ChainedContext < ContextCommon
|
133
|
+
attr_accessor :before_pred, :just_before, :first, :last
|
134
|
+
include FOL
|
135
|
+
|
136
|
+
def initialize(translation, name, parent)
|
137
|
+
super
|
138
|
+
|
139
|
+
@before_pred = translation.create_predicate "#{@type_pred.name}_before", @type_pred.arity + 1
|
140
|
+
@just_before = translation.create_predicate "#{@type_pred.name}_just_before", @type_pred.arity + 1
|
141
|
+
@first = translation.create_predicate "#{@type_pred.name}_first", @type_pred.arity
|
142
|
+
@last = translation.create_predicate "#{@type_pred.name}_last", @type_pred.arity
|
143
|
+
|
144
|
+
ps = []
|
145
|
+
(@type_pred.arity-1).times{ |i| ps << "p#{i}" }
|
146
|
+
translation.create_formula _for_all(ps, :c, _not(@before_pred[ps, :c, :c]))
|
147
|
+
translation.create_formula _for_all(ps, :c1, :c2, _implies(@before_pred[ps, :c1, :c2], _and(
|
148
|
+
@type_pred[ps, :c1],
|
149
|
+
@type_pred[ps, :c2],
|
150
|
+
_not(@before_pred[ps, :c2, :c1]),
|
151
|
+
_implies(
|
152
|
+
_and(@type_pred[ps, :c1], @type_pred[ps, :c2]),
|
153
|
+
_or(_equal(:c1, :c2), @before_pred[ps, :c1, :c2], @before_pred[ps, :c2, :c1])
|
154
|
+
)
|
155
|
+
)))
|
156
|
+
translation.create_formula _for_all(ps, :c1, :c2, :c3, _implies(
|
157
|
+
_and(@before_pred[ps, :c1, :c2], @before_pred[ps, :c2, :c3]),
|
158
|
+
@before_pred[ps, :c1, :c3]
|
159
|
+
))
|
160
|
+
translation.create_formula _for_all(ps, :c1, :c2, _equiv(
|
161
|
+
@just_before[ps, :c1, :c2],
|
162
|
+
_and(
|
163
|
+
@before_pred[ps, :c1, :c2],
|
164
|
+
_not(_exists(:mid, _and(@before_pred[ps, :c1, :mid], @before_pred[ps, :mid, :c2])))
|
165
|
+
)
|
166
|
+
))
|
167
|
+
translation.create_formula _for_all(ps, _and(
|
168
|
+
_equiv(
|
169
|
+
_exists(:c, @type_pred[ps, :c]),
|
170
|
+
_exists(:c, @first[ps, :c]),
|
171
|
+
_exists(:c, @last[ps, :c])
|
172
|
+
),
|
173
|
+
_for_all(ps, :c, _implies(
|
174
|
+
@type_pred[ps, :c],
|
175
|
+
_one_of(@last[ps, :c], _exists(:next, @just_before[ps, :c, :next]))
|
176
|
+
)),
|
177
|
+
_for_all(ps, :c, _equiv(@first[ps, :c],
|
178
|
+
_and(@type_pred[ps, :c], _not(_exists(:pre, @before_pred[ps, :pre, :c])))
|
179
|
+
)),
|
180
|
+
_for_all(ps, :c, _equiv(@last[ps, :c],
|
181
|
+
_and(@type_pred[ps, :c], _not(_exists(:post, @before_pred[ps, :c, :post])))
|
182
|
+
))
|
183
|
+
))
|
184
|
+
end
|
185
|
+
|
186
|
+
def same_level_before_formula(ps, c1, c2)
|
187
|
+
@before_pred[ps, c1, c2]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
class Translation
|
192
|
+
attr_accessor :context, :prev_state, :invariant_state
|
193
|
+
attr_reader :existed_initially, :exists_finally, :root_context
|
194
|
+
attr_reader :is_object, :is_tuple, :is_either_resolution, :resolved_as_true
|
195
|
+
attr_reader :create_obj_stmts, :delete_obj_stmts, :all_contexts, :classes
|
196
|
+
attr_reader :conjectures
|
197
|
+
|
198
|
+
include FOL
|
199
|
+
|
200
|
+
def initialize
|
201
|
+
@classes = []
|
202
|
+
@temp_vars = []
|
203
|
+
@functions = []
|
204
|
+
@predicates = []
|
205
|
+
@formulae = [[]]
|
206
|
+
@conjectures = []
|
207
|
+
@all_contexts = []
|
208
|
+
@existed_initially = create_predicate :existed_initially, 1
|
209
|
+
@exists_finally = create_predicate :exists_finally, 1
|
210
|
+
@is_object = create_predicate :is_object, 1
|
211
|
+
@is_tuple = create_predicate :is_tuple, 1
|
212
|
+
@is_either_resolution = create_predicate :is_either_resolution, 1
|
213
|
+
@root_context = create_context 'root_context', true, nil
|
214
|
+
@context = @root_context
|
215
|
+
# {class => [[before_stmt, context], [after_stmt, context]]}
|
216
|
+
@create_obj_stmts = Hash.new{ |hash, klass| hash[klass] = [] }
|
217
|
+
@delete_obj_stmts = Hash.new{ |hash, klass| hash[klass] = [] }
|
218
|
+
@prev_state = create_state :init_state
|
219
|
+
|
220
|
+
@invariant_state = nil
|
221
|
+
end
|
222
|
+
|
223
|
+
def create_state name
|
224
|
+
state = create_predicate name, @context.level + 1
|
225
|
+
reserve_names([:c_1] * @context.level, :o) do |cs, o|
|
226
|
+
create_formula FOL::ForAll.new(cs, o, FOL::Implies.new(
|
227
|
+
state[cs, o],
|
228
|
+
FOL::And.new(@context.type_pred(cs), FOL::Or.new(@is_object[o], @is_tuple[o]))
|
229
|
+
))
|
230
|
+
end
|
231
|
+
state
|
232
|
+
end
|
233
|
+
|
234
|
+
def create_context(name, flat, parent)
|
235
|
+
context = nil
|
236
|
+
if flat
|
237
|
+
context = FlatContext.new self, name, parent
|
238
|
+
else
|
239
|
+
context = ChainedContext.new self, name, parent
|
240
|
+
end
|
241
|
+
@all_contexts << context
|
242
|
+
context
|
243
|
+
end
|
244
|
+
|
245
|
+
def push_formula_frame
|
246
|
+
@formulae.push []
|
247
|
+
end
|
248
|
+
|
249
|
+
def pop_formula_frame
|
250
|
+
@formulae.pop
|
251
|
+
end
|
252
|
+
|
253
|
+
def create_formula(formula)
|
254
|
+
raise ArgumentError, 'Formula not resolveable to Spass' unless formula.class.method_defined? :resolve_spass
|
255
|
+
@formulae.last.push formula
|
256
|
+
end
|
257
|
+
|
258
|
+
def create_conjecture(formula)
|
259
|
+
raise ArgumentError, 'Formula not resolveable to Spass' unless formula.class.method_defined? :resolve_spass
|
260
|
+
@conjectures.push formula
|
261
|
+
end
|
262
|
+
|
263
|
+
def create_function(name, arity)
|
264
|
+
function = Predicate.new get_pred_name(name.to_s), arity
|
265
|
+
@functions << function
|
266
|
+
function
|
267
|
+
end
|
268
|
+
|
269
|
+
def create_predicate(name, arity)
|
270
|
+
pred = Predicate.new get_pred_name(name.to_s), arity
|
271
|
+
@predicates << pred
|
272
|
+
pred
|
273
|
+
end
|
274
|
+
|
275
|
+
def get_pred_name common_name
|
276
|
+
registered_names = (@functions + @predicates).map{ |a| a.name }
|
277
|
+
prefix = common_name
|
278
|
+
prefix = common_name.scan(/^(.+)_\d+$/).first.first if prefix =~ /^.+_\d+$/
|
279
|
+
regexp = /^#{ Regexp.escape prefix }(?:_(\d+))?$/
|
280
|
+
|
281
|
+
already_registered = registered_names.select{ |a| a =~ regexp }
|
282
|
+
return common_name if already_registered.empty?
|
283
|
+
|
284
|
+
rhs_numbers = already_registered.map{ |a| [a, a.scan(regexp).first.first] }
|
285
|
+
|
286
|
+
rhs_numbers.each do |a|
|
287
|
+
a[1] = a[1].nil? ? -1 : a[1].to_i
|
288
|
+
end
|
289
|
+
|
290
|
+
max_name = rhs_numbers.max_by{ |a| a[1] }
|
291
|
+
return max_name[0].increment_suffix
|
292
|
+
end
|
293
|
+
|
294
|
+
def _reserve_names(*names)
|
295
|
+
result = []
|
296
|
+
names.each do |name|
|
297
|
+
if name.is_a? Array
|
298
|
+
result << _reserve_names(*name)
|
299
|
+
else
|
300
|
+
while @temp_vars.include? name
|
301
|
+
name = name.to_s.increment_suffix.to_sym
|
302
|
+
end
|
303
|
+
@temp_vars.push name
|
304
|
+
result << name
|
305
|
+
end
|
306
|
+
end
|
307
|
+
result
|
308
|
+
end
|
309
|
+
|
310
|
+
def reserve_names(*names)
|
311
|
+
result = _reserve_names(*names)
|
312
|
+
yield *result
|
313
|
+
ensure
|
314
|
+
names.flatten.length.times do
|
315
|
+
@temp_vars.pop
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
def gen_formula_for_unique_arg(pred, *args)
|
320
|
+
individuals = []
|
321
|
+
args.each do |arg|
|
322
|
+
arg = arg.is_a?(Range) ? arg.to_a : [arg].flatten
|
323
|
+
next if arg.empty?
|
324
|
+
vars1 = (1..pred.arity).map{ |i| "e#{i}" }
|
325
|
+
vars2 = vars1.dup
|
326
|
+
as = []
|
327
|
+
bs = []
|
328
|
+
arg.each do |index|
|
329
|
+
a = "a#{index+1}".to_sym
|
330
|
+
vars1[index] = a
|
331
|
+
b = "b#{index+1}".to_sym
|
332
|
+
vars2[index] = b
|
333
|
+
as << a
|
334
|
+
bs << b
|
335
|
+
end
|
336
|
+
reserve_names (vars1 | vars2) do
|
337
|
+
individuals << _for_all(vars1 | vars2, _implies(_and(pred[vars1], pred[vars2]), _pairwise_equal(as, bs)))
|
338
|
+
end
|
339
|
+
end
|
340
|
+
return true if individuals.empty?
|
341
|
+
formula = _and(individuals)
|
342
|
+
create_formula formula
|
343
|
+
return formula
|
344
|
+
end
|
345
|
+
|
346
|
+
def spass_wrap(with, what)
|
347
|
+
return "" if what.length == 0
|
348
|
+
return with % what
|
349
|
+
end
|
350
|
+
|
351
|
+
def spass_list_of(what, *content)
|
352
|
+
spass_wrap "list_of_#{what.to_s}.%s\nend_of_list.", content.flatten.map{ |c| "\n " + c.to_s }.join("")
|
353
|
+
end
|
354
|
+
|
355
|
+
def to_spass_string
|
356
|
+
functions = @functions.map{ |f| "(#{f.name}, #{f.arity})" }.join(", ")
|
357
|
+
predicates = @predicates.map{ |p| "(#{p.name}, #{p.arity})" }.join(", ")
|
358
|
+
formulae = @formulae.first.map do |f|
|
359
|
+
begin
|
360
|
+
next "formula(#{f.resolve_spass})."
|
361
|
+
rescue => e
|
362
|
+
pp f
|
363
|
+
raise e
|
364
|
+
end
|
365
|
+
end
|
366
|
+
conjectures = @conjectures.map{ |f| "formula(#{f.resolve_spass})." }
|
367
|
+
<<-SPASS
|
368
|
+
begin_problem(Blahblah).
|
369
|
+
list_of_descriptions.
|
370
|
+
name({* *}).
|
371
|
+
author({* *}).
|
372
|
+
status(satisfiable).
|
373
|
+
description( {* *} ).
|
374
|
+
end_of_list.
|
375
|
+
#{spass_list_of( :symbols,
|
376
|
+
spass_wrap("functions[%s].", functions),
|
377
|
+
spass_wrap("predicates[%s].", predicates)
|
378
|
+
)}
|
379
|
+
#{spass_list_of( "formulae(axioms)",
|
380
|
+
formulae
|
381
|
+
)}
|
382
|
+
#{spass_list_of( "formulae(conjectures)",
|
383
|
+
conjectures
|
384
|
+
)}
|
385
|
+
end_problem.
|
386
|
+
SPASS
|
387
|
+
end
|
388
|
+
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
end
|
393
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ADSL
|
2
|
+
module Spass
|
3
|
+
module Util
|
4
|
+
def replace_conjecture(input, conjecture)
|
5
|
+
input.gsub(/list_of_formulae\s*\(\s*conjectures\s*\)\s*\..*?end_of_list\./m, <<-SPASS)
|
6
|
+
list_of_formulae(conjectures).
|
7
|
+
formula(#{conjecture.resolve_spass}).
|
8
|
+
end_of_list.
|
9
|
+
SPASS
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# A writer into CSV format that takes lines in hash format
|
2
|
+
# row = {:column1 => value1, :column2 => value2, ... }
|
3
|
+
# All rows are buffered together and a csv file is output with
|
4
|
+
# the union of individual column sets
|
5
|
+
# if the order of columns matter, supply an OrderedHash
|
6
|
+
# instance for each row
|
7
|
+
|
8
|
+
require 'set'
|
9
|
+
|
10
|
+
module ADSL
|
11
|
+
module Util
|
12
|
+
class CSVHashFormatter
|
13
|
+
def escape_str(obj)
|
14
|
+
"\"#{obj.to_s.gsub('"', '""')}\""
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(*cols)
|
18
|
+
@row_hashes = []
|
19
|
+
@columns = []
|
20
|
+
cols.each do |col|
|
21
|
+
add_column col
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def prepare_for_csv(row)
|
26
|
+
row.keys.each do |col|
|
27
|
+
row[col] = row[col].to_s if row[col].is_a? Symbol
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_row(row)
|
32
|
+
prepare_for_csv row
|
33
|
+
@row_hashes << row
|
34
|
+
row.keys.each do |key|
|
35
|
+
add_column key unless @columns.include? key
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_column(col)
|
40
|
+
raise "Duplicate column name #{col}" if @columns.include? col.to_sym
|
41
|
+
@columns << col.to_sym
|
42
|
+
end
|
43
|
+
|
44
|
+
alias_method :<<, :add_row
|
45
|
+
|
46
|
+
def column_type(col)
|
47
|
+
type = nil
|
48
|
+
@row_hashes.each do |row|
|
49
|
+
next if row[col].nil?
|
50
|
+
if row[col].is_a?(Numeric) && type.nil?
|
51
|
+
type = Numeric
|
52
|
+
elsif row[col].is_a?(String) || row[col].is_a?(Symbol)
|
53
|
+
type = String
|
54
|
+
end
|
55
|
+
end
|
56
|
+
type
|
57
|
+
end
|
58
|
+
|
59
|
+
def infer_column_types
|
60
|
+
types = {}
|
61
|
+
@columns.each do |col|
|
62
|
+
types[col] = column_type col
|
63
|
+
end
|
64
|
+
types
|
65
|
+
end
|
66
|
+
|
67
|
+
def sort!(*columns)
|
68
|
+
types = infer_column_types
|
69
|
+
@row_hashes.sort_by! do |row|
|
70
|
+
columns.map do |col|
|
71
|
+
if types[col] == nil
|
72
|
+
nil
|
73
|
+
elsif types[col] == Numeric
|
74
|
+
row[col] || -Float::INFINITY
|
75
|
+
else
|
76
|
+
row[col] || ''
|
77
|
+
end
|
78
|
+
end.to_a
|
79
|
+
end
|
80
|
+
self
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_s
|
84
|
+
return '' if @columns.empty?
|
85
|
+
output = @columns.map{ |c| escape_str(c) }.join(',') + "\n"
|
86
|
+
types = infer_column_types
|
87
|
+
@row_hashes.each do |row|
|
88
|
+
output += @columns.map{ |c| types[c] == Numeric ? (row[c] || '') : escape_str(row[c] || '') }.join(',') + "\n"
|
89
|
+
end
|
90
|
+
output
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|