oakproof 0.7.1
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 +7 -0
- data/eprover/eprover-2.3-linux +0 -0
- data/eprover/eprover-2.3-mac +0 -0
- data/eprover/eprover-2.3-windows.exe +0 -0
- data/eprover/eprover.txt +5 -0
- data/oak +3 -0
- data/src/bindings.rb +464 -0
- data/src/commands.rb +349 -0
- data/src/external prover.rb +189 -0
- data/src/grammar rules.rb +439 -0
- data/src/grammar.rb +218 -0
- data/src/oak.rb +56 -0
- data/src/parser.rb +1089 -0
- data/src/proof.rb +471 -0
- data/src/schema.rb +170 -0
- data/src/utilities.rb +361 -0
- metadata +58 -0
data/src/commands.rb
ADDED
@@ -0,0 +1,349 @@
|
|
1
|
+
require_relative 'bindings.rb'
|
2
|
+
require_relative 'external prover.rb'
|
3
|
+
require_relative 'schema.rb'
|
4
|
+
|
5
|
+
class Proof
|
6
|
+
class Line < Content
|
7
|
+
attr_reader :label, :filename, :fileline
|
8
|
+
|
9
|
+
def initialize content, type, id
|
10
|
+
super content # set instance variables from content
|
11
|
+
types = [:assumption, :axiom, :derivation, :supposition]
|
12
|
+
raise "unknown type #{type.inspect}" unless types.include? type
|
13
|
+
@type = type
|
14
|
+
@label, @filename, @fileline = id[:label], id[:filename], id[:fileline]
|
15
|
+
end
|
16
|
+
|
17
|
+
def supposition?
|
18
|
+
@type == :supposition
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
### start of Proof class #################################################
|
24
|
+
|
25
|
+
class Proof
|
26
|
+
attr_reader :scopes, :theses
|
27
|
+
|
28
|
+
def initialize manager, options = {}
|
29
|
+
@lines = []
|
30
|
+
@active_suppositions = []
|
31
|
+
@active_contexts = [[]]
|
32
|
+
@scopes = []
|
33
|
+
@theses = []
|
34
|
+
@label_stack = [[]]
|
35
|
+
@line_numbers_by_label = {}
|
36
|
+
@inactive_labels = Set[]
|
37
|
+
@bindings = Bindings.new
|
38
|
+
@manager = manager
|
39
|
+
@marker = :waiting if options[:marker]
|
40
|
+
end
|
41
|
+
|
42
|
+
def assume content, id = nil
|
43
|
+
if content.schema and not @active_suppositions.empty?
|
44
|
+
raise ProofException, '"assume schema" not allowed in supposition'
|
45
|
+
end
|
46
|
+
check_admission content
|
47
|
+
add content, :assumption, id
|
48
|
+
end
|
49
|
+
|
50
|
+
def assuming?
|
51
|
+
@scopes.include? :assume or @marker == :waiting
|
52
|
+
end
|
53
|
+
|
54
|
+
def axiom content, id = nil
|
55
|
+
message = case @scopes.last
|
56
|
+
when :suppose then 'axiom not allowed in supposition'
|
57
|
+
when :now then 'axiom not allowed in "now" block'
|
58
|
+
when Array then 'axiom not allowed in "proof" block'
|
59
|
+
end
|
60
|
+
raise ProofException, message if message
|
61
|
+
check_admission content
|
62
|
+
add content, :axiom, id
|
63
|
+
end
|
64
|
+
|
65
|
+
def begin_assume
|
66
|
+
@scopes << :assume
|
67
|
+
end
|
68
|
+
|
69
|
+
def check_admission content
|
70
|
+
@bindings.check_admission content
|
71
|
+
return
|
72
|
+
|
73
|
+
=begin
|
74
|
+
constants = sentence.free_variables - @active_bindings.keys
|
75
|
+
intersection = constants & sentence.bound_variables
|
76
|
+
if not intersection.empty?
|
77
|
+
name = intersection[0] # pick one for the error message
|
78
|
+
raise ProofException, "#{name} appears as both a variable and a constant"
|
79
|
+
end
|
80
|
+
|
81
|
+
# clear binding if :for_all or :for_some occurs in sentence?
|
82
|
+
=end
|
83
|
+
end
|
84
|
+
|
85
|
+
def derive content, reasons = [], id = nil
|
86
|
+
return assume content, id if assuming?
|
87
|
+
line_numbers, question_mark = process_reasons reasons
|
88
|
+
derive_internal content, line_numbers, question_mark, id
|
89
|
+
end
|
90
|
+
|
91
|
+
def end_assume
|
92
|
+
if not @scopes.include? :assume
|
93
|
+
raise ProofException, 'no assume block to end'
|
94
|
+
elsif @scopes[-1] == :suppose
|
95
|
+
raise ProofException, 'assume block interleaves supposition'
|
96
|
+
elsif @scopes[-1] == :now
|
97
|
+
raise ProofException, 'assume block interleaves "now" block'
|
98
|
+
elsif @scopes[-1].is_a? Array
|
99
|
+
raise ProofException, 'assume block interleaves "proof" block'
|
100
|
+
elsif @scopes[-1] != :assume
|
101
|
+
raise
|
102
|
+
end
|
103
|
+
@scopes.pop
|
104
|
+
end
|
105
|
+
|
106
|
+
def end_block
|
107
|
+
raise ProofException, 'nothing to end' if @scopes.empty?
|
108
|
+
if @scopes[-1] == :assume
|
109
|
+
raise ProofException, '"begin assume" must end with "end assume"'
|
110
|
+
end
|
111
|
+
last_scope = @scopes.pop
|
112
|
+
last_context = @active_contexts.pop
|
113
|
+
last_thesis = @theses.pop
|
114
|
+
if last_scope.is_a? Array # end of proof block
|
115
|
+
@label_stack[-1].each {|label|
|
116
|
+
@line_numbers_by_label.delete label
|
117
|
+
@inactive_labels << label
|
118
|
+
}
|
119
|
+
@label_stack.pop
|
120
|
+
|
121
|
+
@bindings.end_block
|
122
|
+
|
123
|
+
content, id = last_scope
|
124
|
+
if assuming? then
|
125
|
+
assume content, id
|
126
|
+
else
|
127
|
+
derive_internal content, last_context, false, id
|
128
|
+
end
|
129
|
+
else
|
130
|
+
if last_scope == :suppose
|
131
|
+
@active_suppositions.pop
|
132
|
+
@bindings.end_block
|
133
|
+
end
|
134
|
+
@active_contexts.last.concat last_context
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def marker
|
139
|
+
case @marker
|
140
|
+
when :waiting then @marker = :seen
|
141
|
+
when :seen then raise ProofException, 'duplicate marker'
|
142
|
+
when nil then raise ProofException, 'marker used without -m option'
|
143
|
+
else raise
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def now
|
148
|
+
@scopes << :now
|
149
|
+
@active_contexts << []
|
150
|
+
@theses << @theses[-1] # inherit thesis if it exists
|
151
|
+
end
|
152
|
+
|
153
|
+
def proof content, id = nil
|
154
|
+
@scopes << [content, id]
|
155
|
+
@active_contexts << []
|
156
|
+
@theses << content
|
157
|
+
@label_stack << []
|
158
|
+
|
159
|
+
@bindings.begin_block
|
160
|
+
end
|
161
|
+
|
162
|
+
def so content, reasons = [], id = nil
|
163
|
+
return so_assume content, id if assuming?
|
164
|
+
if @active_contexts[-1].empty?
|
165
|
+
raise ProofException, 'nothing for "so" to use'
|
166
|
+
end
|
167
|
+
line_numbers, question_mark = process_reasons reasons
|
168
|
+
line_numbers.concat @active_contexts[-1]
|
169
|
+
@active_contexts[-1] = []
|
170
|
+
derive_internal content, line_numbers, question_mark, id
|
171
|
+
end
|
172
|
+
|
173
|
+
def so_assume content, id = nil
|
174
|
+
if @active_contexts[-1].empty?
|
175
|
+
raise ProofException, 'nothing for "so" to use'
|
176
|
+
end
|
177
|
+
@active_contexts[-1] = []
|
178
|
+
assume content, id
|
179
|
+
end
|
180
|
+
|
181
|
+
def suppose content, id = nil
|
182
|
+
@scopes << :suppose
|
183
|
+
@active_contexts << []
|
184
|
+
@theses << @theses[-1] # inherit thesis if it exists
|
185
|
+
check_admission content
|
186
|
+
@active_suppositions << @lines.size
|
187
|
+
add content, :supposition, id
|
188
|
+
end
|
189
|
+
|
190
|
+
def check content, line_numbers
|
191
|
+
to_check = @bindings.to_check content, @lines.values_at(*line_numbers)
|
192
|
+
schema, tree = to_check.values_at :schema, :tree
|
193
|
+
|
194
|
+
if schema
|
195
|
+
begin
|
196
|
+
tree = SchemaModule.instantiate_schema schema, tree
|
197
|
+
rescue ProofException => e
|
198
|
+
raise unless e.message == 'ProofException' # re-raise original message
|
199
|
+
raise ProofException, 'could not instantiate schema'
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# puts 'checking tree:'
|
204
|
+
# tree.pretty_print
|
205
|
+
|
206
|
+
result = ExternalProver.valid_e? tree
|
207
|
+
|
208
|
+
if schema and result != :valid
|
209
|
+
raise ProofException, 'could not instantiate schema'
|
210
|
+
end
|
211
|
+
|
212
|
+
[result, tree]
|
213
|
+
end
|
214
|
+
|
215
|
+
def check_wait_forever tree
|
216
|
+
ExternalProver.valid_e? tree, true
|
217
|
+
end
|
218
|
+
|
219
|
+
def reduce content, line_numbers
|
220
|
+
# find the minimal subsets of the line numbers which make the content valid
|
221
|
+
labeled = line_numbers.select {|i| @lines[i].label}
|
222
|
+
unlabeled = line_numbers - labeled
|
223
|
+
minimal = find_minimal_subsets(labeled) {|subset|
|
224
|
+
begin
|
225
|
+
# note: order and duplicates do not matter to check
|
226
|
+
result, checked = check content, unlabeled + subset
|
227
|
+
{:valid => true, :invalid => false}[result]
|
228
|
+
rescue ProofException # e.g. "could not instantiate schema"
|
229
|
+
false
|
230
|
+
end
|
231
|
+
}
|
232
|
+
return nil if minimal == [labeled]
|
233
|
+
[labeled, minimal]
|
234
|
+
end
|
235
|
+
|
236
|
+
def fix content, line_numbers
|
237
|
+
# look for additional line numbers that make the content valid
|
238
|
+
originals = line_numbers
|
239
|
+
lines_with_label_not_schema = @line_numbers_by_label.values.select {|i|
|
240
|
+
not @lines[i].schema
|
241
|
+
}
|
242
|
+
additions = lines_with_label_not_schema - originals
|
243
|
+
return nil if additions.empty?
|
244
|
+
seek_valid_subset(additions) {|subset|
|
245
|
+
result, checked = check content, originals + subset
|
246
|
+
result
|
247
|
+
}
|
248
|
+
end
|
249
|
+
|
250
|
+
def reduce_fix fix_line_numbers, content, original_line_numbers
|
251
|
+
# look for a subset of the fix line numbers that makes the content valid
|
252
|
+
reduce_subset(fix_line_numbers) {|subset|
|
253
|
+
result, checked = check content, original_line_numbers + subset
|
254
|
+
result == :valid
|
255
|
+
}
|
256
|
+
end
|
257
|
+
|
258
|
+
def resolve_question_mark content, line_numbers
|
259
|
+
# look for a single additional line number that makes the content valid
|
260
|
+
originals = line_numbers
|
261
|
+
lines_with_label_not_schema = @line_numbers_by_label.values.select {|i|
|
262
|
+
not @lines[i].schema
|
263
|
+
}
|
264
|
+
additions = lines_with_label_not_schema - originals
|
265
|
+
return [] if additions.empty?
|
266
|
+
find_valid_elements(additions) {|subset|
|
267
|
+
result, checked = check content, originals + subset
|
268
|
+
result
|
269
|
+
}
|
270
|
+
end
|
271
|
+
|
272
|
+
def citation_string line_numbers
|
273
|
+
line_numbers.collect {|i|
|
274
|
+
@lines[i].label or "line #{@lines[i].fileline}"
|
275
|
+
}.join ', '
|
276
|
+
end
|
277
|
+
|
278
|
+
private #####################################################################
|
279
|
+
|
280
|
+
def add content, type, id
|
281
|
+
line = Line.new content, type, id
|
282
|
+
@bindings.begin_block if type == :axiom or type == :supposition
|
283
|
+
@bindings.admit line
|
284
|
+
label = id[:label]
|
285
|
+
if @line_numbers_by_label[label]
|
286
|
+
raise ProofException, "label #{label} already in scope"
|
287
|
+
end
|
288
|
+
@lines << line
|
289
|
+
n = @lines.size - 1
|
290
|
+
if label
|
291
|
+
@label_stack[-1] << label
|
292
|
+
@line_numbers_by_label[label] = n
|
293
|
+
elsif content.tie_ins.empty? or not content.binds.empty?
|
294
|
+
@active_contexts[-1] << n
|
295
|
+
end
|
296
|
+
n
|
297
|
+
end
|
298
|
+
|
299
|
+
def derive_internal content, line_numbers, question_mark, id
|
300
|
+
check_admission content
|
301
|
+
@manager.derive self, content, line_numbers, question_mark
|
302
|
+
add content, :derivation, id
|
303
|
+
end
|
304
|
+
|
305
|
+
def process_reasons reasons
|
306
|
+
line_numbers, question_mark = [], false, false
|
307
|
+
reasons.each {|reason|
|
308
|
+
if reason == :question_mark
|
309
|
+
raise ProofException, 'cannot use ? twice in "by"' if question_mark
|
310
|
+
question_mark = true
|
311
|
+
else
|
312
|
+
i = @line_numbers_by_label[reason]
|
313
|
+
if not i
|
314
|
+
if @inactive_labels.include? reason
|
315
|
+
raise ProofException, "label #{reason} is no longer in scope"
|
316
|
+
else
|
317
|
+
raise ProofException, "unknown label #{reason}"
|
318
|
+
end
|
319
|
+
end
|
320
|
+
if @lines[i].supposition? and not @active_suppositions.include? i
|
321
|
+
raise ProofException, "supposition cited outside itself"
|
322
|
+
end
|
323
|
+
line_numbers << i
|
324
|
+
end
|
325
|
+
}
|
326
|
+
[line_numbers, question_mark]
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
### end of Proof class ###################################################
|
331
|
+
|
332
|
+
class ProofException < StandardError; end
|
333
|
+
|
334
|
+
class ParseException < ProofException
|
335
|
+
attr_reader :line_number
|
336
|
+
|
337
|
+
def initialize message, line_number = nil
|
338
|
+
@line_number = line_number
|
339
|
+
super message
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
class DeriveException < ProofException; end
|
344
|
+
|
345
|
+
class BaseException < ProofException; end
|
346
|
+
|
347
|
+
class EndException < ProofException; end
|
348
|
+
|
349
|
+
class SubstituteException < ProofException; end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module ExternalProver
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def valid_e? tree, wait_forever = false
|
7
|
+
tb_insert_limit = 100000
|
8
|
+
valid_tptp?(tree) {|file_path|
|
9
|
+
settings = []
|
10
|
+
settings << "--tb-insert-limit=#{tb_insert_limit}" unless wait_forever
|
11
|
+
settings << '--detsort-rw --detsort-new' # make it deterministic
|
12
|
+
settings << '--print-statistics' if wait_forever
|
13
|
+
|
14
|
+
command = %{"#{find_e}" #{settings.join ' '} --auto --tptp3-format } +
|
15
|
+
%{-s #{file_path} 2>&1}
|
16
|
+
output = `#{command}`
|
17
|
+
|
18
|
+
if output.include? '# Proof found!'
|
19
|
+
next :valid unless wait_forever
|
20
|
+
work = output.match(/# Termbank termtop insertions\s+: (\d+)/).to_a[1]
|
21
|
+
next :valid if (Integer work) <= tb_insert_limit
|
22
|
+
next Float(work) / tb_insert_limit
|
23
|
+
end
|
24
|
+
next :invalid if output.include? '# No proof found!'
|
25
|
+
next :unknown if output.include? '# Failure: User resource limit exceeded!'
|
26
|
+
next :unknown if output.include? '# Failure: Out of unprocessed clauses!'
|
27
|
+
|
28
|
+
message = "unexpected output when calling eprover:\n #{output.strip}\n"
|
29
|
+
if $?.exitstatus == 127 or # command not found
|
30
|
+
output.include? 'Unknown Option' or # happens with version < 2.0
|
31
|
+
output.include? 'not recognized as an internal or external command'
|
32
|
+
message << "check that E Theorem Prover version 2.3 exists at:\n"
|
33
|
+
message << " #{find_e}"
|
34
|
+
raise ProofException, message
|
35
|
+
end
|
36
|
+
raise message # no idea what happened, so treat it as a bug
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
private #######################################################################
|
41
|
+
|
42
|
+
def find_e
|
43
|
+
# https://stackoverflow.com/a/171011/
|
44
|
+
if (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
|
45
|
+
filename = 'eprover-2.3-windows.exe'
|
46
|
+
elsif (/darwin/ =~ RUBY_PLATFORM) != nil
|
47
|
+
filename = 'eprover-2.3-mac'
|
48
|
+
else
|
49
|
+
filename = 'eprover-2.3-linux'
|
50
|
+
end
|
51
|
+
src_dir = File.dirname __FILE__
|
52
|
+
File.expand_path "../eprover/#{filename}", src_dir
|
53
|
+
end
|
54
|
+
|
55
|
+
def make_booleans_explicit tree, booleanize_now = true
|
56
|
+
case tree.operator
|
57
|
+
when :for_all, :for_some
|
58
|
+
body = make_booleans_explicit tree.subtrees[1], true
|
59
|
+
Tree.new tree.operator, [tree.subtrees[0], body]
|
60
|
+
when :not, :and, :or, :implies, :iff
|
61
|
+
subtrees = tree.subtrees.collect {|subtree|
|
62
|
+
make_booleans_explicit subtree, true
|
63
|
+
}
|
64
|
+
Tree.new tree.operator, subtrees
|
65
|
+
when :equals
|
66
|
+
subtrees = tree.subtrees.collect {|subtree|
|
67
|
+
make_booleans_explicit subtree, false
|
68
|
+
}
|
69
|
+
Tree.new tree.operator, subtrees
|
70
|
+
when :predicate
|
71
|
+
subtrees = tree.subtrees.collect {|subtree|
|
72
|
+
make_booleans_explicit subtree, false
|
73
|
+
}
|
74
|
+
tree = Tree.new :predicate, subtrees
|
75
|
+
return tree if not booleanize_now
|
76
|
+
Tree.new :predicate, [Tree.new('boolean', []), tree]
|
77
|
+
when String
|
78
|
+
return tree if not booleanize_now
|
79
|
+
Tree.new :predicate, [Tree.new('boolean', []), tree]
|
80
|
+
else
|
81
|
+
raise "unexpected operator #{tree.operator.inspect}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def rename_for_tptp_internal tree, used, replace = {}
|
86
|
+
case tree.operator
|
87
|
+
when :for_all, :for_some
|
88
|
+
variables = tree.subtrees[0].operator
|
89
|
+
old_replacements = variables.collect {|variable| replace[variable]}
|
90
|
+
new_replacements = new_names used, variables.size, 'V'
|
91
|
+
variables.zip(new_replacements) {|v, r| replace[v] = r}
|
92
|
+
used.concat new_replacements
|
93
|
+
variables_tree = Tree.new new_replacements, []
|
94
|
+
body = rename_for_tptp_internal tree.subtrees[1], used, replace
|
95
|
+
variables.zip(old_replacements) {|v, r| replace[v] = r}
|
96
|
+
tree = Tree.new tree.operator, [variables_tree, body]
|
97
|
+
when :not, :and, :or, :implies, :iff, :equals
|
98
|
+
subtrees = tree.subtrees.collect {|subtree|
|
99
|
+
rename_for_tptp_internal subtree, used, replace
|
100
|
+
}
|
101
|
+
Tree.new tree.operator, subtrees
|
102
|
+
when :predicate
|
103
|
+
# assume that predicate names don't need replacing, e.g. because they
|
104
|
+
# were first-orderized
|
105
|
+
subtrees = tree.subtrees[1..-1].collect {|subtree|
|
106
|
+
rename_for_tptp_internal subtree, used, replace
|
107
|
+
}
|
108
|
+
Tree.new tree.operator, [tree.subtrees[0], *subtrees]
|
109
|
+
when String
|
110
|
+
if not replace[tree.operator]
|
111
|
+
replace[tree.operator] = new_name used, 'c'
|
112
|
+
used << replace[tree.operator]
|
113
|
+
end
|
114
|
+
Tree.new replace[tree.operator], []
|
115
|
+
else
|
116
|
+
raise "unexpected operator #{tree.operator.inspect}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def rename_for_tptp tree
|
121
|
+
used = strings_from tree
|
122
|
+
rename_for_tptp_internal tree, used
|
123
|
+
end
|
124
|
+
|
125
|
+
def strings_from tree
|
126
|
+
if tree.operator.is_a? String
|
127
|
+
[tree.operator]
|
128
|
+
elsif tree.operator.is_a? Array
|
129
|
+
tree.operator
|
130
|
+
else
|
131
|
+
tree.subtrees.collect {|subtree| strings_from subtree}.flatten.uniq
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def tptp_from_internal tree
|
136
|
+
subtrees = tree.subtrees.collect {|subtree| tptp_from_internal subtree}
|
137
|
+
case tree.operator
|
138
|
+
when :for_all
|
139
|
+
"(! [#{subtrees[0]}] : #{subtrees[1]})"
|
140
|
+
when :for_some
|
141
|
+
"(? [#{subtrees[0]}] : #{subtrees[1]})"
|
142
|
+
when :not
|
143
|
+
"~(#{subtrees[0]})"
|
144
|
+
when :and
|
145
|
+
"(#{subtrees.join ' & '})"
|
146
|
+
when :or
|
147
|
+
"(#{subtrees.join ' | '})"
|
148
|
+
when :implies
|
149
|
+
"(#{subtrees[0]} => #{subtrees[1]})"
|
150
|
+
when :iff
|
151
|
+
"(#{subtrees[0]} <=> #{subtrees[1]})"
|
152
|
+
when :equals
|
153
|
+
"(#{subtrees[0]} = #{subtrees[1]})"
|
154
|
+
when :predicate
|
155
|
+
"#{subtrees[0]}(#{subtrees[1..-1].join ','})"
|
156
|
+
when String
|
157
|
+
tree.operator
|
158
|
+
when Array
|
159
|
+
tree.operator.join ','
|
160
|
+
else
|
161
|
+
raise "unexpected operator #{tree.operator.inspect}"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def tptp_from tree
|
166
|
+
tree = replace_for_at_most_one tree
|
167
|
+
tree = replace_empty_quantifiers tree
|
168
|
+
tree = first_orderize tree, true
|
169
|
+
tree = rename_for_tptp tree
|
170
|
+
tree = make_booleans_explicit tree
|
171
|
+
# puts "tree for tptp_from_internal:"
|
172
|
+
# p tree
|
173
|
+
tptp_from_internal tree
|
174
|
+
end
|
175
|
+
|
176
|
+
def valid_tptp? tree
|
177
|
+
input = tptp_from tree
|
178
|
+
input = "fof(query,conjecture,#{input})."
|
179
|
+
# puts "\ntptp:"
|
180
|
+
# puts input
|
181
|
+
file = Tempfile.new ''
|
182
|
+
file.write input
|
183
|
+
file.close # ensures that input is written
|
184
|
+
result = yield file.path
|
185
|
+
file.unlink # best practice
|
186
|
+
result
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|