adsl 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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
|