Uh oh!
There was an error while loading. Please reload this page.
output proofs in the TPTP fragment of the input problem - #884
output proofs in the TPTP fragment of the input problem#884shalashaska117 wants to merge 7 commits into
Conversation
The proof output language was chosen with hasNonDefaultSorts(), which Problem recomputes from its current unit list. Preprocessing can remove the last unit mentioning a sort, and the property then reports an untyped problem while the proof still contains typed formulas. For the problems in vprover#730 the conjecture normalizes to ~$true, so the arithmetic disappears and the proof is printed as fof even though it contains $is_int. Type declarations are printed from the signature, which only grows, so the two could also disagree inside one proof, giving a tff type declaration followed by fof formulas. TFF subsumes FOF, so print tff unconditionally, or thf for higher-order problems, and drop the property test. TPTPPrinter already did this. Also annotate a quantified variable whose sort is not $i even when the property is false, to match Formula::toString.
cc068d0 to
f7b3617Compare
MichaelRawson
left a comment
There was a problem hiding this comment.
Cool! I intend to merge after asking a few people about it.
Uh oh!
There was an error while loading. Please reload this page.
MichaelRawson
commented
Jul 29, 2026
This doesn't seem good: CI passes this test. What system are you using? |
shalashaska117
commented
Jul 29, 2026
I don't understand it either, I get the same error on main, I used Ubuntu latest version, now I'm not at the computer so can't see the exact version |
MichaelRawson
commented
Jul 29, 2026
Uh-oh. Experience suggests that a compiler upgrade finally found a bug that was lurking - if you can, please try to debug the unit test. Otherwise I guess we'll let it play out. |
MichaelRawson
commented
Jul 29, 2026
(but it's independent of this change of course, don't worry!) |
shalashaska117
commented
Jul 29, 2026
I will work on it today. |
shalashaska117
commented
Jul 29, 2026
@MichaelRawson success_3's expected clause was wrong (copy-pasted from success_2), and clang only hides it because it evaluates the two sides of the != in the opposite order to gcc, which makes the produced clause share a subterm with the expected one, and the test comparator returns true on identical subterms without checking that the variable renaming is consistent. |
mezpusz
commented
Jul 29, 2026
I also like the fix, but I think the issue could also happen for I will open a separate PR with my proposed solution, so that we can discuss. |
I am very curious about your solution, I will look into it |
shalashaska117
commented
Jul 29, 2026
@mezpusz do you have any test idea that I could try to verify your claim about thf problems? trying something but I don't know how to check for all cases to be honest, so if you have better ideas to try to point to errors that I could not find |
mezpusz
commented
Jul 30, 2026
I've checked it now with an "unsound" preprocessing step that just replaces all units with I pushed the changes for the alternative solution to |
shalashaska117
commented
Aug 3, 2026
@mezpusz any news about how to solve this problem? |
mezpusz
commented
Aug 3, 2026
@shalashaska117This is my proposed solution but I need to clear out a few other TPTP issues before I can verify that it works. |
Problem::hasNonDefaultSorts() and Problem::isHigherOrder() are recomputed from the current unit list, so when preprocessing removed the last typed or higher-order unit the proof came out in the wrong language. Instead of always printing tff, record both flags when the parsed problem is set as the main problem and pick fof, tff or thf from the recorded values. The proof stays in the fragment of the input: untyped problems keep fof, and originally higher-order problems keep thf even when preprocessing removes every higher-order construct. Recording the flags was suggested by @mezpusz in the vprover#884 discussion. Variable sort annotations keep the per-formula test (annotate whenever the sort is not $i), so a typed variable is never printed bare, and symbol type declarations follow the same recorded flag as the proof steps, so one proof cannot mix languages. FunctionRelationshipInference temporarily swaps the main problem during FMB sort bound detection, which runs after preprocessing; its two setMainProblem calls pass isInputProblem=false so the recorded fragment survives the swap.
printGeneralSplittingComponent passed getQuantifiedStr a static sort map that nothing ever filled, so the variables of a definition introduced by -gsp on printed without sorts, and a $int variable read back as $i. Collect the sorts from the clause instead, and remove the map-less overload, which is now unused. The proof printers also printed symbol type declarations when the proof itself is fof: the signature can hold a typed symbol that no unit ever used, and its declaration put a tff line in front of an fof proof. Skip the declarations when the recorded fragment is fof.
shalashaska117
commented
Aug 5, 2026
@mezpusz I went through
Two more changes in the same area:
|
mezpusz
commented
Aug 6, 2026
Good catch!
The point of this assertion was to enforce callers to fill the map, otherwise @MichaelRawson might know why we want UB in case the assertion fails in release.
I think it should never happen that |
Wouldn't this create more problems?
I can check this easily, but in my test it never occurred. Easy fix to the code. |
MichaelRawson
commented
Aug 6, 2026
I defined Consider e.g. voidf(int x) {
if(x < 0) throwException("expected positive integer");
// ....
}
voidg(int y) {
ASS(y > 0)
f(y);
// ...
}When inlining |
shalashaska117
commented
Aug 6, 2026
@mezpusz agreed on the assertion. I'll add ASS(t == AtomicSort::defaultSort() || env.initiallyHasNonDefaultSorts());at the two sites of the per-formula test ( I could not come up with a counterexample either: theory axioms, induction and FOOL elimination all need the sorts to be in the problem already. For some confidence beyond that I'll run a debug build with the assertion over On @MichaelRawson thanks for the explanation. One detail: in release only |
A non-default sort should never appear in a proof step of an initially untyped problem: every preprocessing step that builds sorted terms (theory axioms, induction, FOOL elimination) needs the sorts to be in the input already. Assert this in getQuantifiedStr and Formula::toString instead of relying on it silently. The disjunction stays as the print condition: ASS compiles to nothing in release, and if a future rule ever breaks the invariant, a release build prints the variable with its sort instead of dropping the annotation and changing the formula, while a debug build fails the assertion and points at the rule.
shalashaska117
commented
Aug 6, 2026
Pushed the assertion in 5bf5aa6: Validation: 97/97 unit tests in debug, The sweep did surface two debug assertion failures that already exist on master (reproduced at 3677326), so they are not from this PR:
I can open issues for these if they are not already known. |
The previous run died before starting: the job was never acquired by a hosted runner.
MichaelRawson
commented
Aug 7, 2026
Oops, yes - evaluating the |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
The proof output language checks leave checks/sanity: the three helpers and their six invocations are gone, since proof output gets checked by the occasional GDV run over the whole TPTP anyway. The problem files stay under checks/proof for running by hand, with their header comments cut down to the expected outcome. Formula::toString and getQuantifiedStr now annotate variables only when env.initiallyHasNonDefaultSorts() holds. The dropped disjunct also printed the sort whenever it was not $i, which for an initially untyped problem can only happen if preprocessing breaks the invariant asserted one line above; printing the annotation in release would hide the very error the assertion is meant to catch.
shalashaska117
commented
Aug 10, 2026
@mezpusz all three done in 0e5a7e2:
Re-ran ctest (97/97, debug) and checks/sanity with the release build, plus the dropped checks by hand against debug: the -gsp definition still annotates its variables, PUZ001+1 stays fof, mixed-language.p comes out all tff, unused-typed-symbol.p all fof, and ARI496_1 has no fof lines with either -p tptp or -p proofcheck. |
MichaelRawson
commented
Aug 12, 2026
#881 merged now, feel free to run tests. |
Fixes#730.
InferenceStorechose betweenfofandtffusingProblem::hasNonDefaultSorts(). That property is recomputed from the current unit list (refreshPropertycallsProperty::scan(_units)), so it answers "do the units I am holding right now mention a non-$isort" rather than "which fragment was the input problem in". Preprocessing can delete the last unit mentioning a sort, and the property then reports an untyped problem while the proof still contains typed formulas.The eight problems listed in #730 hit this. The conjecture normalizes to
~$true, the arithmetic disappears, and the proof comes out as:What changed
The first version of this PR printed
tffunconditionally, as @MichaelRawson suggested in #730. It is now the union of that and @mezpusz's counter-proposal onfix-output-tptp-fragment:ProblemrecordsinitiallyHasNonDefaultSortsandinitiallyHigherOrderwhen the input problem is set, and the proof printers pickfof,tfforthffrom those flags. A pure FOF problem keeps itsfofproof.t != defaultSort() || initiallyHasNonDefaultSorts()) ingetQuantifiedStrandFormula::toString, so a$intvariable surviving in a proof step never prints bare and reads back as$i.getQuantifiedStroverload without a sort map is gone. It passed a staticDHMapthat nothing ever filled, andprintGeneralSplittingComponentwent through it:ALWAYS(t_map.find(var,t))on an empty map is undefined behaviour in release, and the general splitting definitions printed their variables without sorts either way. The definition printer now collects the sorts from the clause.FunctionRelationshipInferenceswaps the main problem twice during FMB sort bound detection, which runs after preprocessing, so the flags got recomputed from the preprocessed units and the bug came back for fmb strategies. Those two calls now skip the recording (isInputProblem=false).outputSymbolTypeDeclarationIfNeededfollows the saved flags, and the proof printers skip type declarations entirely when the recorded fragment is fof. The signature can hold a typed symbol that no unit ever used, and its declaration would put atffline in front of anfofproof.-p on,-p smtcheckand-p smt2_proofcheckare untouched, and SAT steps from AVATAR still print ascnf.Testing
checks/sanitypasses. The new checks test both directions: nofofin the proofs of ARI496_1 andmixed-language.p, onlyfoffor PUZ001+1 and for a problem whose signature holds an unused typed symbol, and sort annotations on the gsp definitions (checks/proof/gsp-typed.pfails on master).-sa fmb -fmbdsb on.-p tptpover the checks problems against master: ARI496_1,let-bool.pandmixed-language.pchangefof(totff(,unused-typed-symbol.pdrops the unused declaration, every SZS status is unchanged, and the remaining outputs are identical up to the clause renumbering master already shows between runs.I still have not checked the output against a strict TPTP parser like tptp4X; Vampire's own parser accepted the broken proofs, so round-tripping through Vampire does not catch the old behaviour.