From 8e70dbaebce2f9455efe6b0828aa8fa39312a516 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jun 2026 15:22:41 -0700 Subject: [PATCH 01/48] Update tptp_frontend.cpp --- src/cmd_context/tptp_frontend.cpp | 54 +++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/src/cmd_context/tptp_frontend.cpp b/src/cmd_context/tptp_frontend.cpp index 4cb5d9451f..c8295b7391 100644 --- a/src/cmd_context/tptp_frontend.cpp +++ b/src/cmd_context/tptp_frontend.cpp @@ -87,6 +87,7 @@ struct token { std::string text; unsigned line = 1; unsigned col = 1; + bool dquote = false; // true for double-quoted strings ("..."): TPTP distinct objects }; class lexer { @@ -163,6 +164,7 @@ public: if (peek() == '\'' || peek() == '"') { char q = get(); t.kind = token_kind::str; + t.dquote = (q == '"'); while (!eof()) { char c = get(); if (c == '\\' && !eof()) { @@ -292,6 +294,11 @@ class tptp_parser { bool m_has_conjecture = false; unsigned m_dropped_formulas = 0; // axioms/definitions skipped due to encoding errors bool m_last_name_quoted = false; + bool m_last_name_dquoted = false; // last parsed name was a double-quoted distinct object + // Distinct objects: TPTP double-quoted strings ("...") denote pairwise distinct + // domain elements. Collected here (deduplicated by name) so a single global + // (distinct ...) constraint can be asserted before solving. + std::unordered_map m_distinct_objects; std::string m_expected_status; // SZS status from the input annotation, if any std::unordered_map m_sorts; sort_ref_vector m_pinned_sorts; // prevents cached sorts from being freed @@ -426,6 +433,7 @@ class tptp_parser { std::string parse_name() { if (is(token_kind::id) || is(token_kind::str)) { m_last_name_quoted = is(token_kind::str); + m_last_name_dquoted = is(token_kind::str) && m_curr.dquote; std::string r = m_curr.text; next(); return r; @@ -957,6 +965,7 @@ class tptp_parser { return parse_numeral_from_name(n); } + bool dq_name = m_last_name_dquoted; expr_ref b(m); // Check bound variables: uppercase (quantifier vars) AND lowercase (let-bound names) if (!m_last_name_quoted && find_bound(n, b)) { @@ -1007,7 +1016,10 @@ class tptp_parser { func_decl* f = mk_decl_or_ho_const(n, args.size(), false); coerce_args(f, args); - return expr_ref(args.empty() ? m.mk_const(f) : m.mk_app(f, args.size(), args.data()), m); + expr_ref term(args.empty() ? m.mk_const(f) : m.mk_app(f, args.size(), args.data()), m); + if (dq_name && args.empty()) + register_distinct_object(n, term); + return term; } // Grammar: ::= | @@ -1346,7 +1358,7 @@ class tptp_parser { // resume precedence-climbing parsing from that negated left operand. expr_ref operand = parse_unary_formula(true); expr_ref neg(m.mk_not(ensure_bool(operand)), m); - inner = parse_binary_rest(neg, PREC_IFF, true, true); + inner = parse_binary_rest(neg, PREC_IFF, true); } else { // Binary connective at start of parens — shouldn't happen in valid TPTP throw parse_error("unexpected connective after '(' at " + loc()); @@ -1391,6 +1403,7 @@ class tptp_parser { return parse_numeral_from_name(n); } + bool dq_name = m_last_name_dquoted; // Check if name is let-bound (works for both uppercase vars and lowercase let-bound names) { expr_ref b(m); @@ -1492,7 +1505,10 @@ class tptp_parser { func_decl* pred = mk_decl_or_ho_const(n, args.size(), is_boolean); coerce_args(pred, args); - return expr_ref(m.mk_app(pred, args.size(), args.data()), m); + expr_ref atom(m.mk_app(pred, args.size(), args.data()), m); + if (dq_name && args.empty() && !m.is_bool(atom)) + register_distinct_object(n, atom); + return atom; } // Grammar: ::= ^ [] : @@ -1711,13 +1727,13 @@ class tptp_parser { // Implements a Pratt-style (precedence climbing) parser for binary connectives. expr_ref parse_expr(unsigned min_prec, bool consume_at, bool is_boolean) { expr_ref e = parse_unary_formula(is_boolean); - return parse_binary_rest(e, min_prec, consume_at, m.is_bool(e)); + return parse_binary_rest(e, min_prec, consume_at); } // Precedence-climbing loop continued from an already-parsed left operand `e`. // Split out from parse_expr so callers that have consumed a leading unary unit // (e.g. a '~' immediately after '(') can resume binary-connective parsing. - expr_ref parse_binary_rest(expr_ref e, unsigned min_prec, bool consume_at = true, bool is_boolean = true) { + expr_ref parse_binary_rest(expr_ref e, unsigned min_prec, bool consume_at = true) { for (;;) { // Handle @ (function application) with highest precedence // But NOT when we're inside a lambda body that's an @ argument @@ -1748,7 +1764,15 @@ class tptp_parser { if (it->second.precedence < min_prec) break; next(); // consume the operator token unsigned next_prec = it->second.right_assoc ? it->second.precedence : it->second.precedence + 1; - expr_ref rhs = parse_expr(next_prec, consume_at, is_boolean); + // Operands of every connective except '='/'!=' are Boolean; only equality + // takes term operands. Derive the operand context from the operator rather + // than inheriting is_boolean from the left operand. Otherwise, once a + // term-valued equality literal (e.g. 'a = b') sets is_boolean to false, a + // predicate atom later in the same clause ('a = b | q') would be parsed as a + // term and boxed into '$box_U_to_Bool(q)', severing it from the Boolean + // predicate 'q' used elsewhere and making refutable problems satisfiable. + bool rhs_is_boolean = it->second.precedence != PREC_EQ; + expr_ref rhs = parse_expr(next_prec, consume_at, rhs_is_boolean); expr_ref_vector args(m); args.push_back(e); args.push_back(rhs); @@ -2176,6 +2200,12 @@ public: }}; } + // Record a double-quoted string constant as a TPTP distinct object (deduplicated by name). + void register_distinct_object(std::string const& name, expr* c) { + if (m_distinct_objects.emplace(name, c).second) + m_pinned_exprs.push_back(c); + } + void parse_input(std::istream& in, std::string const& current_file) { // Save parser state so that included files don't clobber the caller's lexer. std::string saved_input = std::move(m_input); @@ -2213,6 +2243,17 @@ public: bool has_conjecture() const { return m_has_conjecture; } + // TPTP double-quoted strings ("...") denote pairwise distinct domain elements. + // Assert a single global distinctness constraint over all collected distinct objects + // so that e.g. "Apple" != "Microsoft" is recognized as a theorem. + void assert_distinct_objects() { + if (m_distinct_objects.size() < 2) return; + expr_ref_vector objs(m); + for (auto const& kv : m_distinct_objects) + objs.push_back(kv.second); + m_cmd.assert_expr(expr_ref(m.mk_distinct(objs.size(), objs.data()), m)); + } + // Number of axioms/definitions that were dropped during parsing because the // higher-order encoding could not type-check them. When non-zero, a "sat" // verdict cannot be trusted (the missing constraints may be exactly what @@ -2339,6 +2380,7 @@ static unsigned read_tptp_stream(std::istream& in, char const* current_file) { tptp_parser p(ctx); p.parse_input(in, current_file ? current_file : "."); + p.assert_distinct_objects(); // Suppress default check-sat output; TPTP frontend reports SZS status explicitly. std::ostringstream sink; From 4fb80761c626a1124632a70014d2269cd21d3357 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jun 2026 20:18:41 -0700 Subject: [PATCH 02/48] bug fixes --- src/cmd_context/tptp_frontend.cpp | 52 ++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/src/cmd_context/tptp_frontend.cpp b/src/cmd_context/tptp_frontend.cpp index c8295b7391..0f2e686696 100644 --- a/src/cmd_context/tptp_frontend.cpp +++ b/src/cmd_context/tptp_frontend.cpp @@ -1328,24 +1328,37 @@ class tptp_parser { token saved = m_curr; next(); if (accept(token_kind::rparen)) { - // Parenthesized connective: treat as HO constant with array sort + // A parenthesized connective used as a higher-order term, e.g. + // "(~) @ p" or "(|) @ p @ q". Encode it as a genuine lambda over Bool + // carrying the real logical semantics, so that application beta-reduces + // to the actual connective (e.g. "(~) @ p" ==> "not p"). Encoding it as + // an uninterpreted array constant instead would sever it from Boolean + // logic and make valid higher-order theorems spuriously + // CounterSatisfiable (the (~)/(|) applications would be unrelated to the + // truth values of their operands). + (void)op_text; sort* bool_sort = m.mk_bool_sort(); - sort* ho_sort; - if (arity == 1) - ho_sort = m_array.mk_array_sort(bool_sort, bool_sort); - else - ho_sort = m_array.mk_array_sort(bool_sort, m_array.mk_array_sort(bool_sort, bool_sort)); - std::string key = mk_decl_key(op_text, 0, 'h'); - auto it = m_decls.find(key); - func_decl* f; - if (it != m_decls.end()) { - f = it->second; - } else { - f = m.mk_func_decl(symbol(op_text), 0, static_cast(nullptr), ho_sort); - m_pinned_decls.push_back(f); - m_decls.emplace(key, f); + symbol xn("X"), yn("Y"); + if (arity == 1) { + // (~) ==> ^[X:$o] : ~X + expr_ref body(m.mk_not(m.mk_var(0, bool_sort)), m); + return expr_ref(m.mk_lambda(1, &bool_sort, &xn, body), m); } - return expr_ref(m.mk_const(f), m); + // binary connective ==> ^[X:$o] : ^[Y:$o] : (X Y) + // de Bruijn: X is var(1) (outer binder), Y is var(0) (inner binder). + expr* vx = m.mk_var(1, bool_sort); + expr* vy = m.mk_var(0, bool_sort); + expr_ref opbody(m); + switch (saved.kind) { + case token_kind::and_tok: opbody = m.mk_and(vx, vy); break; + case token_kind::or_tok: opbody = m.mk_or(vx, vy); break; + case token_kind::implies_tok: opbody = m.mk_implies(vx, vy); break; + case token_kind::iff_tok: opbody = m.mk_eq(vx, vy); break; + case token_kind::xor_tok: opbody = m.mk_xor(vx, vy); break; + default: opbody = m.mk_eq(vx, vy); break; + } + expr_ref inner(m.mk_lambda(1, &bool_sort, &yn, opbody), m); + return expr_ref(m.mk_lambda(1, &bool_sort, &xn, inner), m); } // Not a parenthesized connective — lparen was consumed and connective was consumed // but ')' didn't follow. Parse as formula with the connective already consumed. @@ -1839,14 +1852,15 @@ class tptp_parser { // Try relative to current file's directory std::string local = normalize_path(dirname(curr_file) + "/" + name); if (file_exists(local)) return local; - #if 0 - // Try TPTP environment variable (standard TPTP convention) + // Try TPTP environment variable (standard TPTP convention): includes such as + // "Axioms/MAT001^0.ax" are resolved relative to the TPTP root directory named + // by $TPTP. This is required when a problem is run from a directory that does + // not contain the Axioms/ tree (e.g. an isolated benchmark harness workspace). char const* root = std::getenv("TPTP"); if (root) { std::string env = normalize_path(std::string(root) + "/" + name); if (file_exists(env)) return env; } - #endif // Walk up ancestor directories of the current file. TPTP include paths are // relative to the TPTP root directory (e.g. "Axioms/BOO001-0.ax"), while the // problem file typically lives in a subdirectory such as "Problems/BOO/". From 652402fa1f39b7b8ad06c78c10c0b4a5cf2f016a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jun 2026 20:47:01 -0700 Subject: [PATCH 03/48] branch Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_split.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ast/rewriter/seq_split.cpp b/src/ast/rewriter/seq_split.cpp index 8977065fc0..fcba3a8d03 100644 --- a/src/ast/rewriter/seq_split.cpp +++ b/src/ast/rewriter/seq_split.cpp @@ -1,3 +1,4 @@ + /*++ Copyright (c) 2026 Microsoft Corporation From 69444de05b225628019b88d46794e76c328acd5f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Jul 2026 16:26:41 -0700 Subject: [PATCH 04/48] updated with bug fixes Signed-off-by: Nikolaj Bjorner --- src/cmd_context/tptp_frontend.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/cmd_context/tptp_frontend.cpp b/src/cmd_context/tptp_frontend.cpp index 0f2e686696..4dd535b765 100644 --- a/src/cmd_context/tptp_frontend.cpp +++ b/src/cmd_context/tptp_frontend.cpp @@ -1011,6 +1011,10 @@ class tptp_parser { // Table-driven prefix operator dispatch auto op_it = m_ops.find(n); if (op_it != m_ops.end() && !op_it->second.is_infix) { + if (args.empty()) { + while (accept(token_kind::at_tok)) + args.push_back(parse_at_arg()); + } return op_it->second.builder(args); } @@ -1491,6 +1495,10 @@ class tptp_parser { // Table-driven prefix operator dispatch auto op_it = m_ops.find(n); if (op_it != m_ops.end() && !op_it->second.is_infix) { + if (args.empty()) { + while (accept(token_kind::at_tok)) + args.push_back(parse_at_arg()); + } return op_it->second.builder(args); } @@ -1808,8 +1816,19 @@ class tptp_parser { expect(token_kind::rparen, "')'"); if (t.domain.empty() && is_ttype(t.range)) { - // Sort declaration: monomorphize to m_univ - m_sorts.insert_or_assign(name, m_univ); + // Sort declaration: give every declared type its own distinct uninterpreted + // sort. Collapsing all declared $tType sorts onto a single m_univ is unsound: + // a per-type constraint such as "![H:human]:H=jon" would then also constrain + // unrelated sorts (e.g. cats), turning satisfiable axiom sets into a spurious + // contradiction and reporting Theorem where the conjecture is CounterSatisfiable. + if (m_sorts.find(name) == m_sorts.end()) { + sort* s = m.mk_uninterpreted_sort(symbol(name)); + m_pinned_sorts.push_back(s); + m_sorts.emplace(name, s); + } + // A prior *use* of the name (before its declaration) already created a fresh + // sort via parse_defined_sort; keep that same sort so uses and the declaration + // agree. return; } From 6ac3075022f217cb2f0bebd42c56d86c3ccd4300 Mon Sep 17 00:00:00 2001 From: davedets Date: Thu, 2 Jul 2026 12:47:29 -0700 Subject: [PATCH 05/48] Remove unnecessary semicolons (Attempt 2) (#10020) This is another PR towards the goal of getting Z3 to compile cleanly when included via FetchContents into clang-tidy, which uses a pretty strict set of warnings. This is a second version of https://github.com/Z3Prover/z3/pull/9957. I address @NikolajBjorner 's comments about not changing the semicolons after macro invocations, because some editors work better with them present. It now, to the best of my ability, only deletes semis: * after the closing brace of namespace decl. * after the closing brace of an extern "C" decl. * after a function definition. This PR is very large, but it consists entirely of deletions of semicolons in these situations. (If there was a way to update the previous PR, which had been closed, and that is preferable, please let me know. I couldn't figure it out.) --- cmake/compiler_warnings.cmake | 3 ++- src/api/api_algebraic.cpp | 2 +- src/api/api_arith.cpp | 2 +- src/api/api_array.cpp | 2 +- src/api/api_ast.cpp | 2 +- src/api/api_ast_map.cpp | 2 +- src/api/api_ast_vector.cpp | 2 +- src/api/api_ast_vector.h | 2 +- src/api/api_bv.cpp | 2 +- src/api/api_config_params.cpp | 2 +- src/api/api_context.cpp | 4 ++-- src/api/api_context.h | 8 ++++---- src/api/api_datalog.cpp | 4 ++-- src/api/api_datalog.h | 2 +- src/api/api_datatype.cpp | 2 +- src/api/api_finite_set.cpp | 2 +- src/api/api_fpa.cpp | 2 +- src/api/api_goal.cpp | 2 +- src/api/api_model.cpp | 2 +- src/api/api_numeral.cpp | 2 +- src/api/api_opt.cpp | 2 +- src/api/api_params.cpp | 2 +- src/api/api_pb.cpp | 2 +- src/api/api_polynomial.cpp | 2 +- src/api/api_quant.cpp | 2 +- src/api/api_rcf.cpp | 2 +- src/api/api_seq.cpp | 2 +- src/api/api_solver.cpp | 2 +- src/api/api_special_relations.cpp | 2 +- src/api/api_stats.cpp | 2 +- src/api/api_tactic.cpp | 2 +- src/api/api_util.h | 2 +- src/ast/arith_decl_plugin.h | 2 +- src/ast/datatype_decl_plugin.h | 4 ++-- src/ast/dl_decl_plugin.cpp | 4 ++-- src/ast/dl_decl_plugin.h | 2 +- src/ast/euf/euf_ac_plugin.h | 4 ++-- src/ast/euf/euf_etable.cpp | 2 +- src/ast/euf/euf_etable.h | 2 +- src/ast/euf/euf_mam.h | 2 +- src/ast/euf/euf_plugin.h | 2 +- src/ast/for_each_expr.cpp | 2 +- src/ast/format.cpp | 2 +- src/ast/format.h | 2 +- src/ast/fpa/fpa2bv_converter.h | 8 ++++---- src/ast/macros/macro_manager.cpp | 2 +- src/ast/macros/quasi_macros.cpp | 2 +- src/ast/polymorphism_inst.h | 2 +- src/ast/quantifier_stat.cpp | 2 +- src/ast/quantifier_stat.h | 2 +- src/ast/recfun_decl_plugin.h | 4 ++-- src/ast/rewriter/bv_bounds.h | 2 +- src/ast/rewriter/seq_axioms.h | 2 +- src/ast/rewriter/seq_eq_solver.cpp | 2 +- src/ast/rewriter/seq_eq_solver.h | 2 +- src/ast/rewriter/seq_skolem.h | 2 +- src/ast/simplifiers/distribute_forall.cpp | 2 +- src/ast/simplifiers/propagate_values.cpp | 2 +- src/ast/sls/sls_array_plugin.h | 6 +++--- src/ast/sls/sls_bv_lookahead.cpp | 4 ++-- src/ast/sls/sls_bv_tracker.h | 2 +- src/ast/sls/sls_context.h | 6 +++--- src/ast/sls/sls_euf_plugin.h | 4 ++-- src/cmd_context/extra_cmds/dbg_cmds.cpp | 6 +++--- src/math/grobner/pdd_simplifier.cpp | 2 +- src/math/lp/lp_primal_core_solver.h | 2 +- src/math/lp/nla_types.h | 6 +++--- src/math/polynomial/algebraic_numbers.cpp | 2 +- src/math/polynomial/algebraic_numbers.h | 2 +- src/math/polynomial/polynomial.cpp | 2 +- src/math/polynomial/polynomial.h | 4 ++-- src/math/polynomial/polynomial_cache.cpp | 2 +- src/math/polynomial/polynomial_cache.h | 2 +- src/math/polynomial/polynomial_primes.h | 2 +- src/math/polynomial/polynomial_var2value.h | 2 +- src/math/polynomial/rpolynomial.cpp | 2 +- src/math/polynomial/rpolynomial.h | 2 +- src/math/polynomial/upolynomial.cpp | 2 +- src/math/polynomial/upolynomial.h | 2 +- src/math/polynomial/upolynomial_factorization.cpp | 2 +- src/math/polynomial/upolynomial_factorization.h | 2 +- src/math/polynomial/upolynomial_factorization_int.h | 2 +- src/math/realclosure/realclosure.cpp | 2 +- src/math/realclosure/realclosure.h | 2 +- src/math/simplex/simplex.cpp | 2 +- src/math/simplex/simplex.h | 2 +- src/math/simplex/simplex_def.h | 2 +- src/math/simplex/sparse_matrix.h | 2 +- src/math/simplex/sparse_matrix_def.h | 2 +- src/math/subpaving/subpaving.cpp | 2 +- src/math/subpaving/subpaving.h | 2 +- src/math/subpaving/subpaving_hwf.h | 2 +- src/math/subpaving/subpaving_mpf.h | 2 +- src/math/subpaving/subpaving_mpff.h | 2 +- src/math/subpaving/subpaving_mpfx.h | 2 +- src/math/subpaving/subpaving_mpq.h | 2 +- src/math/subpaving/subpaving_t.h | 2 +- src/math/subpaving/subpaving_t_def.h | 2 +- src/muz/base/dl_context.cpp | 2 +- src/muz/base/dl_context.h | 2 +- src/muz/base/dl_costs.cpp | 2 +- src/muz/base/dl_costs.h | 2 +- src/muz/base/dl_rule.cpp | 2 +- src/muz/base/dl_rule.h | 4 ++-- src/muz/base/dl_rule_set.cpp | 2 +- src/muz/base/dl_rule_set.h | 2 +- src/muz/base/dl_rule_subsumption_index.cpp | 2 +- src/muz/base/dl_rule_subsumption_index.h | 2 +- src/muz/base/dl_rule_transformer.cpp | 2 +- src/muz/base/dl_rule_transformer.h | 2 +- src/muz/base/dl_util.cpp | 2 +- src/muz/base/dl_util.h | 2 +- src/muz/bmc/dl_bmc_engine.cpp | 2 +- src/muz/bmc/dl_bmc_engine.h | 2 +- src/muz/clp/clp_context.cpp | 2 +- src/muz/clp/clp_context.h | 2 +- src/muz/ddnf/ddnf.cpp | 2 +- src/muz/ddnf/ddnf.h | 2 +- src/muz/fp/datalog_parser.h | 2 +- src/muz/rel/check_relation.h | 2 +- src/muz/rel/dl_base.h | 6 +++--- src/muz/rel/dl_bound_relation.cpp | 2 +- src/muz/rel/dl_bound_relation.h | 2 +- src/muz/rel/dl_check_table.cpp | 2 +- src/muz/rel/dl_check_table.h | 2 +- src/muz/rel/dl_compiler.h | 2 +- src/muz/rel/dl_external_relation.cpp | 2 +- src/muz/rel/dl_external_relation.h | 2 +- src/muz/rel/dl_finite_product_relation.cpp | 2 +- src/muz/rel/dl_finite_product_relation.h | 2 +- src/muz/rel/dl_instruction.h | 2 +- src/muz/rel/dl_interval_relation.cpp | 2 +- src/muz/rel/dl_interval_relation.h | 2 +- src/muz/rel/dl_mk_explanations.cpp | 2 +- src/muz/rel/dl_mk_explanations.h | 2 +- src/muz/rel/dl_mk_similarity_compressor.cpp | 2 +- src/muz/rel/dl_mk_similarity_compressor.h | 2 +- src/muz/rel/dl_mk_simple_joins.cpp | 2 +- src/muz/rel/dl_mk_simple_joins.h | 2 +- src/muz/rel/dl_product_relation.cpp | 2 +- src/muz/rel/dl_product_relation.h | 2 +- src/muz/rel/dl_relation_manager.cpp | 2 +- src/muz/rel/dl_relation_manager.h | 2 +- src/muz/rel/dl_sieve_relation.cpp | 2 +- src/muz/rel/dl_sieve_relation.h | 2 +- src/muz/rel/dl_sparse_table.cpp | 2 +- src/muz/rel/dl_sparse_table.h | 2 +- src/muz/rel/dl_table.cpp | 2 +- src/muz/rel/dl_table.h | 2 +- src/muz/rel/dl_table_relation.cpp | 2 +- src/muz/rel/dl_table_relation.h | 2 +- src/muz/rel/dl_vector_relation.h | 2 +- src/muz/rel/karr_relation.cpp | 2 +- src/muz/rel/karr_relation.h | 2 +- src/muz/rel/rel_context.cpp | 2 +- src/muz/rel/rel_context.h | 2 +- src/muz/rel/udoc_relation.h | 2 +- src/muz/spacer/spacer_concretize.cpp | 2 +- src/muz/spacer/spacer_context.h | 2 +- src/muz/spacer/spacer_convex_closure.h | 2 +- src/muz/spacer/spacer_farkas_learner.cpp | 2 +- src/muz/spacer/spacer_generalizers.cpp | 2 +- src/muz/spacer/spacer_mbc.cpp | 2 +- src/muz/spacer/spacer_proof_utils.cpp | 2 +- src/muz/spacer/spacer_qe_project.h | 2 +- src/muz/spacer/spacer_sym_mux.h | 2 +- src/muz/spacer/spacer_unsat_core_learner.h | 2 +- src/muz/spacer/spacer_unsat_core_plugin.cpp | 2 +- src/muz/spacer/spacer_unsat_core_plugin.h | 8 ++++---- src/muz/tab/tab_context.cpp | 4 ++-- src/muz/tab/tab_context.h | 2 +- src/muz/transforms/dl_mk_array_blast.cpp | 2 +- src/muz/transforms/dl_mk_array_blast.h | 2 +- src/muz/transforms/dl_mk_array_eq_rewrite.h | 2 +- src/muz/transforms/dl_mk_array_instantiation.h | 2 +- src/muz/transforms/dl_mk_backwards.cpp | 2 +- src/muz/transforms/dl_mk_backwards.h | 2 +- src/muz/transforms/dl_mk_bit_blast.cpp | 2 +- src/muz/transforms/dl_mk_bit_blast.h | 2 +- src/muz/transforms/dl_mk_coalesce.cpp | 2 +- src/muz/transforms/dl_mk_coalesce.h | 2 +- src/muz/transforms/dl_mk_filter_rules.cpp | 2 +- src/muz/transforms/dl_mk_filter_rules.h | 2 +- src/muz/transforms/dl_mk_interp_tail_simplifier.cpp | 2 +- src/muz/transforms/dl_mk_interp_tail_simplifier.h | 2 +- src/muz/transforms/dl_mk_karr_invariants.cpp | 2 +- src/muz/transforms/dl_mk_karr_invariants.h | 2 +- src/muz/transforms/dl_mk_loop_counter.cpp | 2 +- src/muz/transforms/dl_mk_loop_counter.h | 2 +- src/muz/transforms/dl_mk_magic_sets.cpp | 2 +- src/muz/transforms/dl_mk_magic_sets.h | 2 +- src/muz/transforms/dl_mk_magic_symbolic.cpp | 2 +- src/muz/transforms/dl_mk_magic_symbolic.h | 2 +- src/muz/transforms/dl_mk_quantifier_abstraction.cpp | 2 +- src/muz/transforms/dl_mk_quantifier_abstraction.h | 2 +- src/muz/transforms/dl_mk_quantifier_instantiation.cpp | 2 +- src/muz/transforms/dl_mk_quantifier_instantiation.h | 2 +- src/muz/transforms/dl_mk_rule_inliner.cpp | 2 +- src/muz/transforms/dl_mk_rule_inliner.h | 2 +- src/muz/transforms/dl_mk_scale.cpp | 2 +- src/muz/transforms/dl_mk_scale.h | 2 +- src/muz/transforms/dl_mk_slice.cpp | 2 +- src/muz/transforms/dl_mk_slice.h | 2 +- src/muz/transforms/dl_mk_subsumption_checker.cpp | 2 +- src/muz/transforms/dl_mk_subsumption_checker.h | 2 +- src/muz/transforms/dl_mk_synchronize.cpp | 2 +- src/muz/transforms/dl_mk_synchronize.h | 2 +- src/muz/transforms/dl_mk_unbound_compressor.cpp | 2 +- src/muz/transforms/dl_mk_unbound_compressor.h | 2 +- src/muz/transforms/dl_mk_unfold.cpp | 2 +- src/muz/transforms/dl_mk_unfold.h | 2 +- src/nlsat/nlsat_assignment.h | 2 +- src/nlsat/nlsat_clause.cpp | 2 +- src/nlsat/nlsat_clause.h | 2 +- src/nlsat/nlsat_evaluator.cpp | 2 +- src/nlsat/nlsat_evaluator.h | 2 +- src/nlsat/nlsat_explain.cpp | 2 +- src/nlsat/nlsat_explain.h | 2 +- src/nlsat/nlsat_interval_set.cpp | 2 +- src/nlsat/nlsat_interval_set.h | 2 +- src/nlsat/nlsat_justification.h | 2 +- src/nlsat/nlsat_scoped_literal_vector.h | 2 +- src/nlsat/nlsat_simplify.cpp | 2 +- src/nlsat/nlsat_solver.cpp | 2 +- src/nlsat/nlsat_solver.h | 2 +- src/nlsat/nlsat_types.cpp | 2 +- src/nlsat/nlsat_types.h | 4 ++-- src/opt/maxcore.h | 2 +- src/opt/maxlex.h | 2 +- src/opt/maxsmt.cpp | 6 +++--- src/opt/maxsmt.h | 2 +- src/opt/opt_cores.cpp | 2 +- src/opt/opt_cores.h | 2 +- src/opt/opt_lns.cpp | 2 +- src/opt/opt_lns.h | 2 +- src/opt/opt_preprocess.cpp | 2 +- src/opt/opt_preprocess.h | 2 +- src/opt/optsmt.h | 2 +- src/opt/pb_sls.h | 2 +- src/parsers/smt2/smt2parser.cpp | 2 +- src/parsers/smt2/smt2scanner.cpp | 2 +- src/parsers/smt2/smt2scanner.h | 2 +- src/qe/mbp/mbp_arith.h | 2 +- src/qe/mbp/mbp_arrays.cpp | 2 +- src/qe/mbp/mbp_arrays.h | 2 +- src/qe/mbp/mbp_datatypes.h | 2 +- src/qe/mbp/mbp_euf.h | 2 +- src/qe/mbp/mbp_plugin.h | 2 +- src/qe/mbp/mbp_tg_plugins.h | 8 ++++---- src/qe/nlarith_util.cpp | 2 +- src/qe/nlarith_util.h | 2 +- src/qe/nlqsat.cpp | 2 +- src/qe/qe.h | 2 +- src/qe/qe_mbi.cpp | 2 +- src/qe/qe_mbi.h | 2 +- src/qe/qsat.cpp | 2 +- src/sat/dimacs.h | 4 ++-- src/sat/sat_anf_simplifier.h | 2 +- src/sat/sat_asymm_branch.cpp | 2 +- src/sat/sat_asymm_branch.h | 2 +- src/sat/sat_bcd.cpp | 2 +- src/sat/sat_bcd.h | 2 +- src/sat/sat_big.cpp | 2 +- src/sat/sat_big.h | 2 +- src/sat/sat_clause.cpp | 2 +- src/sat/sat_clause.h | 2 +- src/sat/sat_clause_set.cpp | 2 +- src/sat/sat_clause_set.h | 2 +- src/sat/sat_clause_use_list.cpp | 2 +- src/sat/sat_clause_use_list.h | 2 +- src/sat/sat_cleaner.cpp | 2 +- src/sat/sat_cleaner.h | 2 +- src/sat/sat_config.cpp | 2 +- src/sat/sat_config.h | 2 +- src/sat/sat_elim_eqs.cpp | 2 +- src/sat/sat_elim_eqs.h | 2 +- src/sat/sat_extension.h | 4 ++-- src/sat/sat_integrity_checker.cpp | 2 +- src/sat/sat_integrity_checker.h | 2 +- src/sat/sat_justification.h | 2 +- src/sat/sat_lookahead.h | 2 +- src/sat/sat_model_converter.cpp | 2 +- src/sat/sat_model_converter.h | 2 +- src/sat/sat_mus.h | 2 +- src/sat/sat_parallel.cpp | 2 +- src/sat/sat_parallel.h | 2 +- src/sat/sat_probing.cpp | 2 +- src/sat/sat_probing.h | 2 +- src/sat/sat_scc.cpp | 2 +- src/sat/sat_scc.h | 2 +- src/sat/sat_simplifier.cpp | 2 +- src/sat/sat_simplifier.h | 2 +- src/sat/sat_solver.cpp | 2 +- src/sat/sat_solver.h | 4 ++-- src/sat/sat_solver_core.h | 4 ++-- src/sat/sat_types.h | 4 ++-- src/sat/sat_watched.cpp | 2 +- src/sat/sat_watched.h | 2 +- src/sat/smt/arith_value.cpp | 2 +- src/sat/smt/arith_value.h | 2 +- src/sat/smt/bv_ackerman.h | 2 +- src/sat/smt/bv_delay_internalize.cpp | 4 ++-- src/sat/smt/bv_solver.cpp | 2 +- src/sat/smt/euf_ackerman.h | 2 +- src/sat/smt/euf_solver.h | 2 +- src/sat/smt/fpa_solver.cpp | 2 +- src/sat/smt/intblast_solver.cpp | 2 +- src/sat/smt/pb_constraint.h | 2 +- src/sat/smt/pb_solver.cpp | 2 +- src/sat/smt/pb_solver.h | 2 +- src/sat/smt/q_queue.h | 2 +- src/sat/smt/user_solver.h | 2 +- src/smt/arith_eq_adapter.cpp | 2 +- src/smt/arith_eq_adapter.h | 2 +- src/smt/dyn_ack.cpp | 2 +- src/smt/dyn_ack.h | 2 +- src/smt/fingerprints.cpp | 2 +- src/smt/fingerprints.h | 2 +- src/smt/mam.h | 2 +- src/smt/qi_queue.cpp | 2 +- src/smt/qi_queue.h | 2 +- src/smt/seq_axioms.h | 2 +- src/smt/seq_offset_eq.h | 2 +- src/smt/seq_regex.h | 2 +- src/smt/smt_almost_cg_table.cpp | 2 +- src/smt/smt_almost_cg_table.h | 2 +- src/smt/smt_arith_value.cpp | 2 +- src/smt/smt_arith_value.h | 2 +- src/smt/smt_b_justification.h | 2 +- src/smt/smt_bool_var_data.h | 2 +- src/smt/smt_case_split_queue.h | 2 +- src/smt/smt_cg_table.cpp | 2 +- src/smt/smt_cg_table.h | 2 +- src/smt/smt_checker.cpp | 2 +- src/smt/smt_checker.h | 2 +- src/smt/smt_clause.cpp | 2 +- src/smt/smt_clause.h | 2 +- src/smt/smt_clause_proof.cpp | 2 +- src/smt/smt_clause_proof.h | 2 +- src/smt/smt_conflict_resolution.cpp | 2 +- src/smt/smt_conflict_resolution.h | 2 +- src/smt/smt_context.cpp | 2 +- src/smt/smt_context.h | 2 +- src/smt/smt_context_inv.cpp | 2 +- src/smt/smt_context_pp.cpp | 2 +- src/smt/smt_context_stat.cpp | 2 +- src/smt/smt_enode.cpp | 2 +- src/smt/smt_enode.h | 2 +- src/smt/smt_eq_justification.h | 2 +- src/smt/smt_failure.h | 2 +- src/smt/smt_for_each_relevant_expr.cpp | 2 +- src/smt/smt_for_each_relevant_expr.h | 4 ++-- src/smt/smt_implied_equalities.h | 2 +- src/smt/smt_internalizer.cpp | 2 +- src/smt/smt_justification.cpp | 2 +- src/smt/smt_justification.h | 2 +- src/smt/smt_kernel.cpp | 2 +- src/smt/smt_kernel.h | 2 +- src/smt/smt_literal.cpp | 2 +- src/smt/smt_literal.h | 2 +- src/smt/smt_model_checker.cpp | 2 +- src/smt/smt_model_checker.h | 2 +- src/smt/smt_model_finder.h | 4 ++-- src/smt/smt_model_generator.cpp | 2 +- src/smt/smt_model_generator.h | 2 +- src/smt/smt_quantifier.cpp | 2 +- src/smt/smt_quantifier.h | 2 +- src/smt/smt_quick_checker.cpp | 2 +- src/smt/smt_quick_checker.h | 2 +- src/smt/smt_relevancy.cpp | 2 +- src/smt/smt_relevancy.h | 2 +- src/smt/smt_setup.cpp | 2 +- src/smt/smt_setup.h | 2 +- src/smt/smt_statistics.cpp | 2 +- src/smt/smt_statistics.h | 2 +- src/smt/smt_theory.cpp | 2 +- src/smt/smt_theory.h | 2 +- src/smt/smt_types.h | 2 +- src/smt/smt_value_sort.h | 2 +- src/smt/theory_arith.cpp | 2 +- src/smt/theory_arith.h | 2 +- src/smt/theory_arith_aux.h | 4 ++-- src/smt/theory_arith_core.h | 2 +- src/smt/theory_arith_eq.h | 2 +- src/smt/theory_arith_int.h | 2 +- src/smt/theory_arith_inv.h | 2 +- src/smt/theory_arith_nl.h | 2 +- src/smt/theory_arith_pp.h | 2 +- src/smt/theory_array.cpp | 2 +- src/smt/theory_array.h | 2 +- src/smt/theory_array_base.cpp | 2 +- src/smt/theory_array_base.h | 2 +- src/smt/theory_array_full.h | 2 +- src/smt/theory_bv.cpp | 2 +- src/smt/theory_bv.h | 2 +- src/smt/theory_datatype.cpp | 2 +- src/smt/theory_datatype.h | 2 +- src/smt/theory_dense_diff_logic.cpp | 2 +- src/smt/theory_dense_diff_logic.h | 2 +- src/smt/theory_dense_diff_logic_def.h | 2 +- src/smt/theory_diff_logic.cpp | 4 ++-- src/smt/theory_diff_logic.h | 2 +- src/smt/theory_dl.cpp | 2 +- src/smt/theory_dl.h | 2 +- src/smt/theory_dummy.cpp | 2 +- src/smt/theory_dummy.h | 2 +- src/smt/theory_fpa.cpp | 2 +- src/smt/theory_fpa.h | 2 +- src/smt/theory_opt.cpp | 2 +- src/smt/theory_pb.h | 2 +- src/smt/theory_polymorphism.h | 2 +- src/smt/theory_seq.h | 2 +- src/smt/theory_seq_empty.h | 2 +- src/smt/theory_user_propagator.h | 2 +- src/smt/theory_utvpi.h | 2 +- src/smt/theory_utvpi_def.h | 2 +- src/smt/theory_wmaxsat.cpp | 2 +- src/smt/theory_wmaxsat.h | 2 +- src/smt/watch_list.cpp | 2 +- src/smt/watch_list.h | 2 +- src/solver/assertions/asserted_formulas.h | 2 +- src/tactic/bv/bv_bound_chk_tactic.cpp | 2 +- src/tactic/core/ctx_simplify_tactic.h | 2 +- src/tactic/core/symmetry_reduce_tactic.cpp | 2 +- src/tactic/tactical.cpp | 2 +- src/util/sat_literal.h | 4 ++-- src/util/sat_sls.h | 2 +- src/util/sign.h | 2 +- src/util/util.h | 2 +- 429 files changed, 477 insertions(+), 476 deletions(-) diff --git a/cmake/compiler_warnings.cmake b/cmake/compiler_warnings.cmake index 2708725875..9e11d9082b 100644 --- a/cmake/compiler_warnings.cmake +++ b/cmake/compiler_warnings.cmake @@ -24,8 +24,9 @@ set(CLANG_ONLY_WARNINGS "-Wsuggest-override" "-Winconsistent-missing-override" "-Wno-missing-field-initializers" - "-Wcast-qual" + "-Wcast-qual" ) + set(MSVC_WARNINGS "/W3") ################################################################################ diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index c35d3aa5b6..34a16789ca 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -447,4 +447,4 @@ extern "C" { return _am.get_i(av); Z3_CATCH_RETURN(0); } -}; +} diff --git a/src/api/api_arith.cpp b/src/api/api_arith.cpp index 17810a4947..806f720b32 100644 --- a/src/api/api_arith.cpp +++ b/src/api/api_arith.cpp @@ -235,4 +235,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_array.cpp b/src/api/api_array.cpp index e01248b31a..6b454530ea 100644 --- a/src/api/api_array.cpp +++ b/src/api/api_array.cpp @@ -358,4 +358,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index d7ea3d3c80..f33f93e29f 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1547,4 +1547,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_ast_map.cpp b/src/api/api_ast_map.cpp index 1ebb51fcce..dead361cf7 100644 --- a/src/api/api_ast_map.cpp +++ b/src/api/api_ast_map.cpp @@ -161,4 +161,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_ast_vector.cpp b/src/api/api_ast_vector.cpp index 46a8894387..b74fecef3b 100644 --- a/src/api/api_ast_vector.cpp +++ b/src/api/api_ast_vector.cpp @@ -135,4 +135,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_ast_vector.h b/src/api/api_ast_vector.h index dc1fcb8e6a..f661b8d8d2 100644 --- a/src/api/api_ast_vector.h +++ b/src/api/api_ast_vector.h @@ -21,7 +21,7 @@ Revision History: namespace api { class context; -}; +} struct Z3_ast_vector_ref : public api::object { ast_ref_vector m_ast_vector; diff --git a/src/api/api_bv.cpp b/src/api/api_bv.cpp index 5b627944c7..77e7bfbc29 100644 --- a/src/api/api_bv.cpp +++ b/src/api/api_bv.cpp @@ -399,4 +399,4 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_CATCH_RETURN(0); } -}; +} diff --git a/src/api/api_config_params.cpp b/src/api/api_config_params.cpp index 02bcde2a93..ba926a967f 100644 --- a/src/api/api_config_params.cpp +++ b/src/api/api_config_params.cpp @@ -121,4 +121,4 @@ extern "C" { Z3_CATCH; } -}; +} diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 7fe4e40634..624980d507 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -359,7 +359,7 @@ namespace api { return *(m_rcf_manager.get()); } -}; +} // ------------------------ @@ -531,4 +531,4 @@ extern "C" { Z3_CATCH; } -}; +} diff --git a/src/api/api_context.h b/src/api/api_context.h index 7803725886..80fc90569e 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -45,16 +45,16 @@ Revision History: namespace smtlib { class parser; -}; +} namespace realclosure { class manager; -}; +} namespace smt2 { class parser; void free_parser(parser*); -}; +} namespace api { @@ -267,7 +267,7 @@ namespace api { }; -}; +} inline api::context * mk_c(Z3_context c) { return reinterpret_cast(c); } #define RESET_ERROR_CODE() { mk_c(c)->reset_error_code(); } diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 61d4aa9fda..072b5c8fff 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -142,7 +142,7 @@ namespace api { void collect_param_descrs(param_descrs & p) { m_context.collect_params(p); } void updt_params(params_ref const& p) { m_context.updt_params(p); } }; -}; +} extern "C" { @@ -705,4 +705,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_datalog.h b/src/api/api_datalog.h index 7f1ceb9bbf..11fbf7e119 100644 --- a/src/api/api_datalog.h +++ b/src/api/api_datalog.h @@ -30,7 +30,7 @@ typedef void (*reduce_assign_callback_fptr)(void*, func_decl*, unsigned, expr*co namespace api { class fixedpoint_context; class context; -}; +} struct Z3_fixedpoint_ref : public api::object { diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index ee381e3e78..8d9d0dd206 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -687,4 +687,4 @@ extern "C" { } -}; +} diff --git a/src/api/api_finite_set.cpp b/src/api/api_finite_set.cpp index 2a2787e2a2..922ffe3f2c 100644 --- a/src/api/api_finite_set.cpp +++ b/src/api/api_finite_set.cpp @@ -184,4 +184,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index aeeb24c419..8ffbd4f13e 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -1337,4 +1337,4 @@ extern "C" { Z3_CATCH_RETURN(false); } -}; +} diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index 7ef619c9b3..ae7d832a93 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -213,4 +213,4 @@ extern "C" { Z3_CATCH_RETURN(""); } -}; +} diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 3e065fb64e..500cbce37e 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -448,4 +448,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index cee60272ef..d6cc5afbcb 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -489,4 +489,4 @@ extern "C" { } #endif -}; +} diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index bf8fc98714..47f9dba6c0 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -503,4 +503,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_params.cpp b/src/api/api_params.cpp index efd33cc057..acc3ab7c7a 100644 --- a/src/api/api_params.cpp +++ b/src/api/api_params.cpp @@ -212,4 +212,4 @@ extern "C" { Z3_CATCH_RETURN(""); } -}; +} diff --git a/src/api/api_pb.cpp b/src/api/api_pb.cpp index a51a7c0696..963fe7fa00 100644 --- a/src/api/api_pb.cpp +++ b/src/api/api_pb.cpp @@ -106,4 +106,4 @@ extern "C" { } -}; +} diff --git a/src/api/api_polynomial.cpp b/src/api/api_polynomial.cpp index 55d4a43a8e..ba8345aeeb 100644 --- a/src/api/api_polynomial.cpp +++ b/src/api/api_polynomial.cpp @@ -80,4 +80,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index 83e2fa5932..de1c6ff48d 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -583,5 +583,5 @@ extern "C" { return Z3_ast_to_string(c, reinterpret_cast(p)); } -}; +} diff --git a/src/api/api_rcf.cpp b/src/api/api_rcf.cpp index efbeea2e6c..49bc218f3a 100644 --- a/src/api/api_rcf.cpp +++ b/src/api/api_rcf.cpp @@ -437,4 +437,4 @@ extern "C" { return from_rcnumeral(rcfm(c).get_sign_condition_coefficient(to_rcnumeral(a), i, j)); Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 4ceb827397..94756cc584 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -369,4 +369,4 @@ extern "C" { MK_FOURARY(Z3_mk_seq_foldli, mk_c(c)->get_seq_fid(), OP_SEQ_FOLDLI, SKIP); -}; +} diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 3da3619213..2d39e3287a 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -1218,4 +1218,4 @@ extern "C" { -}; +} diff --git a/src/api/api_special_relations.cpp b/src/api/api_special_relations.cpp index f29254cba2..0063fe7863 100644 --- a/src/api/api_special_relations.cpp +++ b/src/api/api_special_relations.cpp @@ -61,4 +61,4 @@ extern "C" { } MK_DECL(Z3_mk_transitive_closure, OP_SPECIAL_RELATION_TC); -}; +} diff --git a/src/api/api_stats.cpp b/src/api/api_stats.cpp index a3b8bacf07..b4f97716b7 100644 --- a/src/api/api_stats.cpp +++ b/src/api/api_stats.cpp @@ -133,4 +133,4 @@ extern "C" { return memory::get_allocation_size(); } -}; +} diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index e0038d8b75..8a639727f5 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -669,4 +669,4 @@ extern "C" { -}; +} diff --git a/src/api/api_util.h b/src/api/api_util.h index ee38c4f275..a1715eaa09 100644 --- a/src/api/api_util.h +++ b/src/api/api_util.h @@ -46,7 +46,7 @@ namespace api { void inc_ref(); void dec_ref(); }; -}; +} inline ast * to_ast(Z3_ast a) { return reinterpret_cast(a); } inline Z3_ast of_ast(ast* a) { return reinterpret_cast(a); } diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 5172226aee..cfad378a17 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -24,7 +24,7 @@ class sexpr; namespace algebraic_numbers { class anum; class manager; -}; +} enum arith_sort_kind { REAL_SORT, diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 41ed2036bb..f7d65f2b43 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -171,7 +171,7 @@ namespace datatype { size* subst(obj_map& S) override; sort_size eval(obj_map const& S) override { return S[m_param]; } }; - }; + } class def { ast_manager& m; @@ -465,7 +465,7 @@ namespace datatype { sort_ref mk_tuple_datatype(svector> const& elems, symbol const& name, symbol const& test, func_decl_ref& tup, func_decl_ref_vector& accs); }; -}; +} typedef datatype::accessor accessor_decl; typedef datatype::constructor constructor_decl; diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp index af4d30add8..1be709324c 100644 --- a/src/ast/dl_decl_plugin.cpp +++ b/src/ast/dl_decl_plugin.cpp @@ -648,7 +648,7 @@ namespace datalog { m_fid = m.mk_family_id(symbol("datalog_relation")); } return m_fid; - }; + } arith_util& dl_decl_util::arith() const { if (!m_arith) m_arith = alloc(arith_util, m); @@ -788,4 +788,4 @@ namespace datalog { return m.mk_app(f, num_args, args); } -}; +} diff --git a/src/ast/dl_decl_plugin.h b/src/ast/dl_decl_plugin.h index 850d181267..2acbb362a6 100644 --- a/src/ast/dl_decl_plugin.h +++ b/src/ast/dl_decl_plugin.h @@ -199,5 +199,5 @@ namespace datalog { }; -}; +} diff --git a/src/ast/euf/euf_ac_plugin.h b/src/ast/euf/euf_ac_plugin.h index 99d01791c7..352337a2f1 100644 --- a/src/ast/euf/euf_ac_plugin.h +++ b/src/ast/euf/euf_ac_plugin.h @@ -319,14 +319,14 @@ namespace euf { struct eq_pp { ac_plugin const& p; eq const& e; - eq_pp(ac_plugin const& p, eq const& e) : p(p), e(e) {}; + eq_pp(ac_plugin const& p, eq const& e) : p(p), e(e) {} eq_pp(ac_plugin const& p, unsigned eq_id): p(p), e(p.m_active[eq_id]) {} std::ostream& display(std::ostream& out) const { return p.display_equation(out, e); } }; struct eq_pp_ll { ac_plugin const& p; eq const& e; - eq_pp_ll(ac_plugin const& p, eq const& e) : p(p), e(e) {}; + eq_pp_ll(ac_plugin const& p, eq const& e) : p(p), e(e) {} eq_pp_ll(ac_plugin const& p, unsigned eq_id) : p(p), e(p.m_active[eq_id]) {} std::ostream& display(std::ostream& out) const { return p.display_equation_ll(out, e); } }; diff --git a/src/ast/euf/euf_etable.cpp b/src/ast/euf/euf_etable.cpp index b308523a54..93be311740 100644 --- a/src/ast/euf/euf_etable.cpp +++ b/src/ast/euf/euf_etable.cpp @@ -276,5 +276,5 @@ namespace euf { return find(n) == n; } -}; +} diff --git a/src/ast/euf/euf_etable.h b/src/ast/euf/euf_etable.h index d6b64e7566..ecac03a228 100644 --- a/src/ast/euf/euf_etable.h +++ b/src/ast/euf/euf_etable.h @@ -179,7 +179,7 @@ namespace euf { }; -}; +} diff --git a/src/ast/euf/euf_mam.h b/src/ast/euf/euf_mam.h index c391f6c09c..a6c20d74b6 100644 --- a/src/ast/euf/euf_mam.h +++ b/src/ast/euf/euf_mam.h @@ -81,5 +81,5 @@ namespace euf { static void ground_subterms(expr* e, ptr_vector& ground); }; -}; +} diff --git a/src/ast/euf/euf_plugin.h b/src/ast/euf/euf_plugin.h index ba6b2d5f93..0a9503ba5d 100644 --- a/src/ast/euf/euf_plugin.h +++ b/src/ast/euf/euf_plugin.h @@ -47,7 +47,7 @@ namespace euf { virtual void merge_eh(enode* n1, enode* n2) = 0; - virtual void diseq_eh(enode* eq) {}; + virtual void diseq_eh(enode* eq) {} virtual void propagate() = 0; diff --git a/src/ast/for_each_expr.cpp b/src/ast/for_each_expr.cpp index ebad5760cb..ee61f7587e 100644 --- a/src/ast/for_each_expr.cpp +++ b/src/ast/for_each_expr.cpp @@ -94,7 +94,7 @@ namespace has_skolem_functions_ns { void operator()(app const * n) const { if (n->get_decl()->is_skolem() && n->get_num_args() > 0) throw found(); } void operator()(quantifier * n) const {} }; -}; +} bool has_skolem_functions(expr * n) { has_skolem_functions_ns::proc p; diff --git a/src/ast/format.cpp b/src/ast/format.cpp index 6583e9893d..a21f21eebf 100644 --- a/src/ast/format.cpp +++ b/src/ast/format.cpp @@ -195,4 +195,4 @@ namespace format_ns { return fm(m).mk_app(fid(m), OP_NIL); } -}; +} diff --git a/src/ast/format.h b/src/ast/format.h index 2714d54b74..b7356b8029 100644 --- a/src/ast/format.h +++ b/src/ast/format.h @@ -198,6 +198,6 @@ namespace format_ns { return mk_seq4(m, begin, end, proc, static_cast(strlen(lp)), lp, rp); } -}; +} diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index e237c0dcde..0350694082 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -162,10 +162,10 @@ public: void dbg_decouple(const char * prefix, expr_ref & e); expr_ref_vector m_extra_assertions; - special_t const & get_min_max_specials() const { return m_min_max_ufs; }; - const2bv_t const & get_const2bv() const { return m_const2bv; }; - const2bv_t const & get_rm_const2bv() const { return m_rm_const2bv; }; - uf2bvuf_t const & get_uf2bvuf() const { return m_uf2bvuf; }; + special_t const & get_min_max_specials() const { return m_min_max_ufs; } + const2bv_t const & get_const2bv() const { return m_const2bv; } + const2bv_t const & get_rm_const2bv() const { return m_rm_const2bv; } + uf2bvuf_t const & get_uf2bvuf() const { return m_uf2bvuf; } protected: void mk_one(func_decl *f, expr_ref & sign, expr_ref & result); diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index a9a0c77fcf..a9a4618909 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -167,7 +167,7 @@ namespace macro_manager_ns { } } }; -}; +} /** \brief Mark all func_decls used in exprs as forbidden. diff --git a/src/ast/macros/quasi_macros.cpp b/src/ast/macros/quasi_macros.cpp index 094a7cabab..a8fa7187ef 100644 --- a/src/ast/macros/quasi_macros.cpp +++ b/src/ast/macros/quasi_macros.cpp @@ -71,7 +71,7 @@ void quasi_macros::find_occurrences(expr * e) { default: UNREACHABLE(); } } -}; +} bool quasi_macros::is_non_ground_uninterp(expr const * e) const { return is_non_ground(e) && is_uninterp(e); diff --git a/src/ast/polymorphism_inst.h b/src/ast/polymorphism_inst.h index 1d171b3143..d9a6ed943d 100644 --- a/src/ast/polymorphism_inst.h +++ b/src/ast/polymorphism_inst.h @@ -58,7 +58,7 @@ namespace polymorphism { void undo() override { i.m_in_decl_queue.mark(i.m_decl_queue.back(), false); i.m_decl_queue.pop_back(); - }; + } }; struct remove_back : public trail { diff --git a/src/ast/quantifier_stat.cpp b/src/ast/quantifier_stat.cpp index 17efb11e9a..a09d8bd928 100644 --- a/src/ast/quantifier_stat.cpp +++ b/src/ast/quantifier_stat.cpp @@ -115,5 +115,5 @@ namespace q { return r; } -}; +} diff --git a/src/ast/quantifier_stat.h b/src/ast/quantifier_stat.h index 45fd58530c..5bff878f1c 100644 --- a/src/ast/quantifier_stat.h +++ b/src/ast/quantifier_stat.h @@ -149,6 +149,6 @@ namespace q { quantifier_stat * operator()(quantifier * q, unsigned generation); }; -}; +} diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index d9fe07dcf3..f876d3ce89 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -60,7 +60,7 @@ namespace recfun { func_decl_ref m_pred; // interval; typedef obj_map bound_map; - bv_bounds(ast_manager& m) : m_m(m), m_bv_util(m), m_okay(true) {}; + bv_bounds(ast_manager& m) : m_m(m), m_bv_util(m), m_okay(true) {} ~bv_bounds(); public: // bounds addition methods br_status rewrite(unsigned limit, func_decl * f, unsigned num, expr * const * args, expr_ref& result); diff --git a/src/ast/rewriter/seq_axioms.h b/src/ast/rewriter/seq_axioms.h index 5838985625..26469ffa2a 100644 --- a/src/ast/rewriter/seq_axioms.h +++ b/src/ast/rewriter/seq_axioms.h @@ -123,5 +123,5 @@ namespace seq { }; -}; +} diff --git a/src/ast/rewriter/seq_eq_solver.cpp b/src/ast/rewriter/seq_eq_solver.cpp index e1ffae7431..a77aaa55ba 100644 --- a/src/ast/rewriter/seq_eq_solver.cpp +++ b/src/ast/rewriter/seq_eq_solver.cpp @@ -727,5 +727,5 @@ namespace seq { -}; +} diff --git a/src/ast/rewriter/seq_eq_solver.h b/src/ast/rewriter/seq_eq_solver.h index c6c5437b79..a3e8a00d47 100644 --- a/src/ast/rewriter/seq_eq_solver.h +++ b/src/ast/rewriter/seq_eq_solver.h @@ -167,5 +167,5 @@ namespace seq { }; -}; +} diff --git a/src/ast/rewriter/seq_skolem.h b/src/ast/rewriter/seq_skolem.h index 4e327f0fa4..39cf2534fe 100644 --- a/src/ast/rewriter/seq_skolem.h +++ b/src/ast/rewriter/seq_skolem.h @@ -171,5 +171,5 @@ namespace seq { }; -}; +} diff --git a/src/ast/simplifiers/distribute_forall.cpp b/src/ast/simplifiers/distribute_forall.cpp index c7cc6659aa..eb57038103 100644 --- a/src/ast/simplifiers/distribute_forall.cpp +++ b/src/ast/simplifiers/distribute_forall.cpp @@ -101,5 +101,5 @@ void distribute_forall_simplifier::reduce() { if (r != d.fml()) m_fmls.update(idx, dependent_expr(m, r, mp(d.pr(), pr), d.dep())); } -}; +} diff --git a/src/ast/simplifiers/propagate_values.cpp b/src/ast/simplifiers/propagate_values.cpp index efaf7f244a..36c132295f 100644 --- a/src/ast/simplifiers/propagate_values.cpp +++ b/src/ast/simplifiers/propagate_values.cpp @@ -62,7 +62,7 @@ void propagate_values::add_sub(dependent_expr const& de) { else if (m.is_value(y) && m_shared.is_shared(x)) m_subst.insert(x, y, dep); } -}; +} void propagate_values::reduce() { m_shared.reset(); diff --git a/src/ast/sls/sls_array_plugin.h b/src/ast/sls/sls_array_plugin.h index 4040e8d57a..84fadc1260 100644 --- a/src/ast/sls/sls_array_plugin.h +++ b/src/ast/sls/sls_array_plugin.h @@ -36,7 +36,7 @@ namespace sls { for (unsigned i = 1; i < a.sel->num_args(); ++i) h ^= a.sel->get_arg(i)->get_root()->hash(); return h; - }; + } }; struct select_args_eq { bool operator()(select_args const& a, select_args const& b) const { @@ -103,13 +103,13 @@ namespace sls { euf::enode* mk_select(euf::egraph& g, euf::enode* b, euf::enode* sel); void resolve_conflict(); - size_t* to_ptr(sat::literal l) { return reinterpret_cast((size_t)(l.index() << 4)); }; + size_t* to_ptr(sat::literal l) { return reinterpret_cast((size_t)(l.index() << 4)); } size_t* to_ptr(euf::enode* t) { return reinterpret_cast((reinterpret_cast(t) << 4) + 1); } size_t* to_ptr(unsigned n) { return reinterpret_cast((size_t)(n << 4) + 3); } bool is_literal(size_t* p) { return (reinterpret_cast(p) & 3) == 0; } bool is_index(size_t* p) { return (reinterpret_cast(p) & 3) == 3; } bool is_enode(size_t* p) { return (reinterpret_cast(p) & 3) == 1; } - sat::literal to_literal(size_t* p) { return sat::to_literal(static_cast(reinterpret_cast(p) >> 4)); }; + sat::literal to_literal(size_t* p) { return sat::to_literal(static_cast(reinterpret_cast(p) >> 4)); } euf::enode* to_enode(size_t* p) { return reinterpret_cast(reinterpret_cast(p) >> 4); } unsigned to_index(size_t* p) { return static_cast(reinterpret_cast(p) >> 4); } diff --git a/src/ast/sls/sls_bv_lookahead.cpp b/src/ast/sls/sls_bv_lookahead.cpp index 87398429e4..b8b46f9d6d 100644 --- a/src/ast/sls/sls_bv_lookahead.cpp +++ b/src/ast/sls/sls_bv_lookahead.cpp @@ -871,8 +871,8 @@ namespace sls { if (m_la.m_config.use_top_level_assertions) return m_la.ctx.input_assertions().get(idx); return m_la.ctx.atom(m_la.ctx.root_literals()[idx].var()); - }; + } -} \ No newline at end of file +} diff --git a/src/ast/sls/sls_bv_tracker.h b/src/ast/sls/sls_bv_tracker.h index a078de5a19..e87190d9b2 100644 --- a/src/ast/sls/sls_bv_tracker.h +++ b/src/ast/sls/sls_bv_tracker.h @@ -40,7 +40,7 @@ class sls_tracker { mpz m_zero, m_one, m_two; struct value_score { - value_score() : value(unsynch_mpz_manager::mk_z(0)) {}; + value_score() : value(unsynch_mpz_manager::mk_z(0)) {} value_score(value_score&&) noexcept = default; value_score(const value_score &other) { m = other.m; diff --git a/src/ast/sls/sls_context.h b/src/ast/sls/sls_context.h index fae5447eb7..8cad22dc16 100644 --- a/src/ast/sls/sls_context.h +++ b/src/ast/sls/sls_context.h @@ -44,15 +44,15 @@ namespace sls { virtual expr_ref get_value(expr* e) = 0; virtual bool is_fixed(expr* e, expr_ref& value) { return false; } virtual void initialize() = 0; - virtual void start_propagation() {}; + virtual void start_propagation() {} virtual bool propagate() = 0; virtual void propagate_literal(sat::literal lit) = 0; virtual void repair_literal(sat::literal lit) = 0; virtual bool repair_down(app* e) = 0; virtual void repair_up(app* e) = 0; virtual bool is_sat() = 0; - virtual void on_rescale() {}; - virtual void on_restart() {}; + virtual void on_rescale() {} + virtual void on_restart() {} virtual std::ostream& display(std::ostream& out) const = 0; virtual bool set_value(expr* e, expr* v) = 0; virtual void collect_statistics(statistics& st) const = 0; diff --git a/src/ast/sls/sls_euf_plugin.h b/src/ast/sls/sls_euf_plugin.h index 45c93a8d06..99523f5077 100644 --- a/src/ast/sls/sls_euf_plugin.h +++ b/src/ast/sls/sls_euf_plugin.h @@ -52,8 +52,8 @@ namespace sls { bool is_user_sort(sort* s) { return s->get_family_id() == user_sort_family_id; } - size_t* to_ptr(sat::literal l) { return reinterpret_cast((size_t)(l.index() << 4)); }; - sat::literal to_literal(size_t* p) { return sat::to_literal(static_cast(reinterpret_cast(p) >> 4)); }; + size_t* to_ptr(sat::literal l) { return reinterpret_cast((size_t)(l.index() << 4)); } + sat::literal to_literal(size_t* p) { return sat::to_literal(static_cast(reinterpret_cast(p) >> 4)); } void validate_model(); void log_clause(sat::literal_vector const& lits); diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index d7316619f7..aaf1f1b479 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -581,7 +581,7 @@ class mbp_qel_cmd : public cmd { ptr_vector m_vars; public: - mbp_qel_cmd() : cmd("mbp-qel"){}; + mbp_qel_cmd() : cmd("mbp-qel"){} char const *get_usage() const override { return "(exprs) (vars)"; } char const *get_descr(cmd_context &ctx) const override { return "Model based projection using e-graphs"; @@ -639,7 +639,7 @@ class qel_cmd : public cmd { ptr_vector m_vars; public: - qel_cmd() : cmd("qel"){}; + qel_cmd() : cmd("qel"){} char const *get_usage() const override { return "(lits) (vars)"; } char const *get_descr(cmd_context &ctx) const override { return "QE lite over e-graphs"; @@ -703,7 +703,7 @@ class qe_lite_cmd : public cmd { ptr_vector m_vars; public: - qe_lite_cmd() : cmd("qe-lite"){}; + qe_lite_cmd() : cmd("qe-lite"){} char const *get_usage() const override { return "(lits) (vars)"; } char const *get_descr(cmd_context &ctx) const override { return "QE lite over e-graphs"; diff --git a/src/math/grobner/pdd_simplifier.cpp b/src/math/grobner/pdd_simplifier.cpp index 8cc47c21e6..df12638d89 100644 --- a/src/math/grobner/pdd_simplifier.cpp +++ b/src/math/grobner/pdd_simplifier.cpp @@ -494,7 +494,7 @@ namespace dd { hash(unsigned_vector& vars):vars(vars) {} bool operator()(mon const& m) const { return unsigned_ptr_hash(vars.data() + m.offset, m.sz, 1); - }; + } }; struct eq { unsigned_vector& vars; diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index d1ac780e84..fe0d403fba 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -267,7 +267,7 @@ namespace lp { unsigned j, const T &m, X &theta, bool &unlimited) { SASSERT(m > 0 && this->m_column_types[j] == column_type::upper_bound); limit_inf_on_bound_m_pos(m, this->m_x[j], this->m_upper_bounds[j], theta, unlimited); - }; + } void get_bound_on_variable_and_update_leaving_precisely( unsigned j, vector &leavings, T m, X &t, diff --git a/src/math/lp/nla_types.h b/src/math/lp/nla_types.h index 89823e4dc3..a57ca15e6b 100644 --- a/src/math/lp/nla_types.h +++ b/src/math/lp/nla_types.h @@ -43,9 +43,9 @@ namespace nla { ineq(lpvar v, lp::lconstraint_kind cmp, rational const& r): m_cmp(cmp), m_term(v), m_rs(r) {} bool operator==(const ineq& a) const = delete; bool operator!=(const ineq& a) const = delete; - const lp::lar_term& term() const { return m_term; }; - lp::lconstraint_kind cmp() const { return m_cmp; }; - const rational& rs() const { return m_rs; }; + const lp::lar_term& term() const { return m_term; } + lp::lconstraint_kind cmp() const { return m_cmp; } + const rational& rs() const { return m_rs; } }; class lemma { diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp index a890913c2d..945b9023dc 100644 --- a/src/math/polynomial/algebraic_numbers.cpp +++ b/src/math/polynomial/algebraic_numbers.cpp @@ -3511,4 +3511,4 @@ namespace algebraic_numbers { void manager::collect_statistics(statistics & st) const { m_imp->collect_statistics(st); } -}; +} diff --git a/src/math/polynomial/algebraic_numbers.h b/src/math/polynomial/algebraic_numbers.h index e60f8ea1a9..37c0559728 100644 --- a/src/math/polynomial/algebraic_numbers.h +++ b/src/math/polynomial/algebraic_numbers.h @@ -410,7 +410,7 @@ namespace algebraic_numbers { anum& operator=(basic_cell* cell) { SASSERT(is_null()); m_cell = TAG(void*, cell, BASIC); return *this; } anum& operator=(algebraic_cell* cell) { SASSERT(is_null()); m_cell = TAG(void*, cell, ROOT); return *this; } }; -}; +} typedef algebraic_numbers::manager anum_manager; typedef algebraic_numbers::manager::numeral anum; diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index 1b06fb2b09..84825baeb8 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -8253,7 +8253,7 @@ namespace polynomial { p->display_smt2(out, m_imp->m_manager, proc); return out; } -}; +} polynomial::polynomial * convert(polynomial::manager & sm, polynomial::polynomial * p, polynomial::manager & tm, polynomial::var x, unsigned max_d) { diff --git a/src/math/polynomial/polynomial.h b/src/math/polynomial/polynomial.h index 5774e6e132..9d0bcabcf3 100644 --- a/src/math/polynomial/polynomial.h +++ b/src/math/polynomial/polynomial.h @@ -36,7 +36,7 @@ class small_object_allocator; namespace algebraic_numbers { class anum; class manager; -}; +} namespace polynomial { typedef unsigned var; @@ -1065,7 +1065,7 @@ namespace polynomial { scoped_set_zp(manager & _m, uint64_t p):m(_m), m_modular(m.modular()), m_p(m.m()) { m_p = m.p(); m.set_zp(p); } ~scoped_set_zp() { if (m_modular) m.set_zp(m_p); else m.set_z(); } }; -}; +} typedef polynomial::polynomial_ref polynomial_ref; typedef polynomial::polynomial_ref_vector polynomial_ref_vector; diff --git a/src/math/polynomial/polynomial_cache.cpp b/src/math/polynomial/polynomial_cache.cpp index 7d3a15ded6..095027bae4 100644 --- a/src/math/polynomial/polynomial_cache.cpp +++ b/src/math/polynomial/polynomial_cache.cpp @@ -256,4 +256,4 @@ namespace polynomial { dealloc(m_imp); m_imp = alloc(imp, _m); } -}; +} diff --git a/src/math/polynomial/polynomial_cache.h b/src/math/polynomial/polynomial_cache.h index a27abf42d1..ae8fa0ed82 100644 --- a/src/math/polynomial/polynomial_cache.h +++ b/src/math/polynomial/polynomial_cache.h @@ -40,4 +40,4 @@ namespace polynomial { void factor(polynomial const * p, polynomial_ref_vector & distinct_factors); void reset(); }; -}; +} diff --git a/src/math/polynomial/polynomial_primes.h b/src/math/polynomial/polynomial_primes.h index ea2baf0dcc..4c9e05e778 100644 --- a/src/math/polynomial/polynomial_primes.h +++ b/src/math/polynomial/polynomial_primes.h @@ -66,5 +66,5 @@ namespace polynomial { }; #endif -}; +} diff --git a/src/math/polynomial/polynomial_var2value.h b/src/math/polynomial/polynomial_var2value.h index 11e8c3bb8e..2897e74149 100644 --- a/src/math/polynomial/polynomial_var2value.h +++ b/src/math/polynomial/polynomial_var2value.h @@ -43,6 +43,6 @@ namespace polynomial { } }; -}; +} diff --git a/src/math/polynomial/rpolynomial.cpp b/src/math/polynomial/rpolynomial.cpp index 67b8825253..17a3be50d4 100644 --- a/src/math/polynomial/rpolynomial.cpp +++ b/src/math/polynomial/rpolynomial.cpp @@ -789,4 +789,4 @@ namespace rpolynomial { } #endif -}; +} diff --git a/src/math/polynomial/rpolynomial.h b/src/math/polynomial/rpolynomial.h index 2a5123a031..ab04c99d63 100644 --- a/src/math/polynomial/rpolynomial.h +++ b/src/math/polynomial/rpolynomial.h @@ -175,7 +175,7 @@ namespace rpolynomial { return out; } }; -}; +} typedef rpolynomial::polynomial_ref rpolynomial_ref; typedef rpolynomial::polynomial_ref_vector rpolynomial_ref_vector; diff --git a/src/math/polynomial/upolynomial.cpp b/src/math/polynomial/upolynomial.cpp index a30691c9df..7ce6aab5a6 100644 --- a/src/math/polynomial/upolynomial.cpp +++ b/src/math/polynomial/upolynomial.cpp @@ -3142,4 +3142,4 @@ namespace upolynomial { } return out; } -}; +} diff --git a/src/math/polynomial/upolynomial.h b/src/math/polynomial/upolynomial.h index de29a1cdf4..135422b94f 100644 --- a/src/math/polynomial/upolynomial.h +++ b/src/math/polynomial/upolynomial.h @@ -917,4 +917,4 @@ namespace upolynomial { std::ostream& display(std::ostream & out, upolynomial_sequence const & seq, char const * var_name = "x") const; }; -}; +} diff --git a/src/math/polynomial/upolynomial_factorization.cpp b/src/math/polynomial/upolynomial_factorization.cpp index 1ab95def35..34bd83b7ad 100644 --- a/src/math/polynomial/upolynomial_factorization.cpp +++ b/src/math/polynomial/upolynomial_factorization.cpp @@ -1299,4 +1299,4 @@ bool factor_square_free(z_manager & upm, numeral_vector const & f, factors & fs, return factor_square_free(upm, f, fs, 1, params); } -}; // end upolynomial namespace +} // end upolynomial namespace diff --git a/src/math/polynomial/upolynomial_factorization.h b/src/math/polynomial/upolynomial_factorization.h index 3842665bd1..14ec508c3b 100644 --- a/src/math/polynomial/upolynomial_factorization.h +++ b/src/math/polynomial/upolynomial_factorization.h @@ -90,5 +90,5 @@ namespace upolynomial { That is, the factors of f are inserted as factors of degree k into fs. */ bool factor_square_free(z_manager & upm, numeral_vector const & f, factors & fs, unsigned k, factor_params const & ps = factor_params()); -}; +} diff --git a/src/math/polynomial/upolynomial_factorization_int.h b/src/math/polynomial/upolynomial_factorization_int.h index f47610b65d..45f0204441 100644 --- a/src/math/polynomial/upolynomial_factorization_int.h +++ b/src/math/polynomial/upolynomial_factorization_int.h @@ -416,5 +416,5 @@ namespace upolynomial { } } }; -}; +} diff --git a/src/math/realclosure/realclosure.cpp b/src/math/realclosure/realclosure.cpp index 4ba1c11fa7..427070a85d 100644 --- a/src/math/realclosure/realclosure.cpp +++ b/src/math/realclosure/realclosure.cpp @@ -6486,7 +6486,7 @@ namespace realclosure { { return m_imp->get_sign_condition_coefficient(a, i, j); } -}; +} void pp(realclosure::manager::imp * imp, realclosure::polynomial const & p, realclosure::extension * ext) { imp->display_polynomial_expr(std::cout, p, ext, false, false); diff --git a/src/math/realclosure/realclosure.h b/src/math/realclosure/realclosure.h index a1fae3e2bf..b256ffd15b 100644 --- a/src/math/realclosure/realclosure.h +++ b/src/math/realclosure/realclosure.h @@ -317,7 +317,7 @@ namespace realclosure { void * data() { return m_value; } static num mk(void * ptr) { num r; r.m_value = reinterpret_cast(ptr); return r; } }; -}; +} typedef realclosure::manager rcmanager; typedef rcmanager::numeral rcnumeral; diff --git a/src/math/simplex/simplex.cpp b/src/math/simplex/simplex.cpp index 6174b81b35..30de88c543 100644 --- a/src/math/simplex/simplex.cpp +++ b/src/math/simplex/simplex.cpp @@ -74,4 +74,4 @@ namespace simplex { } } } -}; +} diff --git a/src/math/simplex/simplex.h b/src/math/simplex/simplex.h index 0405a59d0b..ad194ebe71 100644 --- a/src/math/simplex/simplex.h +++ b/src/math/simplex/simplex.h @@ -204,5 +204,5 @@ namespace simplex { void kernel(sparse_matrix& s, vector>& K); void kernel_ffe(sparse_matrix &s, vector> &K); -}; +} diff --git a/src/math/simplex/simplex_def.h b/src/math/simplex/simplex_def.h index 69ed434ce6..f7adf424d6 100644 --- a/src/math/simplex/simplex_def.h +++ b/src/math/simplex/simplex_def.h @@ -1035,6 +1035,6 @@ namespace simplex { } -}; +} diff --git a/src/math/simplex/sparse_matrix.h b/src/math/simplex/sparse_matrix.h index 942873b5fa..90cd88d142 100644 --- a/src/math/simplex/sparse_matrix.h +++ b/src/math/simplex/sparse_matrix.h @@ -355,4 +355,4 @@ namespace simplex { typedef unsynch_mpq_inf_manager eps_manager; }; -}; +} diff --git a/src/math/simplex/sparse_matrix_def.h b/src/math/simplex/sparse_matrix_def.h index fd4e7b0c32..430310bc89 100644 --- a/src/math/simplex/sparse_matrix_def.h +++ b/src/math/simplex/sparse_matrix_def.h @@ -603,5 +603,5 @@ namespace simplex { -}; +} diff --git a/src/math/subpaving/subpaving.cpp b/src/math/subpaving/subpaving.cpp index d531f1bafd..51d7b753e0 100644 --- a/src/math/subpaving/subpaving.cpp +++ b/src/math/subpaving/subpaving.cpp @@ -271,4 +271,4 @@ namespace subpaving { return alloc(context_mpfx_wrapper, lim, m, qm, p, a); } -}; +} diff --git a/src/math/subpaving/subpaving.h b/src/math/subpaving/subpaving.h index b76f5e8313..0c5a76770d 100644 --- a/src/math/subpaving/subpaving.h +++ b/src/math/subpaving/subpaving.h @@ -116,6 +116,6 @@ context * mk_hwf_context(reslimit& lim, f2n & m, unsynch_mpq_manage context * mk_mpff_context(reslimit& lim, mpff_manager & m, unsynch_mpq_manager & qm, params_ref const & p = params_ref(), small_object_allocator * a = nullptr); context * mk_mpfx_context(reslimit& lim, mpfx_manager & m, unsynch_mpq_manager & qm, params_ref const & p = params_ref(), small_object_allocator * a = nullptr); -}; +} diff --git a/src/math/subpaving/subpaving_hwf.h b/src/math/subpaving/subpaving_hwf.h index f2378a73a4..49f2dbc5fa 100644 --- a/src/math/subpaving/subpaving_hwf.h +++ b/src/math/subpaving/subpaving_hwf.h @@ -42,5 +42,5 @@ public: context_hwf(reslimit& lim, f2n & m, params_ref const & p, small_object_allocator * a):context_t(lim, config_hwf(m), p, a) {} }; -}; +} diff --git a/src/math/subpaving/subpaving_mpf.h b/src/math/subpaving/subpaving_mpf.h index 213c3c94b6..bc50de6fdf 100644 --- a/src/math/subpaving/subpaving_mpf.h +++ b/src/math/subpaving/subpaving_mpf.h @@ -43,5 +43,5 @@ public: context_mpf(reslimit& lim, f2n & m, params_ref const & p, small_object_allocator * a):context_t(lim, config_mpf(m), p, a) {} }; -}; +} diff --git a/src/math/subpaving/subpaving_mpff.h b/src/math/subpaving/subpaving_mpff.h index 763195cb91..631293be0c 100644 --- a/src/math/subpaving/subpaving_mpff.h +++ b/src/math/subpaving/subpaving_mpff.h @@ -39,5 +39,5 @@ struct config_mpff { typedef context_t context_mpff; -}; +} diff --git a/src/math/subpaving/subpaving_mpfx.h b/src/math/subpaving/subpaving_mpfx.h index 9613aa124d..14611c13a5 100644 --- a/src/math/subpaving/subpaving_mpfx.h +++ b/src/math/subpaving/subpaving_mpfx.h @@ -39,5 +39,5 @@ struct config_mpfx { typedef context_t context_mpfx; -}; +} diff --git a/src/math/subpaving/subpaving_mpq.h b/src/math/subpaving/subpaving_mpq.h index 441fbe0663..7468672a82 100644 --- a/src/math/subpaving/subpaving_mpq.h +++ b/src/math/subpaving/subpaving_mpq.h @@ -37,5 +37,5 @@ struct config_mpq { typedef context_t context_mpq; -}; +} diff --git a/src/math/subpaving/subpaving_t.h b/src/math/subpaving/subpaving_t.h index 7300e3da3c..3a6081f409 100644 --- a/src/math/subpaving/subpaving_t.h +++ b/src/math/subpaving/subpaving_t.h @@ -845,5 +845,5 @@ public: void operator()(); }; -}; +} diff --git a/src/math/subpaving/subpaving_t_def.h b/src/math/subpaving/subpaving_t_def.h index b71b10faec..39f4a84f5b 100644 --- a/src/math/subpaving/subpaving_t_def.h +++ b/src/math/subpaving/subpaving_t_def.h @@ -1952,4 +1952,4 @@ bool context_t::check_invariant() const { } -}; +} diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 797ce0774c..067ac712ff 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -1360,4 +1360,4 @@ namespace datalog { } -}; +} diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 1181cf82bb..3a9bdcf340 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -620,5 +620,5 @@ namespace datalog { void display_rel_decl(std::ostream& out, func_decl* f); }; -}; +} diff --git a/src/muz/base/dl_costs.cpp b/src/muz/base/dl_costs.cpp index 70688cd59c..35eaddce98 100644 --- a/src/muz/base/dl_costs.cpp +++ b/src/muz/base/dl_costs.cpp @@ -157,4 +157,4 @@ namespace datalog { } } -}; +} diff --git a/src/muz/base/dl_costs.h b/src/muz/base/dl_costs.h index ea3efcda99..a4c681af48 100644 --- a/src/muz/base/dl_costs.h +++ b/src/muz/base/dl_costs.h @@ -106,6 +106,6 @@ namespace datalog { void start(accounted_object *); void finish() { start(nullptr); } }; -}; +} diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index 0824c84cf5..b23786020c 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -1084,6 +1084,6 @@ namespace datalog { -}; +} diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h index 87c2637a9b..e5126c778f 100644 --- a/src/muz/base/dl_rule.h +++ b/src/muz/base/dl_rule.h @@ -373,7 +373,7 @@ namespace datalog { This possibly returns a ";"-separated list of names. */ - symbol const& name() const { return m_name; } ; + symbol const& name() const { return m_name; } unsigned hash() const; @@ -386,6 +386,6 @@ namespace datalog { unsigned operator()(const rule * r) const; }; -}; +} diff --git a/src/muz/base/dl_rule_set.cpp b/src/muz/base/dl_rule_set.cpp index d621e1b24b..4e0572c978 100644 --- a/src/muz/base/dl_rule_set.cpp +++ b/src/muz/base/dl_rule_set.cpp @@ -709,4 +709,4 @@ namespace datalog { } -}; +} diff --git a/src/muz/base/dl_rule_set.h b/src/muz/base/dl_rule_set.h index 4afacacf06..be694af461 100644 --- a/src/muz/base/dl_rule_set.h +++ b/src/muz/base/dl_rule_set.h @@ -281,5 +281,5 @@ namespace datalog { -}; +} diff --git a/src/muz/base/dl_rule_subsumption_index.cpp b/src/muz/base/dl_rule_subsumption_index.cpp index f3fb545b67..cf41c37f20 100644 --- a/src/muz/base/dl_rule_subsumption_index.cpp +++ b/src/muz/base/dl_rule_subsumption_index.cpp @@ -80,5 +80,5 @@ namespace datalog { return false; } -}; +} diff --git a/src/muz/base/dl_rule_subsumption_index.h b/src/muz/base/dl_rule_subsumption_index.h index 3783be3dc3..5d321fe7aa 100644 --- a/src/muz/base/dl_rule_subsumption_index.h +++ b/src/muz/base/dl_rule_subsumption_index.h @@ -56,6 +56,6 @@ namespace datalog { bool is_subsumed(app * query); }; -}; +} diff --git a/src/muz/base/dl_rule_transformer.cpp b/src/muz/base/dl_rule_transformer.cpp index bcdcc6b5bb..4342e3564a 100644 --- a/src/muz/base/dl_rule_transformer.cpp +++ b/src/muz/base/dl_rule_transformer.cpp @@ -148,4 +148,4 @@ namespace datalog { -}; +} diff --git a/src/muz/base/dl_rule_transformer.h b/src/muz/base/dl_rule_transformer.h index c446593bdd..9ac935357a 100644 --- a/src/muz/base/dl_rule_transformer.h +++ b/src/muz/base/dl_rule_transformer.h @@ -110,6 +110,6 @@ namespace datalog { static void remove_duplicate_tails(app_ref_vector& tail, bool_vector& tail_neg); }; -}; +} diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index 975d4e721b..81740cc86a 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -681,5 +681,5 @@ namespace datalog { stm<; diff --git a/src/muz/bmc/dl_bmc_engine.h b/src/muz/bmc/dl_bmc_engine.h index 05d5707a66..c1631a8319 100644 --- a/src/muz/bmc/dl_bmc_engine.h +++ b/src/muz/bmc/dl_bmc_engine.h @@ -67,7 +67,7 @@ namespace datalog { void compile(rule_set const& rules, expr_ref_vector& fmls, unsigned level); expr_ref compile_query(func_decl* query_pred, unsigned level); }; -}; +} diff --git a/src/muz/clp/clp_context.cpp b/src/muz/clp/clp_context.cpp index ccaf46702b..7683e4dbaa 100644 --- a/src/muz/clp/clp_context.cpp +++ b/src/muz/clp/clp_context.cpp @@ -222,4 +222,4 @@ namespace datalog { return m_imp->get_answer(); } -}; +} diff --git a/src/muz/clp/clp_context.h b/src/muz/clp/clp_context.h index 306baf3bd3..4be64b325a 100644 --- a/src/muz/clp/clp_context.h +++ b/src/muz/clp/clp_context.h @@ -38,5 +38,5 @@ namespace datalog { void display_certificate(std::ostream& out) const override; expr_ref get_answer() override; }; -}; +} diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index e692196f26..300edfe239 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -878,4 +878,4 @@ namespace datalog { expr_ref ddnf::get_answer() { return m_imp->get_answer(); } -}; +} diff --git a/src/muz/ddnf/ddnf.h b/src/muz/ddnf/ddnf.h index 6a93ef2305..e25b7a8d08 100644 --- a/src/muz/ddnf/ddnf.h +++ b/src/muz/ddnf/ddnf.h @@ -65,5 +65,5 @@ namespace datalog { void display(std::ostream& out) const; void display_statistics(std::ostream& out) const; }; -}; +} diff --git a/src/muz/fp/datalog_parser.h b/src/muz/fp/datalog_parser.h index e836cbaec8..fcf1a1327f 100644 --- a/src/muz/fp/datalog_parser.h +++ b/src/muz/fp/datalog_parser.h @@ -42,5 +42,5 @@ namespace datalog { virtual bool parse_directory(char const * path) = 0; }; -}; +} diff --git a/src/muz/rel/check_relation.h b/src/muz/rel/check_relation.h index 773b45813f..310e09fe6f 100644 --- a/src/muz/rel/check_relation.h +++ b/src/muz/rel/check_relation.h @@ -164,6 +164,6 @@ namespace datalog { unsigned_vector const& dst_eq, unsigned_vector const& neg_eq); }; -}; +} diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index 9c14421850..2592d642ca 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -631,12 +631,12 @@ namespace datalog { class identity_mutator_fn : public mutator_fn { public: - void operator()(base_object & t) override {}; + void operator()(base_object & t) override {} }; class identity_intersection_filter_fn : public intersection_filter_fn { public: - void operator()(base_object & t, const base_object & neg) override {}; + void operator()(base_object & t, const base_object & neg) override {} }; class default_permutation_rename_fn : public transformer_fn { @@ -1258,5 +1258,5 @@ namespace datalog { expr_ref_vector & renaming_arg); -}; +} diff --git a/src/muz/rel/dl_bound_relation.cpp b/src/muz/rel/dl_bound_relation.cpp index 2a078d8f7e..417ae0cb90 100644 --- a/src/muz/rel/dl_bound_relation.cpp +++ b/src/muz/rel/dl_bound_relation.cpp @@ -676,6 +676,6 @@ namespace datalog { } -}; +} diff --git a/src/muz/rel/dl_bound_relation.h b/src/muz/rel/dl_bound_relation.h index 8f852f0ba4..f90d643246 100644 --- a/src/muz/rel/dl_bound_relation.h +++ b/src/muz/rel/dl_bound_relation.h @@ -168,6 +168,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/dl_check_table.cpp b/src/muz/rel/dl_check_table.cpp index 0a6d900274..e036fdb117 100644 --- a/src/muz/rel/dl_check_table.cpp +++ b/src/muz/rel/dl_check_table.cpp @@ -435,5 +435,5 @@ namespace datalog { return result; } -}; +} diff --git a/src/muz/rel/dl_check_table.h b/src/muz/rel/dl_check_table.h index 144d0d6fc4..4e49bd4de9 100644 --- a/src/muz/rel/dl_check_table.h +++ b/src/muz/rel/dl_check_table.h @@ -129,5 +129,5 @@ namespace datalog { unsigned get_size_estimate_bytes() const override { return m_tocheck->get_size_estimate_bytes(); } }; - }; + } diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h index 106d1b7919..edb7598d68 100644 --- a/src/muz/rel/dl_compiler.h +++ b/src/muz/rel/dl_compiler.h @@ -279,6 +279,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/dl_external_relation.cpp b/src/muz/rel/dl_external_relation.cpp index a2e42f6402..bfbd22f4a3 100644 --- a/src/muz/rel/dl_external_relation.cpp +++ b/src/muz/rel/dl_external_relation.cpp @@ -449,4 +449,4 @@ namespace datalog { return alloc(negation_filter_fn, *this, t, negated_obj, joined_col_cnt, t_cols, negated_cols); } -}; +} diff --git a/src/muz/rel/dl_external_relation.h b/src/muz/rel/dl_external_relation.h index c8887eeedb..98fd74992e 100644 --- a/src/muz/rel/dl_external_relation.h +++ b/src/muz/rel/dl_external_relation.h @@ -147,5 +147,5 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp index 7f3806b91a..61f76c77d6 100644 --- a/src/muz/rel/dl_finite_product_relation.cpp +++ b/src/muz/rel/dl_finite_product_relation.cpp @@ -2372,4 +2372,4 @@ namespace datalog { bool_rewriter(m).mk_or(disjs.size(), disjs.data(), fml); } -}; +} diff --git a/src/muz/rel/dl_finite_product_relation.h b/src/muz/rel/dl_finite_product_relation.h index 324564469f..f602e37126 100644 --- a/src/muz/rel/dl_finite_product_relation.h +++ b/src/muz/rel/dl_finite_product_relation.h @@ -359,6 +359,6 @@ namespace datalog { void to_formula(expr_ref& fml) const override; }; -}; +} diff --git a/src/muz/rel/dl_instruction.h b/src/muz/rel/dl_instruction.h index a008c2b731..4a1da5a791 100644 --- a/src/muz/rel/dl_instruction.h +++ b/src/muz/rel/dl_instruction.h @@ -364,6 +364,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/dl_interval_relation.cpp b/src/muz/rel/dl_interval_relation.cpp index 81c630ec6a..39ffdbfcb1 100644 --- a/src/muz/rel/dl_interval_relation.cpp +++ b/src/muz/rel/dl_interval_relation.cpp @@ -648,5 +648,5 @@ namespace datalog { return false; } -}; +} diff --git a/src/muz/rel/dl_interval_relation.h b/src/muz/rel/dl_interval_relation.h index 0bddec4cf8..857a3f3dfd 100644 --- a/src/muz/rel/dl_interval_relation.h +++ b/src/muz/rel/dl_interval_relation.h @@ -134,6 +134,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/dl_mk_explanations.cpp b/src/muz/rel/dl_mk_explanations.cpp index 9565a71436..67b67bbef5 100644 --- a/src/muz/rel/dl_mk_explanations.cpp +++ b/src/muz/rel/dl_mk_explanations.cpp @@ -885,5 +885,5 @@ namespace datalog { return res.detach(); } -}; +} diff --git a/src/muz/rel/dl_mk_explanations.h b/src/muz/rel/dl_mk_explanations.h index 33d5cc8eea..ba2bbe082f 100644 --- a/src/muz/rel/dl_mk_explanations.h +++ b/src/muz/rel/dl_mk_explanations.h @@ -79,6 +79,6 @@ namespace datalog { static expr* get_explanation(relation_base const& r); }; -}; +} diff --git a/src/muz/rel/dl_mk_similarity_compressor.cpp b/src/muz/rel/dl_mk_similarity_compressor.cpp index 77d106e0cf..39ebbf4344 100644 --- a/src/muz/rel/dl_mk_similarity_compressor.cpp +++ b/src/muz/rel/dl_mk_similarity_compressor.cpp @@ -543,4 +543,4 @@ namespace datalog { reset(); return result; } -}; +} diff --git a/src/muz/rel/dl_mk_similarity_compressor.h b/src/muz/rel/dl_mk_similarity_compressor.h index 394e1a9e62..73ff15339c 100644 --- a/src/muz/rel/dl_mk_similarity_compressor.h +++ b/src/muz/rel/dl_mk_similarity_compressor.h @@ -71,6 +71,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/rel/dl_mk_simple_joins.cpp b/src/muz/rel/dl_mk_simple_joins.cpp index de10c4f7f0..cf85321226 100644 --- a/src/muz/rel/dl_mk_simple_joins.cpp +++ b/src/muz/rel/dl_mk_simple_joins.cpp @@ -751,5 +751,5 @@ namespace datalog { } -}; +} diff --git a/src/muz/rel/dl_mk_simple_joins.h b/src/muz/rel/dl_mk_simple_joins.h index 6ec66159cd..f4aacdaa9a 100644 --- a/src/muz/rel/dl_mk_simple_joins.h +++ b/src/muz/rel/dl_mk_simple_joins.h @@ -56,6 +56,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/rel/dl_product_relation.cpp b/src/muz/rel/dl_product_relation.cpp index 7dd9056f6d..9884aea060 100644 --- a/src/muz/rel/dl_product_relation.cpp +++ b/src/muz/rel/dl_product_relation.cpp @@ -1128,7 +1128,7 @@ namespace datalog { } } -}; +} diff --git a/src/muz/rel/dl_product_relation.h b/src/muz/rel/dl_product_relation.h index 63c0004898..e8190a8301 100644 --- a/src/muz/rel/dl_product_relation.h +++ b/src/muz/rel/dl_product_relation.h @@ -184,6 +184,6 @@ namespace datalog { } }; -}; +} diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index dda2704626..ed0c37f4ff 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -1689,5 +1689,5 @@ namespace datalog { return res; } -}; +} diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index 58d46347d2..3c480785ae 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -699,6 +699,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/dl_sieve_relation.cpp b/src/muz/rel/dl_sieve_relation.cpp index b1e64bd648..19fc688d01 100644 --- a/src/muz/rel/dl_sieve_relation.cpp +++ b/src/muz/rel/dl_sieve_relation.cpp @@ -662,4 +662,4 @@ namespace datalog { } -}; +} diff --git a/src/muz/rel/dl_sieve_relation.h b/src/muz/rel/dl_sieve_relation.h index 0166bec981..71fc8a15a3 100644 --- a/src/muz/rel/dl_sieve_relation.h +++ b/src/muz/rel/dl_sieve_relation.h @@ -190,6 +190,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/dl_sparse_table.cpp b/src/muz/rel/dl_sparse_table.cpp index b59260863c..8cca81d733 100644 --- a/src/muz/rel/dl_sparse_table.cpp +++ b/src/muz/rel/dl_sparse_table.cpp @@ -1404,5 +1404,5 @@ namespace datalog { } -}; +} diff --git a/src/muz/rel/dl_sparse_table.h b/src/muz/rel/dl_sparse_table.h index c548e3ff06..34f05f4798 100644 --- a/src/muz/rel/dl_sparse_table.h +++ b/src/muz/rel/dl_sparse_table.h @@ -494,5 +494,5 @@ namespace datalog { bool knows_exact_size() const override { return true; } }; - }; + } diff --git a/src/muz/rel/dl_table.cpp b/src/muz/rel/dl_table.cpp index 62670254d3..36344f5697 100644 --- a/src/muz/rel/dl_table.cpp +++ b/src/muz/rel/dl_table.cpp @@ -292,5 +292,5 @@ namespace datalog { table_base::iterator bitvector_table::end() const { return mk_iterator(alloc(bv_iterator, *this, true)); } -}; +} diff --git a/src/muz/rel/dl_table.h b/src/muz/rel/dl_table.h index 96f68f44cb..becb61d964 100644 --- a/src/muz/rel/dl_table.h +++ b/src/muz/rel/dl_table.h @@ -144,6 +144,6 @@ namespace datalog { -}; +} diff --git a/src/muz/rel/dl_table_relation.cpp b/src/muz/rel/dl_table_relation.cpp index 4f51001769..c264872c7d 100644 --- a/src/muz/rel/dl_table_relation.cpp +++ b/src/muz/rel/dl_table_relation.cpp @@ -489,5 +489,5 @@ namespace datalog { } } -}; +} diff --git a/src/muz/rel/dl_table_relation.h b/src/muz/rel/dl_table_relation.h index bb6368d253..9ff0636283 100644 --- a/src/muz/rel/dl_table_relation.h +++ b/src/muz/rel/dl_table_relation.h @@ -126,6 +126,6 @@ namespace datalog { bool knows_exact_size() const override { return m_table->knows_exact_size(); } }; -}; +} diff --git a/src/muz/rel/dl_vector_relation.h b/src/muz/rel/dl_vector_relation.h index f659831fb3..3f1edd28ee 100644 --- a/src/muz/rel/dl_vector_relation.h +++ b/src/muz/rel/dl_vector_relation.h @@ -397,6 +397,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/karr_relation.cpp b/src/muz/rel/karr_relation.cpp index c4b6a65b2d..41bd91e31e 100644 --- a/src/muz/rel/karr_relation.cpp +++ b/src/muz/rel/karr_relation.cpp @@ -789,4 +789,4 @@ namespace datalog { } return nullptr; } -}; +} diff --git a/src/muz/rel/karr_relation.h b/src/muz/rel/karr_relation.h index 33ce1ef984..1aee4595db 100644 --- a/src/muz/rel/karr_relation.h +++ b/src/muz/rel/karr_relation.h @@ -80,6 +80,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 20735cfcc0..4d963b1764 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -630,4 +630,4 @@ namespace datalog { } -}; +} diff --git a/src/muz/rel/rel_context.h b/src/muz/rel/rel_context.h index 8d48d2d37d..62f7566b80 100644 --- a/src/muz/rel/rel_context.h +++ b/src/muz/rel/rel_context.h @@ -125,5 +125,5 @@ namespace datalog { lbool saturate() override; }; -}; +} diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index f7a47f0e0e..5c133596be 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -147,6 +147,6 @@ namespace datalog { void disable_fast_pass() { m_disable_fast_pass = true; } }; -}; +} diff --git a/src/muz/spacer/spacer_concretize.cpp b/src/muz/spacer/spacer_concretize.cpp index 9700af1497..d73b3f638e 100644 --- a/src/muz/spacer/spacer_concretize.cpp +++ b/src/muz/spacer/spacer_concretize.cpp @@ -36,7 +36,7 @@ struct proc { } } }; -}; // namespace pattern_var_marker_ns +} // namespace pattern_var_marker_ns namespace spacer { void pob_concretizer::mark_pattern_vars() { pattern_var_marker_ns::proc proc(m_arith, m_var_marks); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 2691421463..0440a0d1e9 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -38,7 +38,7 @@ Notes: namespace datalog { class rule_set; class context; -}; // namespace datalog +} // namespace datalog namespace spacer { diff --git a/src/muz/spacer/spacer_convex_closure.h b/src/muz/spacer/spacer_convex_closure.h index c3676ddf51..da794c4a2d 100644 --- a/src/muz/spacer/spacer_convex_closure.h +++ b/src/muz/spacer/spacer_convex_closure.h @@ -155,7 +155,7 @@ class convex_closure { void add_row(const vector &point) { SASSERT(point.size() == dims()); m_data.add_row(point); - }; + } bool operator()() { return this->compute(); } bool compute(); diff --git a/src/muz/spacer/spacer_farkas_learner.cpp b/src/muz/spacer/spacer_farkas_learner.cpp index 0fa1b74c63..3016b69fe9 100644 --- a/src/muz/spacer/spacer_farkas_learner.cpp +++ b/src/muz/spacer/spacer_farkas_learner.cpp @@ -99,7 +99,7 @@ bool farkas_learner::is_pure_expr(func_decl_set const& symbs, expr* e, ast_manag return false; } return true; -}; +} /** diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index 0fa8ae932b..4653d62b91 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -327,4 +327,4 @@ void lemma_eq_generalizer::operator() (lemma_ref &lemma) { } -}; +} diff --git a/src/muz/spacer/spacer_mbc.cpp b/src/muz/spacer/spacer_mbc.cpp index 78c2799ec6..ee4eb0228f 100644 --- a/src/muz/spacer/spacer_mbc.cpp +++ b/src/muz/spacer/spacer_mbc.cpp @@ -66,7 +66,7 @@ public: } - void reset() {reset_partition();}; + void reset() {reset_partition();} void reset_partition() {m_current_part = UINT_MAX;} unsigned partition() {return m_current_part;} bool found_partition() {return m_current_part < UINT_MAX;} diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 383fda4183..eb4d780c98 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -845,4 +845,4 @@ namespace spacer { return res; } -}; +} diff --git a/src/muz/spacer/spacer_qe_project.h b/src/muz/spacer/spacer_qe_project.h index 37d0985406..b48b3aa321 100644 --- a/src/muz/spacer/spacer_qe_project.h +++ b/src/muz/spacer/spacer_qe_project.h @@ -43,5 +43,5 @@ namespace spacer_qe { void array_project_selects (model& model, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars); void array_project (model& model, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars, bool reduce_all_selects = false); -}; +} diff --git a/src/muz/spacer/spacer_sym_mux.h b/src/muz/spacer/spacer_sym_mux.h index 4ddbeb3e44..549a25b21b 100644 --- a/src/muz/spacer/spacer_sym_mux.h +++ b/src/muz/spacer/spacer_sym_mux.h @@ -35,7 +35,7 @@ private: public: func_decl_ref m_main; func_decl_ref_vector m_variants; - sym_mux_entry(ast_manager &m) : m_main(m), m_variants(m) {}; + sym_mux_entry(ast_manager &m) : m_main(m), m_variants(m) {} }; typedef obj_map decl2entry_map; diff --git a/src/muz/spacer/spacer_unsat_core_learner.h b/src/muz/spacer/spacer_unsat_core_learner.h index 27915b6c9a..fadfe04cfd 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.h +++ b/src/muz/spacer/spacer_unsat_core_learner.h @@ -41,7 +41,7 @@ namespace spacer { public: unsat_core_learner(ast_manager& m, iuc_proof& pr) : - m(m), m_pr(pr), m_unsat_core(m) {}; + m(m), m_pr(pr), m_unsat_core(m) {} virtual ~unsat_core_learner(); ast_manager& get_manager() {return m;} diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index 40060629d0..36500eb770 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -35,7 +35,7 @@ Revision History: namespace spacer { unsat_core_plugin::unsat_core_plugin(unsat_core_learner& ctx): - m(ctx.get_manager()), m_ctx(ctx) {}; + m(ctx.get_manager()), m_ctx(ctx) {} void unsat_core_plugin_lemma::compute_partial_core(proof* step) { SASSERT(m_ctx.is_a(step)); diff --git a/src/muz/spacer/spacer_unsat_core_plugin.h b/src/muz/spacer/spacer_unsat_core_plugin.h index b844cdd469..c327a1fdba 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.h +++ b/src/muz/spacer/spacer_unsat_core_plugin.h @@ -40,7 +40,7 @@ namespace spacer { class unsat_core_plugin_lemma : public unsat_core_plugin { public: - unsat_core_plugin_lemma(unsat_core_learner& learner) : unsat_core_plugin(learner){}; + unsat_core_plugin_lemma(unsat_core_learner& learner) : unsat_core_plugin(learner){} void compute_partial_core(proof* step) override; private: void add_lowest_split_to_core(proof* step) const; @@ -53,7 +53,7 @@ namespace spacer { bool use_constant_from_a=true) : unsat_core_plugin(learner), m_split_literals(split_literals), - m_use_constant_from_a(use_constant_from_a) {}; + m_use_constant_from_a(use_constant_from_a) {} void compute_partial_core(proof* step) override; private: bool m_split_literals; @@ -66,7 +66,7 @@ namespace spacer { class unsat_core_plugin_farkas_lemma_optimized : public unsat_core_plugin { public: - unsat_core_plugin_farkas_lemma_optimized(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin(learner) {}; + unsat_core_plugin_farkas_lemma_optimized(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin(learner) {} void compute_partial_core(proof* step) override; void finalize() override; protected: @@ -79,7 +79,7 @@ namespace spacer { class unsat_core_plugin_farkas_lemma_bounded : public unsat_core_plugin_farkas_lemma_optimized { public: - unsat_core_plugin_farkas_lemma_bounded(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin_farkas_lemma_optimized(learner, m) {}; + unsat_core_plugin_farkas_lemma_bounded(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin_farkas_lemma_optimized(learner, m) {} void finalize() override; }; diff --git a/src/muz/tab/tab_context.cpp b/src/muz/tab/tab_context.cpp index a775a7033d..d92d7614ca 100644 --- a/src/muz/tab/tab_context.cpp +++ b/src/muz/tab/tab_context.cpp @@ -1306,7 +1306,7 @@ namespace tb { } return out << "unmatched instruction"; } -}; +} namespace datalog { @@ -1655,4 +1655,4 @@ namespace datalog { return m_imp->get_answer(); } -}; +} diff --git a/src/muz/tab/tab_context.h b/src/muz/tab/tab_context.h index d5bda040e2..4db6426230 100644 --- a/src/muz/tab/tab_context.h +++ b/src/muz/tab/tab_context.h @@ -39,5 +39,5 @@ namespace datalog { void display_certificate(std::ostream& out) const override; expr_ref get_answer() override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_array_blast.cpp b/src/muz/transforms/dl_mk_array_blast.cpp index f0efe2f3ac..5e163f087d 100644 --- a/src/muz/transforms/dl_mk_array_blast.cpp +++ b/src/muz/transforms/dl_mk_array_blast.cpp @@ -333,6 +333,6 @@ namespace datalog { return rules.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_array_blast.h b/src/muz/transforms/dl_mk_array_blast.h index 12102af73e..04254275b0 100644 --- a/src/muz/transforms/dl_mk_array_blast.h +++ b/src/muz/transforms/dl_mk_array_blast.h @@ -69,6 +69,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/transforms/dl_mk_array_eq_rewrite.h b/src/muz/transforms/dl_mk_array_eq_rewrite.h index eabef4792f..62a9a4e0da 100644 --- a/src/muz/transforms/dl_mk_array_eq_rewrite.h +++ b/src/muz/transforms/dl_mk_array_eq_rewrite.h @@ -44,5 +44,5 @@ namespace datalog { -}; +} diff --git a/src/muz/transforms/dl_mk_array_instantiation.h b/src/muz/transforms/dl_mk_array_instantiation.h index 71924288f9..4b8d8395b9 100644 --- a/src/muz/transforms/dl_mk_array_instantiation.h +++ b/src/muz/transforms/dl_mk_array_instantiation.h @@ -116,5 +116,5 @@ namespace datalog { -}; +} diff --git a/src/muz/transforms/dl_mk_backwards.cpp b/src/muz/transforms/dl_mk_backwards.cpp index a47d0aeebb..b848167026 100644 --- a/src/muz/transforms/dl_mk_backwards.cpp +++ b/src/muz/transforms/dl_mk_backwards.cpp @@ -73,4 +73,4 @@ namespace datalog { return result.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_backwards.h b/src/muz/transforms/dl_mk_backwards.h index 4d1522e021..76aab80af3 100644 --- a/src/muz/transforms/dl_mk_backwards.h +++ b/src/muz/transforms/dl_mk_backwards.h @@ -30,6 +30,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index 9ca982776d..d6f07915db 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -334,4 +334,4 @@ namespace datalog { return (*m_impl)(source); } -}; +} diff --git a/src/muz/transforms/dl_mk_bit_blast.h b/src/muz/transforms/dl_mk_bit_blast.h index 3681ecf380..0f7da47680 100644 --- a/src/muz/transforms/dl_mk_bit_blast.h +++ b/src/muz/transforms/dl_mk_bit_blast.h @@ -31,6 +31,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_coalesce.cpp b/src/muz/transforms/dl_mk_coalesce.cpp index 97c4bb3aff..c7e3a1aede 100644 --- a/src/muz/transforms/dl_mk_coalesce.cpp +++ b/src/muz/transforms/dl_mk_coalesce.cpp @@ -194,6 +194,6 @@ namespace datalog { return rules.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_coalesce.h b/src/muz/transforms/dl_mk_coalesce.h index f94ce3465a..07962a006a 100644 --- a/src/muz/transforms/dl_mk_coalesce.h +++ b/src/muz/transforms/dl_mk_coalesce.h @@ -54,6 +54,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_filter_rules.cpp b/src/muz/transforms/dl_mk_filter_rules.cpp index d403f8b953..32b3f63ba5 100644 --- a/src/muz/transforms/dl_mk_filter_rules.cpp +++ b/src/muz/transforms/dl_mk_filter_rules.cpp @@ -166,4 +166,4 @@ namespace datalog { return m_result; } -}; +} diff --git a/src/muz/transforms/dl_mk_filter_rules.h b/src/muz/transforms/dl_mk_filter_rules.h index 3939c542ba..605fde256f 100644 --- a/src/muz/transforms/dl_mk_filter_rules.h +++ b/src/muz/transforms/dl_mk_filter_rules.h @@ -79,7 +79,7 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp b/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp index 1afb61febc..9d696b7729 100644 --- a/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp @@ -615,4 +615,4 @@ namespace datalog { return res.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_interp_tail_simplifier.h b/src/muz/transforms/dl_mk_interp_tail_simplifier.h index f1757dbce7..4658399380 100644 --- a/src/muz/transforms/dl_mk_interp_tail_simplifier.h +++ b/src/muz/transforms/dl_mk_interp_tail_simplifier.h @@ -102,6 +102,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_karr_invariants.cpp b/src/muz/transforms/dl_mk_karr_invariants.cpp index 71370a0b50..669ea1f2cf 100644 --- a/src/muz/transforms/dl_mk_karr_invariants.cpp +++ b/src/muz/transforms/dl_mk_karr_invariants.cpp @@ -308,5 +308,5 @@ namespace datalog { -}; +} diff --git a/src/muz/transforms/dl_mk_karr_invariants.h b/src/muz/transforms/dl_mk_karr_invariants.h index 9ba579a603..e33ff851cc 100644 --- a/src/muz/transforms/dl_mk_karr_invariants.h +++ b/src/muz/transforms/dl_mk_karr_invariants.h @@ -68,6 +68,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/transforms/dl_mk_loop_counter.cpp b/src/muz/transforms/dl_mk_loop_counter.cpp index a20224eb29..245ad0b2d2 100644 --- a/src/muz/transforms/dl_mk_loop_counter.cpp +++ b/src/muz/transforms/dl_mk_loop_counter.cpp @@ -153,4 +153,4 @@ namespace datalog { return result; } -}; +} diff --git a/src/muz/transforms/dl_mk_loop_counter.h b/src/muz/transforms/dl_mk_loop_counter.h index b2758df67a..d74a73ffe3 100644 --- a/src/muz/transforms/dl_mk_loop_counter.h +++ b/src/muz/transforms/dl_mk_loop_counter.h @@ -43,6 +43,6 @@ namespace datalog { rule_set * revert(rule_set const& source); }; -}; +} diff --git a/src/muz/transforms/dl_mk_magic_sets.cpp b/src/muz/transforms/dl_mk_magic_sets.cpp index 395aa0d693..f8f34827fd 100644 --- a/src/muz/transforms/dl_mk_magic_sets.cpp +++ b/src/muz/transforms/dl_mk_magic_sets.cpp @@ -375,5 +375,5 @@ namespace datalog { result->add_rule(back_to_goal_rule); return result.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_magic_sets.h b/src/muz/transforms/dl_mk_magic_sets.h index 3a8a92580d..4e40e057c1 100644 --- a/src/muz/transforms/dl_mk_magic_sets.h +++ b/src/muz/transforms/dl_mk_magic_sets.h @@ -128,6 +128,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_magic_symbolic.cpp b/src/muz/transforms/dl_mk_magic_symbolic.cpp index ed05d2247e..054abf5e7c 100644 --- a/src/muz/transforms/dl_mk_magic_symbolic.cpp +++ b/src/muz/transforms/dl_mk_magic_symbolic.cpp @@ -130,4 +130,4 @@ namespace datalog { return app_ref(m.mk_app(g, q->get_num_args(), q->get_args()), m); } -}; +} diff --git a/src/muz/transforms/dl_mk_magic_symbolic.h b/src/muz/transforms/dl_mk_magic_symbolic.h index ac29194bcc..1003b2e318 100644 --- a/src/muz/transforms/dl_mk_magic_symbolic.h +++ b/src/muz/transforms/dl_mk_magic_symbolic.h @@ -32,6 +32,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp index b2ec2fb297..a12b230bc3 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp @@ -361,4 +361,4 @@ namespace datalog { } -}; +} diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.h b/src/muz/transforms/dl_mk_quantifier_abstraction.h index 33c70c08b2..40669b02a3 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.h +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.h @@ -55,6 +55,6 @@ namespace datalog { -}; +} diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index 9e567c902b..bc1af9c585 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -289,6 +289,6 @@ namespace datalog { } -}; +} diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.h b/src/muz/transforms/dl_mk_quantifier_instantiation.h index 716de11f02..c27058e30f 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.h +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.h @@ -65,6 +65,6 @@ namespace datalog { -}; +} diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index 340b0ac569..94c174c1db 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -878,4 +878,4 @@ namespace datalog { return res.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_rule_inliner.h b/src/muz/transforms/dl_mk_rule_inliner.h index c0693fde06..adab914e08 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.h +++ b/src/muz/transforms/dl_mk_rule_inliner.h @@ -199,6 +199,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_scale.cpp b/src/muz/transforms/dl_mk_scale.cpp index b6178bb817..a20b1cbdc2 100644 --- a/src/muz/transforms/dl_mk_scale.cpp +++ b/src/muz/transforms/dl_mk_scale.cpp @@ -235,4 +235,4 @@ namespace datalog { return result; } -}; +} diff --git a/src/muz/transforms/dl_mk_scale.h b/src/muz/transforms/dl_mk_scale.h index fcbf4c2265..39ab3cdce2 100644 --- a/src/muz/transforms/dl_mk_scale.h +++ b/src/muz/transforms/dl_mk_scale.h @@ -45,6 +45,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_slice.cpp b/src/muz/transforms/dl_mk_slice.cpp index ecdf3ab23a..6cfb1e8add 100644 --- a/src/muz/transforms/dl_mk_slice.cpp +++ b/src/muz/transforms/dl_mk_slice.cpp @@ -854,5 +854,5 @@ namespace datalog { return result.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_slice.h b/src/muz/transforms/dl_mk_slice.h index 807c6dac4e..e619bc90b7 100644 --- a/src/muz/transforms/dl_mk_slice.h +++ b/src/muz/transforms/dl_mk_slice.h @@ -106,6 +106,6 @@ namespace datalog { obj_map const& get_predicates() { return m_predicates; } }; -}; +} diff --git a/src/muz/transforms/dl_mk_subsumption_checker.cpp b/src/muz/transforms/dl_mk_subsumption_checker.cpp index c71fddf9ee..c0e499d06e 100644 --- a/src/muz/transforms/dl_mk_subsumption_checker.cpp +++ b/src/muz/transforms/dl_mk_subsumption_checker.cpp @@ -357,4 +357,4 @@ namespace datalog { return res.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_subsumption_checker.h b/src/muz/transforms/dl_mk_subsumption_checker.h index 87c5c8f2e5..e2b21da694 100644 --- a/src/muz/transforms/dl_mk_subsumption_checker.h +++ b/src/muz/transforms/dl_mk_subsumption_checker.h @@ -86,6 +86,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_synchronize.cpp b/src/muz/transforms/dl_mk_synchronize.cpp index 81c01d7fcc..261768bf7a 100644 --- a/src/muz/transforms/dl_mk_synchronize.cpp +++ b/src/muz/transforms/dl_mk_synchronize.cpp @@ -373,4 +373,4 @@ namespace datalog { return rules; } -}; +} diff --git a/src/muz/transforms/dl_mk_synchronize.h b/src/muz/transforms/dl_mk_synchronize.h index 3f3657cae7..c81a3c9c6d 100644 --- a/src/muz/transforms/dl_mk_synchronize.h +++ b/src/muz/transforms/dl_mk_synchronize.h @@ -128,5 +128,5 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_unbound_compressor.cpp b/src/muz/transforms/dl_mk_unbound_compressor.cpp index 15b619ff85..161af7cea9 100644 --- a/src/muz/transforms/dl_mk_unbound_compressor.cpp +++ b/src/muz/transforms/dl_mk_unbound_compressor.cpp @@ -400,4 +400,4 @@ namespace datalog { } -}; +} diff --git a/src/muz/transforms/dl_mk_unbound_compressor.h b/src/muz/transforms/dl_mk_unbound_compressor.h index 63463dc5ce..9102837bf4 100644 --- a/src/muz/transforms/dl_mk_unbound_compressor.h +++ b/src/muz/transforms/dl_mk_unbound_compressor.h @@ -88,6 +88,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_unfold.cpp b/src/muz/transforms/dl_mk_unfold.cpp index 6a1ae1535e..2d71aafcef 100644 --- a/src/muz/transforms/dl_mk_unfold.cpp +++ b/src/muz/transforms/dl_mk_unfold.cpp @@ -59,5 +59,5 @@ namespace datalog { return rules.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_unfold.h b/src/muz/transforms/dl_mk_unfold.h index abba64c897..6687e7fadf 100644 --- a/src/muz/transforms/dl_mk_unfold.h +++ b/src/muz/transforms/dl_mk_unfold.h @@ -46,6 +46,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/nlsat/nlsat_assignment.h b/src/nlsat/nlsat_assignment.h index d96c8099e9..73d565142e 100644 --- a/src/nlsat/nlsat_assignment.h +++ b/src/nlsat/nlsat_assignment.h @@ -97,5 +97,5 @@ namespace nlsat { bool contains(var x) const override { return x != m_y && m_assignment.is_assigned(x); } anum const & operator()(var x) const override { return m_assignment.value(x); } }; -}; +} diff --git a/src/nlsat/nlsat_clause.cpp b/src/nlsat/nlsat_clause.cpp index 9543c44978..270617d057 100644 --- a/src/nlsat/nlsat_clause.cpp +++ b/src/nlsat/nlsat_clause.cpp @@ -49,4 +49,4 @@ namespace nlsat { return false; } -}; +} diff --git a/src/nlsat/nlsat_clause.h b/src/nlsat/nlsat_clause.h index 91467303cd..52afece639 100644 --- a/src/nlsat/nlsat_clause.h +++ b/src/nlsat/nlsat_clause.h @@ -66,5 +66,5 @@ namespace nlsat { typedef ptr_vector clause_vector; -}; +} diff --git a/src/nlsat/nlsat_evaluator.cpp b/src/nlsat/nlsat_evaluator.cpp index 6520754163..9f97332bb7 100644 --- a/src/nlsat/nlsat_evaluator.cpp +++ b/src/nlsat/nlsat_evaluator.cpp @@ -699,4 +699,4 @@ namespace nlsat { void evaluator::pop(unsigned num_scopes) { // do nothing } -}; +} diff --git a/src/nlsat/nlsat_evaluator.h b/src/nlsat/nlsat_evaluator.h index d2db3f41a6..2ea5bdc4db 100644 --- a/src/nlsat/nlsat_evaluator.h +++ b/src/nlsat/nlsat_evaluator.h @@ -57,5 +57,5 @@ namespace nlsat { void pop(unsigned num_scopes); }; -}; +} diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index d9a0bf131b..0827af809e 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -1784,7 +1784,7 @@ namespace nlsat { m_imp->test_root_literal(k, y, i, p, result); } -}; +} #ifdef Z3DEBUG #include void pp(nlsat::explain::imp & ex, unsigned num, nlsat::literal const * ls) { diff --git a/src/nlsat/nlsat_explain.h b/src/nlsat/nlsat_explain.h index 60a7c53e18..44279e8bba 100644 --- a/src/nlsat/nlsat_explain.h +++ b/src/nlsat/nlsat_explain.h @@ -108,4 +108,4 @@ namespace nlsat { void test_root_literal(atom::kind k, var y, unsigned i, poly* p, scoped_literal_vector & result); }; -}; +} diff --git a/src/nlsat/nlsat_interval_set.cpp b/src/nlsat/nlsat_interval_set.cpp index 160c8afb66..580aae781a 100644 --- a/src/nlsat/nlsat_interval_set.cpp +++ b/src/nlsat/nlsat_interval_set.cpp @@ -794,4 +794,4 @@ namespace nlsat { out << "*"; return out; } -}; +} diff --git a/src/nlsat/nlsat_interval_set.h b/src/nlsat/nlsat_interval_set.h index 263ab8a103..4efd0c3678 100644 --- a/src/nlsat/nlsat_interval_set.h +++ b/src/nlsat/nlsat_interval_set.h @@ -118,5 +118,5 @@ namespace nlsat { return out; } -}; +} diff --git a/src/nlsat/nlsat_justification.h b/src/nlsat/nlsat_justification.h index d9567ebf93..55501a8aff 100644 --- a/src/nlsat/nlsat_justification.h +++ b/src/nlsat/nlsat_justification.h @@ -106,5 +106,5 @@ namespace nlsat { a.deallocate(obj_sz, ptr); } } -}; +} diff --git a/src/nlsat/nlsat_scoped_literal_vector.h b/src/nlsat/nlsat_scoped_literal_vector.h index d67805c156..ee3a4acd9c 100644 --- a/src/nlsat/nlsat_scoped_literal_vector.h +++ b/src/nlsat/nlsat_scoped_literal_vector.h @@ -107,5 +107,5 @@ namespace nlsat { operator literal const &() const { return m_lit; } void neg() { m_lit.neg(); } }; -}; +} diff --git a/src/nlsat/nlsat_simplify.cpp b/src/nlsat/nlsat_simplify.cpp index e1c10d5f51..08e5c3d58b 100644 --- a/src/nlsat/nlsat_simplify.cpp +++ b/src/nlsat/nlsat_simplify.cpp @@ -826,4 +826,4 @@ namespace nlsat { (*m_imp)(); } -}; +} diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 6a656b46d4..074b159484 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -4784,4 +4784,4 @@ namespace nlsat { unsigned solver::lws_spt_threshold() const { return m_imp->m_lws_spt_threshold; } bool solver::lws_witness_subs_lc() const { return m_imp->m_lws_witness_subs_lc; } bool solver::lws_witness_subs_disc() const { return m_imp->m_lws_witness_subs_disc; } -}; +} diff --git a/src/nlsat/nlsat_solver.h b/src/nlsat/nlsat_solver.h index b6e0034733..21d9e42538 100644 --- a/src/nlsat/nlsat_solver.h +++ b/src/nlsat/nlsat_solver.h @@ -316,4 +316,4 @@ namespace nlsat { }; -}; +} diff --git a/src/nlsat/nlsat_types.cpp b/src/nlsat/nlsat_types.cpp index 42c41cec14..f2fe6f4287 100644 --- a/src/nlsat/nlsat_types.cpp +++ b/src/nlsat/nlsat_types.cpp @@ -67,4 +67,4 @@ namespace nlsat { return a1->m_kind == a2->m_kind && a1->m_x == a2->m_x && a1->m_i == a2->m_i && a1->m_p == a2->m_p; } -}; +} diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index be8f625c92..ee3b2935bf 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -26,7 +26,7 @@ Revision History: namespace algebraic_numbers { class anum; class manager; -}; +} namespace nlsat { #define NLSAT_VB_LVL 10 @@ -204,5 +204,5 @@ namespace nlsat { if (s == 0) return 0; return 1; } -}; +} diff --git a/src/opt/maxcore.h b/src/opt/maxcore.h index 283fee8506..f16904a21b 100644 --- a/src/opt/maxcore.h +++ b/src/opt/maxcore.h @@ -33,5 +33,5 @@ namespace opt { maxsmt_solver_base* mk_primal_dual_maxres(maxsat_context& c, unsigned id, vector& soft); -}; +} diff --git a/src/opt/maxlex.h b/src/opt/maxlex.h index fc30b1fd88..4cfa35fe49 100644 --- a/src/opt/maxlex.h +++ b/src/opt/maxlex.h @@ -26,5 +26,5 @@ namespace opt { maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, vector& soft); -}; +} diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index d1d1506714..665b739783 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -380,12 +380,12 @@ namespace opt { params_ref& params() override { return m_params; } void enable_sls(bool force) override { } // no op symbol const& maxsat_engine() const override { return m_maxsat_engine; } - void get_base_model(model_ref& _m) override { _m = m_model; }; + void get_base_model(model_ref& _m) override { _m = m_model; } smt::context& smt_context() override { throw default_exception("stand-alone maxsat context does not support wmax"); } unsigned num_objectives() override { return 1; } - bool verify_model(unsigned id, model* mdl, rational const& v) override { return true; }; + bool verify_model(unsigned id, model* mdl, rational const& v) override { return true; } void set_model(model_ref& _m) override { m_model = _m; } void model_updated(model* mdl) override { } // no-op rational adjust(unsigned id, rational const& r) override { @@ -419,4 +419,4 @@ namespace opt { } return r; } -}; +} diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 7e75cde450..ca73437d5d 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -211,5 +211,5 @@ namespace opt { model_ref get_model() { return m_model; } }; -}; +} diff --git a/src/opt/opt_cores.cpp b/src/opt/opt_cores.cpp index 049a64da23..7948cdd502 100644 --- a/src/opt/opt_cores.cpp +++ b/src/opt/opt_cores.cpp @@ -394,4 +394,4 @@ namespace opt { } } -}; +} diff --git a/src/opt/opt_cores.h b/src/opt/opt_cores.h index 6dda34fd78..7ba4166913 100644 --- a/src/opt/opt_cores.h +++ b/src/opt/opt_cores.h @@ -68,4 +68,4 @@ namespace opt { void updt_params(params_ref& p); }; -}; +} diff --git a/src/opt/opt_lns.cpp b/src/opt/opt_lns.cpp index 019a60b532..5133ac8c6c 100644 --- a/src/opt/opt_lns.cpp +++ b/src/opt/opt_lns.cpp @@ -269,4 +269,4 @@ namespace opt { return r; } -}; +} diff --git a/src/opt/opt_lns.h b/src/opt/opt_lns.h index 1bc27f9b13..4dc24d05c6 100644 --- a/src/opt/opt_lns.h +++ b/src/opt/opt_lns.h @@ -77,4 +77,4 @@ namespace opt { void set_conflicts(unsigned c) { m_max_conflicts = c; } unsigned climb(model_ref& mdl); }; -}; +} diff --git a/src/opt/opt_preprocess.cpp b/src/opt/opt_preprocess.cpp index 2e1b780707..3a4a712eb0 100644 --- a/src/opt/opt_preprocess.cpp +++ b/src/opt/opt_preprocess.cpp @@ -238,4 +238,4 @@ namespace opt { return false; return true; } -}; +} diff --git a/src/opt/opt_preprocess.h b/src/opt/opt_preprocess.h index 71e06eb2c6..21c9efde9c 100644 --- a/src/opt/opt_preprocess.h +++ b/src/opt/opt_preprocess.h @@ -40,4 +40,4 @@ namespace opt { preprocess(solver& s); bool operator()(vector& soft, rational& lower); }; -}; +} diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index b1198a7f90..385392a1dc 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -93,5 +93,5 @@ namespace opt { }; -}; +} diff --git a/src/opt/pb_sls.h b/src/opt/pb_sls.h index 6537574698..b511a45efa 100644 --- a/src/opt/pb_sls.h +++ b/src/opt/pb_sls.h @@ -44,5 +44,5 @@ namespace smt { }; -}; +} diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index f7bfe6ed53..15f1721b16 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -3333,7 +3333,7 @@ namespace smt2 { }; void free_parser(parser * p) { dealloc(p); } -}; +} bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & ps, char const * filename) { smt2::parser p(ctx, is, interactive, ps, filename); diff --git a/src/parsers/smt2/smt2scanner.cpp b/src/parsers/smt2/smt2scanner.cpp index 3ab95ab40c..d6edcd0fb0 100644 --- a/src/parsers/smt2/smt2scanner.cpp +++ b/src/parsers/smt2/smt2scanner.cpp @@ -403,5 +403,5 @@ namespace smt2 { m_bend = 0; next(); } -}; +} diff --git a/src/parsers/smt2/smt2scanner.h b/src/parsers/smt2/smt2scanner.h index dd1aa04c06..fa37870ae3 100644 --- a/src/parsers/smt2/smt2scanner.h +++ b/src/parsers/smt2/smt2scanner.h @@ -104,6 +104,6 @@ namespace smt2 { char const * cached_str(unsigned begin, unsigned end); }; -}; +} diff --git a/src/qe/mbp/mbp_arith.h b/src/qe/mbp/mbp_arith.h index 1323032eba..936b08dbd1 100644 --- a/src/qe/mbp/mbp_arith.h +++ b/src/qe/mbp/mbp_arith.h @@ -51,5 +51,5 @@ namespace mbp { bool arith_project(model& model, app* var, expr_ref_vector& lits); -}; +} diff --git a/src/qe/mbp/mbp_arrays.cpp b/src/qe/mbp/mbp_arrays.cpp index 2c3e6ddf3b..d6daef7b9f 100644 --- a/src/qe/mbp/mbp_arrays.cpp +++ b/src/qe/mbp/mbp_arrays.cpp @@ -1500,4 +1500,4 @@ namespace mbp { } -}; +} diff --git a/src/qe/mbp/mbp_arrays.h b/src/qe/mbp/mbp_arrays.h index ed06ba78b3..1dced44c8c 100644 --- a/src/qe/mbp/mbp_arrays.h +++ b/src/qe/mbp/mbp_arrays.h @@ -40,5 +40,5 @@ namespace mbp { }; -}; +} diff --git a/src/qe/mbp/mbp_datatypes.h b/src/qe/mbp/mbp_datatypes.h index 28f93089d5..8f667e7b36 100644 --- a/src/qe/mbp/mbp_datatypes.h +++ b/src/qe/mbp/mbp_datatypes.h @@ -39,5 +39,5 @@ namespace mbp { }; -}; +} diff --git a/src/qe/mbp/mbp_euf.h b/src/qe/mbp/mbp_euf.h index 59515e9bd9..1be5cd3387 100644 --- a/src/qe/mbp/mbp_euf.h +++ b/src/qe/mbp/mbp_euf.h @@ -31,5 +31,5 @@ namespace mbp { }; -}; +} diff --git a/src/qe/mbp/mbp_plugin.h b/src/qe/mbp/mbp_plugin.h index 5e7dae8c78..67cf396287 100644 --- a/src/qe/mbp/mbp_plugin.h +++ b/src/qe/mbp/mbp_plugin.h @@ -69,7 +69,7 @@ namespace mbp { virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return false; } virtual family_id get_family_id() { return null_family_id; } - virtual bool project(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return false; }; + virtual bool project(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return false; } /** \brief project vars modulo model, return set of definitions for eliminated variables. diff --git a/src/qe/mbp/mbp_tg_plugins.h b/src/qe/mbp/mbp_tg_plugins.h index 3850f11ca1..671f3701ce 100644 --- a/src/qe/mbp/mbp_tg_plugins.h +++ b/src/qe/mbp/mbp_tg_plugins.h @@ -26,9 +26,9 @@ class mbp_tg_plugin { public: // iterate through all terms in m_tg and apply all theory MBP rules once // returns true if any rules were applied - virtual bool apply() { return false; }; + virtual bool apply() { return false; } virtual ~mbp_tg_plugin() = default; - virtual void use_model() { }; - virtual void get_new_vars(app_ref_vector*&) { }; - virtual family_id get_family_id() const { return null_family_id; }; + virtual void use_model() { } + virtual void get_new_vars(app_ref_vector*&) { } + virtual family_id get_family_id() const { return null_family_id; } }; diff --git a/src/qe/nlarith_util.cpp b/src/qe/nlarith_util.cpp index 7e68f33fbe..eda48e607f 100644 --- a/src/qe/nlarith_util.cpp +++ b/src/qe/nlarith_util.cpp @@ -2022,6 +2022,6 @@ namespace nlarith { void util::get_sign_branches(literal_set& lits, eval& ev, ptr_vector& branches) { m_imp->get_sign_branches(lits, ev, branches); } -}; +} diff --git a/src/qe/nlarith_util.h b/src/qe/nlarith_util.h index dccc4f606f..8f2137a155 100644 --- a/src/qe/nlarith_util.h +++ b/src/qe/nlarith_util.h @@ -143,5 +143,5 @@ namespace nlarith { }; -}; +} diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index 263dad43cb..8e168e62fd 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -955,7 +955,7 @@ namespace qe { return alloc(nlqsat, m, m_mode, m_params); } }; -}; +} tactic * mk_nlqsat_tactic(ast_manager & m, params_ref const& p) { return alloc(qe::nlqsat, m, qe::qsat_t, p); diff --git a/src/qe/qe.h b/src/qe/qe.h index 2fd36596d9..6f07b157bf 100644 --- a/src/qe/qe.h +++ b/src/qe/qe.h @@ -367,6 +367,6 @@ namespace qe { }; -}; +} diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index ba8f5faa3b..aab03e9039 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -613,4 +613,4 @@ namespace qe { return pogo(pA, pB, itp); } -}; +} diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index 93f7df88d4..18c33cb51a 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -156,4 +156,4 @@ namespace qe { lbool pogo(solver_factory& sf, expr* a, expr* b, expr_ref& itp); }; -}; +} diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 86234962c0..d5ca03096c 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -1503,7 +1503,7 @@ namespace qe { void qmax::collect_statistics(statistics& st) const { m_imp->m_qsat.collect_statistics(st); } -}; +} tactic * mk_qsat_tactic(ast_manager& m, params_ref const& p) { return alloc(qe::qsat, m, p, qe::qsat_sat); diff --git a/src/sat/dimacs.h b/src/sat/dimacs.h index f6be01ef82..9f43048272 100644 --- a/src/sat/dimacs.h +++ b/src/sat/dimacs.h @@ -97,10 +97,10 @@ namespace dimacs { bool operator!=(iterator const& other) const { return m_eof != other.m_eof; } }; - iterator begin() { return iterator(*this, false); }; + iterator begin() { return iterator(*this, false); } iterator end() { return iterator(*this, true); } void set_read_theory(std::function& r) { m_read_theory_id = r; } }; -}; +} diff --git a/src/sat/sat_anf_simplifier.h b/src/sat/sat_anf_simplifier.h index 0f140d5ab4..8bd30bbe73 100644 --- a/src/sat/sat_anf_simplifier.h +++ b/src/sat/sat_anf_simplifier.h @@ -28,7 +28,7 @@ namespace dd { class pdd; class solver; -}; +} namespace sat { diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 0aed69d616..11a85b79e4 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -497,4 +497,4 @@ namespace sat { m_tr = 0; } -}; +} diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index 20a561214e..7be980477e 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -106,5 +106,5 @@ namespace sat { inline void dec(unsigned c) { m_counter -= c; } }; -}; +} diff --git a/src/sat/sat_bcd.cpp b/src/sat/sat_bcd.cpp index 0b9792ad68..99e0bd4f8f 100644 --- a/src/sat/sat_bcd.cpp +++ b/src/sat/sat_bcd.cpp @@ -353,4 +353,4 @@ namespace sat { m_R.reset(); } -}; +} diff --git a/src/sat/sat_bcd.h b/src/sat/sat_bcd.h index 643a8b8ad4..52d11ba5ed 100644 --- a/src/sat/sat_bcd.h +++ b/src/sat/sat_bcd.h @@ -73,5 +73,5 @@ namespace sat { void operator()(union_find<>& uf); }; -}; +} diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index 96ab78cb1a..9469f8431c 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -281,4 +281,4 @@ namespace sat { -}; +} diff --git a/src/sat/sat_big.h b/src/sat/sat_big.h index 8ee185f16a..a30231c7b0 100644 --- a/src/sat/sat_big.h +++ b/src/sat/sat_big.h @@ -87,5 +87,5 @@ namespace sat { void display(std::ostream& out) const; }; -}; +} diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index c59ce72891..6af39f4cd6 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -249,4 +249,4 @@ namespace sat { return out; } -}; +} diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 0129febbf8..852508a123 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -198,5 +198,5 @@ namespace sat { std::ostream & operator<<(std::ostream & out, clause_wrapper const & c); -}; +} diff --git a/src/sat/sat_clause_set.cpp b/src/sat/sat_clause_set.cpp index c223009d6e..13e08eb54c 100644 --- a/src/sat/sat_clause_set.cpp +++ b/src/sat/sat_clause_set.cpp @@ -88,4 +88,4 @@ namespace sat { return true; } -}; +} diff --git a/src/sat/sat_clause_set.h b/src/sat/sat_clause_set.h index aa0be6b62d..1a2ad3e756 100644 --- a/src/sat/sat_clause_set.h +++ b/src/sat/sat_clause_set.h @@ -50,5 +50,5 @@ namespace sat { bool check_invariant() const; }; -}; +} diff --git a/src/sat/sat_clause_use_list.cpp b/src/sat/sat_clause_use_list.cpp index 347e49db99..b00e26e78e 100644 --- a/src/sat/sat_clause_use_list.cpp +++ b/src/sat/sat_clause_use_list.cpp @@ -54,4 +54,4 @@ namespace sat { m_clauses.shrink(m_j); } -}; +} diff --git a/src/sat/sat_clause_use_list.h b/src/sat/sat_clause_use_list.h index 14961a2236..63b5879568 100644 --- a/src/sat/sat_clause_use_list.h +++ b/src/sat/sat_clause_use_list.h @@ -134,5 +134,5 @@ namespace sat { } }; -}; +} diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index 46b94b52c4..97abf11be5 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -230,4 +230,4 @@ namespace sat { st.update("sat elim literals", m_elim_literals); } -}; +} diff --git a/src/sat/sat_cleaner.h b/src/sat/sat_cleaner.h index 08d73029af..557b8a0d0b 100644 --- a/src/sat/sat_cleaner.h +++ b/src/sat/sat_cleaner.h @@ -48,5 +48,5 @@ namespace sat { void dec() { m_cleanup_counter--; } }; -}; +} diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 3dfb67f2a4..cf01d39eea 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -259,4 +259,4 @@ namespace sat { sat_params::collect_param_descrs(r); } -}; +} diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 83241fe88a..57076bf6ab 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -196,5 +196,5 @@ namespace sat { static void collect_param_descrs(param_descrs & d); }; -}; +} diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index f761ef9264..ea6ebd495b 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -306,4 +306,4 @@ namespace sat { } (*this)(roots, to_elim); } -}; +} diff --git a/src/sat/sat_elim_eqs.h b/src/sat/sat_elim_eqs.h index 8bfc2c4578..c5000f108b 100644 --- a/src/sat/sat_elim_eqs.h +++ b/src/sat/sat_elim_eqs.h @@ -47,5 +47,5 @@ namespace sat { void operator()(union_find<>& uf); }; -}; +} diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index b42cc33e21..0acfa4ea31 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -77,7 +77,7 @@ namespace sat { solver const& s() const { return *m_solver; } symbol const& name() const { return m_name; } - virtual void set_lookahead(lookahead* s) {}; + virtual void set_lookahead(lookahead* s) {} class scoped_drating { extension& ext; public: @@ -138,5 +138,5 @@ namespace sat { virtual std::string reason_unknown() { return "unknown"; } }; -}; +} diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index b10d243c23..54b0d63d79 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -221,4 +221,4 @@ namespace sat { VERIFY(check_disjoint_clauses()); return true; } -}; +} diff --git a/src/sat/sat_integrity_checker.h b/src/sat/sat_integrity_checker.h index bc7fecf68d..3d8ecd921d 100644 --- a/src/sat/sat_integrity_checker.h +++ b/src/sat/sat_integrity_checker.h @@ -42,4 +42,4 @@ namespace sat { bool check_disjoint_clauses() const; bool operator()() const; }; -}; +} diff --git a/src/sat/sat_justification.h b/src/sat/sat_justification.h index f83173aa7d..ecffa096fc 100644 --- a/src/sat/sat_justification.h +++ b/src/sat/sat_justification.h @@ -72,5 +72,5 @@ namespace sat { return out; } -}; +} diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 87757ba59d..0aaaf6f04c 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -25,7 +25,7 @@ Notes: namespace pb { class solver; -}; +} namespace sat { diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 67136d79ab..d1b2d38f06 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -455,4 +455,4 @@ namespace sat { } } -}; +} diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index 170886aa69..1d44db51ac 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -153,4 +153,4 @@ namespace sat { return out; } -}; +} diff --git a/src/sat/sat_mus.h b/src/sat/sat_mus.h index 672e90185f..b6845c30c5 100644 --- a/src/sat/sat_mus.h +++ b/src/sat/sat_mus.h @@ -61,5 +61,5 @@ namespace sat { }; }; -}; +} diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index 7d5c022ff1..8c9b897098 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -276,5 +276,5 @@ namespace sat { return copied; } -}; +} diff --git a/src/sat/sat_parallel.h b/src/sat/sat_parallel.h index 0fbf4f05d0..948eeaa3f0 100644 --- a/src/sat/sat_parallel.h +++ b/src/sat/sat_parallel.h @@ -112,5 +112,5 @@ namespace sat { bool copy_solver(solver& s); }; -}; +} diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index f1830623a3..b29e9513b1 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -322,4 +322,4 @@ namespace sat { void probing::reset_statistics() { m_num_assigned = 0; } -}; +} diff --git a/src/sat/sat_probing.h b/src/sat/sat_probing.h index 4b13d6afdd..a7eac7ba8b 100644 --- a/src/sat/sat_probing.h +++ b/src/sat/sat_probing.h @@ -91,5 +91,5 @@ namespace sat { void dec(unsigned c) { m_counter -= c; } }; -}; +} diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 8308a7ea59..21ceb3c6c5 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -282,4 +282,4 @@ namespace sat { sat_scc_params::collect_param_descrs(d); } -}; +} diff --git a/src/sat/sat_scc.h b/src/sat/sat_scc.h index af239c53d9..5b2f0dd260 100644 --- a/src/sat/sat_scc.h +++ b/src/sat/sat_scc.h @@ -65,5 +65,5 @@ namespace sat { int get_right(literal l) const { return m_big.get_right(l); } bool connected(literal u, literal v) const { return m_big.connected(u, v); } }; -}; +} diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 18e6288208..79c8a723c6 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -2148,4 +2148,4 @@ namespace sat { m_num_bca = 0; m_num_ate = 0; } -}; +} diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index e32c52e4a1..0dd85c6b85 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -250,5 +250,5 @@ namespace sat { bool need_cleanup() const { return m_need_cleanup; } }; -}; +} diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 0a109bd0c5..634b09830e 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -4865,4 +4865,4 @@ namespace sat { return true; } -}; +} diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 66352387a2..a64b8fa614 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -48,7 +48,7 @@ Revision History: namespace pb { class solver; -}; +} namespace sat { @@ -895,4 +895,4 @@ namespace sat { std::ostream & operator<<(std::ostream & out, mk_stat const & stat); -}; +} diff --git a/src/sat/sat_solver_core.h b/src/sat/sat_solver_core.h index cc0e6e0233..905f9739fd 100644 --- a/src/sat/sat_solver_core.h +++ b/src/sat/sat_solver_core.h @@ -49,7 +49,7 @@ namespace sat { // optional support for user-scopes. Not relevant for sat_tactic integration. // it is only relevant for incremental mode SAT, which isn't wrapped (yet) virtual void user_push() { throw default_exception("optional API not supported"); } - virtual void user_pop(unsigned num_scopes) {}; + virtual void user_pop(unsigned num_scopes) {} virtual unsigned num_user_scopes() const { return 0;} virtual unsigned num_scopes() const { return 0; } @@ -58,5 +58,5 @@ namespace sat { virtual extension* get_extension() const { return nullptr; } virtual void set_extension(extension* e) { if (e) throw default_exception("optional API not supported"); } }; -}; +} diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index b027d4f2e1..ce24521cae 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -106,7 +106,7 @@ namespace sat { int m_orig; const proof_hint* m_hint; public: - status(st s, int o, proof_hint const* ps = nullptr) : m_st(s), m_orig(o), m_hint(ps) {}; + status(st s, int o, proof_hint const* ps = nullptr) : m_st(s), m_orig(o), m_hint(ps) {} status(status const& s) : m_st(s.m_st), m_orig(s.m_orig), m_hint(s.m_hint) {} status(status&& s) noexcept { m_st = st::asserted; m_orig = -1; std::swap(m_st, s.m_st); std::swap(m_orig, s.m_orig); std::swap(m_hint, s.m_hint); } status& operator=(status const& other) { m_st = other.m_st; m_orig = other.m_orig; return *this; } @@ -170,7 +170,7 @@ namespace sat { }; -}; +} diff --git a/src/sat/sat_watched.cpp b/src/sat/sat_watched.cpp index 5573212f53..865a4b06dc 100644 --- a/src/sat/sat_watched.cpp +++ b/src/sat/sat_watched.cpp @@ -110,4 +110,4 @@ namespace sat { return out; } -}; +} diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index 6d91434dba..4e44bbc1b1 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -125,5 +125,5 @@ namespace sat { std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist, extension* ext); void conflict_cleanup(watch_list::iterator it, watch_list::iterator it2, watch_list& wlist); -}; +} diff --git a/src/sat/smt/arith_value.cpp b/src/sat/smt/arith_value.cpp index fb66bdaefd..f6e1e68c79 100644 --- a/src/sat/smt/arith_value.cpp +++ b/src/sat/smt/arith_value.cpp @@ -142,4 +142,4 @@ namespace arith { #endif -}; +} diff --git a/src/sat/smt/arith_value.h b/src/sat/smt/arith_value.h index b858ff8965..89d7c69a36 100644 --- a/src/sat/smt/arith_value.h +++ b/src/sat/smt/arith_value.h @@ -49,4 +49,4 @@ namespace arith { expr_ref get_fixed(expr* e); #endif }; -}; +} diff --git a/src/sat/smt/bv_ackerman.h b/src/sat/smt/bv_ackerman.h index aab4053a28..259e1bfbf8 100644 --- a/src/sat/smt/bv_ackerman.h +++ b/src/sat/smt/bv_ackerman.h @@ -78,4 +78,4 @@ namespace bv { void propagate(); }; -}; +} diff --git a/src/sat/smt/bv_delay_internalize.cpp b/src/sat/smt/bv_delay_internalize.cpp index af3c4abe92..aeda79b5be 100644 --- a/src/sat/smt/bv_delay_internalize.cpp +++ b/src/sat/smt/bv_delay_internalize.cpp @@ -308,7 +308,7 @@ namespace bv { tmp = m.mk_or(literal2expr(b), tmp); xs.push_back(tmp); } - }; + } /** * The i'th bit in xs is 1 if the least significant bit of x is i or lower. @@ -324,7 +324,7 @@ namespace bv { tmp = m.mk_or(literal2expr(b), tmp); xs.push_back(tmp); } - }; + } /** * Check non-overflow of unsigned multiplication. diff --git a/src/sat/smt/bv_solver.cpp b/src/sat/smt/bv_solver.cpp index 3ac6da3033..09299bbca6 100644 --- a/src/sat/smt/bv_solver.cpp +++ b/src/sat/smt/bv_solver.cpp @@ -521,7 +521,7 @@ namespace bv { } func_decl* f = m.mk_func_decl(th, sorts.size(), sorts.data(), proof); return m.mk_app(f, args); - }; + } void solver::asserted(literal l) { atom* a = get_bv2a(l.var()); diff --git a/src/sat/smt/euf_ackerman.h b/src/sat/smt/euf_ackerman.h index 846ddb8ae6..37ed814153 100644 --- a/src/sat/smt/euf_ackerman.h +++ b/src/sat/smt/euf_ackerman.h @@ -87,4 +87,4 @@ namespace euf { void propagate(); }; -}; +} diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 69017679c3..72fd6ebabb 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -576,7 +576,7 @@ namespace euf { return p.display(out); } -}; +} inline std::ostream& operator<<(std::ostream& out, euf::solver const& s) { return s.display(out); diff --git a/src/sat/smt/fpa_solver.cpp b/src/sat/smt/fpa_solver.cpp index 7f39cd5ed3..238c7d57cc 100644 --- a/src/sat/smt/fpa_solver.cpp +++ b/src/sat/smt/fpa_solver.cpp @@ -440,4 +440,4 @@ namespace fpa { } } -}; +} diff --git a/src/sat/smt/intblast_solver.cpp b/src/sat/smt/intblast_solver.cpp index 39094b9682..2b8468e16b 100644 --- a/src/sat/smt/intblast_solver.cpp +++ b/src/sat/smt/intblast_solver.cpp @@ -330,7 +330,7 @@ namespace intblast { } } return r; - }; + } bool solver::is_bv(sat::literal lit) { expr* e = ctx.bool_var2expr(lit.var()); diff --git a/src/sat/smt/pb_constraint.h b/src/sat/smt/pb_constraint.h index 4c6f69e077..15e885ae2d 100644 --- a/src/sat/smt/pb_constraint.h +++ b/src/sat/smt/pb_constraint.h @@ -100,7 +100,7 @@ namespace pb { virtual bool validate_unit_propagation(solver_interface const& s, literal alit) const = 0; - virtual bool is_watching(literal l) const { UNREACHABLE(); return false; }; + virtual bool is_watching(literal l) const { UNREACHABLE(); return false; } virtual literal_vector literals() const { UNREACHABLE(); return literal_vector(); } virtual void swap(unsigned i, unsigned j) noexcept { UNREACHABLE(); } virtual literal get_lit(unsigned i) const { UNREACHABLE(); return sat::null_literal; } diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index 460a051ab2..fd91199bf7 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -3795,6 +3795,6 @@ namespace pb { return true; } -}; +} diff --git a/src/sat/smt/pb_solver.h b/src/sat/smt/pb_solver.h index 67c55c9d58..c73ad8f9ef 100644 --- a/src/sat/smt/pb_solver.h +++ b/src/sat/smt/pb_solver.h @@ -418,5 +418,5 @@ namespace pb { }; -}; +} diff --git a/src/sat/smt/q_queue.h b/src/sat/smt/q_queue.h index 3750ee31ba..256061aab7 100644 --- a/src/sat/smt/q_queue.h +++ b/src/sat/smt/q_queue.h @@ -26,7 +26,7 @@ Author: namespace euf { class solver; -}; +} namespace q { diff --git a/src/sat/smt/user_solver.h b/src/sat/smt/user_solver.h index 4bdfcf064f..df56bc1c98 100644 --- a/src/sat/smt/user_solver.h +++ b/src/sat/smt/user_solver.h @@ -169,4 +169,4 @@ namespace user_solver { euf::th_solver* clone(euf::solver& ctx) override; }; -}; +} diff --git a/src/smt/arith_eq_adapter.cpp b/src/smt/arith_eq_adapter.cpp index 2bbe7a4e1d..ba578b1850 100644 --- a/src/smt/arith_eq_adapter.cpp +++ b/src/smt/arith_eq_adapter.cpp @@ -278,5 +278,5 @@ namespace smt { out << "eq_adapter: #" << n1->get_owner_id() << " #" << n2->get_owner_id() << "\n"; } } -}; +} diff --git a/src/smt/arith_eq_adapter.h b/src/smt/arith_eq_adapter.h index 7b1c068761..b719d7e451 100644 --- a/src/smt/arith_eq_adapter.h +++ b/src/smt/arith_eq_adapter.h @@ -86,6 +86,6 @@ namespace smt { void collect_statistics(::statistics & st) const; void display_already_processed(std::ostream & out) const; }; -}; +} diff --git a/src/smt/dyn_ack.cpp b/src/smt/dyn_ack.cpp index 691bd7fc07..12fcc9754d 100644 --- a/src/smt/dyn_ack.cpp +++ b/src/smt/dyn_ack.cpp @@ -587,4 +587,4 @@ namespace smt { } #endif -}; +} diff --git a/src/smt/dyn_ack.h b/src/smt/dyn_ack.h index e04f78fd36..6d239d27b2 100644 --- a/src/smt/dyn_ack.h +++ b/src/smt/dyn_ack.h @@ -130,6 +130,6 @@ namespace smt { #endif }; -}; +} diff --git a/src/smt/fingerprints.cpp b/src/smt/fingerprints.cpp index d41e01573f..6a7d176965 100644 --- a/src/smt/fingerprints.cpp +++ b/src/smt/fingerprints.cpp @@ -165,4 +165,4 @@ namespace smt { #endif -}; +} diff --git a/src/smt/fingerprints.h b/src/smt/fingerprints.h index dc1863041e..93f6a115e7 100644 --- a/src/smt/fingerprints.h +++ b/src/smt/fingerprints.h @@ -76,6 +76,6 @@ namespace smt { bool slow_contains(void const * data, unsigned data_hash, unsigned num_args, enode * const * args) const; #endif }; -}; +} diff --git a/src/smt/mam.h b/src/smt/mam.h index e7051b3f76..758d9c684f 100644 --- a/src/smt/mam.h +++ b/src/smt/mam.h @@ -69,5 +69,5 @@ namespace smt { }; mam * mk_mam(context & ctx); -}; +} diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index 905644354d..cb803d7559 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -518,5 +518,5 @@ namespace smt { #endif } -}; +} diff --git a/src/smt/qi_queue.h b/src/smt/qi_queue.h index 13878a158b..7ae92fd16b 100644 --- a/src/smt/qi_queue.h +++ b/src/smt/qi_queue.h @@ -101,6 +101,6 @@ namespace smt { m_on_binding = on_binding; } }; -}; +} diff --git a/src/smt/seq_axioms.h b/src/smt/seq_axioms.h index 525f6b3db3..f16ae6b55f 100644 --- a/src/smt/seq_axioms.h +++ b/src/smt/seq_axioms.h @@ -105,5 +105,5 @@ namespace smt { }; -}; +} diff --git a/src/smt/seq_offset_eq.h b/src/smt/seq_offset_eq.h index 669d63b7fd..ee308d5161 100644 --- a/src/smt/seq_offset_eq.h +++ b/src/smt/seq_offset_eq.h @@ -53,5 +53,5 @@ namespace smt { void pop_scope_eh(unsigned num_scopes); }; -}; +} diff --git a/src/smt/seq_regex.h b/src/smt/seq_regex.h index dd1c474b31..bba4d30eaa 100644 --- a/src/smt/seq_regex.h +++ b/src/smt/seq_regex.h @@ -214,4 +214,4 @@ namespace smt { }; -}; +} diff --git a/src/smt/smt_almost_cg_table.cpp b/src/smt/smt_almost_cg_table.cpp index f50f34dd6f..e97aa32d08 100644 --- a/src/smt/smt_almost_cg_table.cpp +++ b/src/smt/smt_almost_cg_table.cpp @@ -124,4 +124,4 @@ namespace smt { return result; } -}; +} diff --git a/src/smt/smt_almost_cg_table.h b/src/smt/smt_almost_cg_table.h index 6b0cc66526..f7b89af324 100644 --- a/src/smt/smt_almost_cg_table.h +++ b/src/smt/smt_almost_cg_table.h @@ -65,6 +65,6 @@ namespace smt { bool empty() const { return m_table.empty(); } }; -}; +} diff --git a/src/smt/smt_arith_value.cpp b/src/smt/smt_arith_value.cpp index 806598e76f..6c187b9482 100644 --- a/src/smt/smt_arith_value.cpp +++ b/src/smt/smt_arith_value.cpp @@ -169,4 +169,4 @@ namespace smt { return l_undef; return m_thr->check_lp_feasible(ineqs, lit_core, eq_core); } -}; +} diff --git a/src/smt/smt_arith_value.h b/src/smt/smt_arith_value.h index 7e351e43d5..3c2339887d 100644 --- a/src/smt/smt_arith_value.h +++ b/src/smt/smt_arith_value.h @@ -51,4 +51,4 @@ namespace smt { lbool check_lp_feasible(vector> &ineqs, literal_vector &lit_core, enode_pair_vector &eq_core); }; -}; +} diff --git a/src/smt/smt_b_justification.h b/src/smt/smt_b_justification.h index ae01a389d9..cbf399ef79 100644 --- a/src/smt/smt_b_justification.h +++ b/src/smt/smt_b_justification.h @@ -99,6 +99,6 @@ namespace smt { } typedef std::pair justified_literal; -}; +} diff --git a/src/smt/smt_bool_var_data.h b/src/smt/smt_bool_var_data.h index 68d7a8d45f..129a864897 100644 --- a/src/smt/smt_bool_var_data.h +++ b/src/smt/smt_bool_var_data.h @@ -131,6 +131,6 @@ namespace smt { m_atom = false; } }; -}; +} diff --git a/src/smt/smt_case_split_queue.h b/src/smt/smt_case_split_queue.h index 5c1b8c8ee3..1e503afdb9 100644 --- a/src/smt/smt_case_split_queue.h +++ b/src/smt/smt_case_split_queue.h @@ -52,6 +52,6 @@ namespace smt { }; case_split_queue * mk_case_split_queue(context & ctx, smt_params & p); -}; +} diff --git a/src/smt/smt_cg_table.cpp b/src/smt/smt_cg_table.cpp index 018a543c0b..a25b38aee9 100644 --- a/src/smt/smt_cg_table.cpp +++ b/src/smt/smt_cg_table.cpp @@ -258,5 +258,5 @@ namespace smt { return true; } -}; +} diff --git a/src/smt/smt_cg_table.h b/src/smt/smt_cg_table.h index 9c2baed11e..3b24ceccf1 100644 --- a/src/smt/smt_cg_table.h +++ b/src/smt/smt_cg_table.h @@ -216,6 +216,6 @@ namespace smt { bool check_invariant() const; }; -}; +} diff --git a/src/smt/smt_checker.cpp b/src/smt/smt_checker.cpp index d2c1758d35..ab25923111 100644 --- a/src/smt/smt_checker.cpp +++ b/src/smt/smt_checker.cpp @@ -182,7 +182,7 @@ namespace smt { m_bindings(nullptr) { } -}; +} diff --git a/src/smt/smt_checker.h b/src/smt/smt_checker.h index 3cd83a106d..7a69a12316 100644 --- a/src/smt/smt_checker.h +++ b/src/smt/smt_checker.h @@ -50,6 +50,6 @@ namespace smt { bool is_unsat(expr * n, unsigned num_bindings = 0, enode * const * bindings = nullptr); }; -}; +} diff --git a/src/smt/smt_clause.cpp b/src/smt/smt_clause.cpp index 061e1dd230..0c2e8617eb 100644 --- a/src/smt/smt_clause.cpp +++ b/src/smt/smt_clause.cpp @@ -126,4 +126,4 @@ namespace smt { return out << mk_pp(disj, m, 3); } -}; +} diff --git a/src/smt/smt_clause.h b/src/smt/smt_clause.h index 89d8f2d66b..eeb9375ef5 100644 --- a/src/smt/smt_clause.h +++ b/src/smt/smt_clause.h @@ -279,6 +279,6 @@ namespace smt { typedef ptr_vector clause_vector; typedef obj_hashtable clause_set; -}; +} diff --git a/src/smt/smt_clause_proof.cpp b/src/smt/smt_clause_proof.cpp index 324674a998..96e4a6d57c 100644 --- a/src/smt/smt_clause_proof.cpp +++ b/src/smt/smt_clause_proof.cpp @@ -291,6 +291,6 @@ namespace smt { } } -}; +} diff --git a/src/smt/smt_clause_proof.h b/src/smt/smt_clause_proof.h index 28191cfa25..7fa86671e0 100644 --- a/src/smt/smt_clause_proof.h +++ b/src/smt/smt_clause_proof.h @@ -94,6 +94,6 @@ namespace smt { }; std::ostream& operator<<(std::ostream& out, clause_proof::status st); -}; +} diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 6cb22e5058..c1bed6fdb8 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -1485,5 +1485,5 @@ namespace smt { return alloc(conflict_resolution, m, ctx, dack_manager, params, assigned_literals, watches); } -}; +} diff --git a/src/smt/smt_conflict_resolution.h b/src/smt/smt_conflict_resolution.h index 39f7c68d50..54e91ba941 100644 --- a/src/smt/smt_conflict_resolution.h +++ b/src/smt/smt_conflict_resolution.h @@ -276,6 +276,6 @@ namespace smt { ); -}; +} diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 0e8062e880..4fafb42980 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4884,7 +4884,7 @@ namespace smt { m_model->add_rec_funs(); } -}; +} #ifdef Z3DEBUG diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index f11b54aeb1..8786e73bae 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1924,4 +1924,4 @@ namespace smt { std::ostream& operator<<(std::ostream& out, enode_pp const& p); -}; +} diff --git a/src/smt/smt_context_inv.cpp b/src/smt/smt_context_inv.cpp index e8f590e1a3..05b60ee625 100644 --- a/src/smt/smt_context_inv.cpp +++ b/src/smt/smt_context_inv.cpp @@ -420,5 +420,5 @@ namespace smt { } } -}; +} diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 8041099e59..10d6f624b8 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -786,5 +786,5 @@ namespace smt { IF_VERBOSE(2, verbose_stream() << str); } -}; +} diff --git a/src/smt/smt_context_stat.cpp b/src/smt/smt_context_stat.cpp index e1ff89c544..c01091e2b2 100644 --- a/src/smt/smt_context_stat.cpp +++ b/src/smt/smt_context_stat.cpp @@ -145,4 +145,4 @@ namespace smt { if (m_fparams.m_profile_res_sub) display_profile_res_sub(out); } -}; +} diff --git a/src/smt/smt_enode.cpp b/src/smt/smt_enode.cpp index 05b174e5e0..c4af96369b 100644 --- a/src/smt/smt_enode.cpp +++ b/src/smt/smt_enode.cpp @@ -374,5 +374,5 @@ namespace smt { get_enode()->m_func_decl_id = UINT_MAX; } -}; +} diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index e9dc4c4e13..30a2b512af 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -480,6 +480,6 @@ namespace smt { }; inline mk_pp pp(enode* n, ast_manager& m) { return mk_pp(n->get_expr(), m); } -}; +} diff --git a/src/smt/smt_eq_justification.h b/src/smt/smt_eq_justification.h index cc8b3ceb61..a8a3226c36 100644 --- a/src/smt/smt_eq_justification.h +++ b/src/smt/smt_eq_justification.h @@ -78,6 +78,6 @@ namespace smt { }; const eq_justification null_eq_justification(static_cast(nullptr)); -}; +} diff --git a/src/smt/smt_failure.h b/src/smt/smt_failure.h index 15890dd5bd..5ebc1fff61 100644 --- a/src/smt/smt_failure.h +++ b/src/smt/smt_failure.h @@ -35,5 +35,5 @@ namespace smt { QUANTIFIERS //!< Logical context contains universal quantifiers. }; -}; +} diff --git a/src/smt/smt_for_each_relevant_expr.cpp b/src/smt/smt_for_each_relevant_expr.cpp index e71a848a2b..5aac74b349 100644 --- a/src/smt/smt_for_each_relevant_expr.cpp +++ b/src/smt/smt_for_each_relevant_expr.cpp @@ -295,4 +295,4 @@ namespace smt { m_manager.is_label(n, pos, m_buffer); // copy symbols to buffer } -}; +} diff --git a/src/smt/smt_for_each_relevant_expr.h b/src/smt/smt_for_each_relevant_expr.h index 20be165c67..5fdb151736 100644 --- a/src/smt/smt_for_each_relevant_expr.h +++ b/src/smt/smt_for_each_relevant_expr.h @@ -35,7 +35,7 @@ namespace smt { unsigned count_at_labels_lit(expr* n, bool polarity); public: - check_at_labels(ast_manager& m) : m_manager(m) {}; + check_at_labels(ast_manager& m) : m_manager(m) {} /** \brief Check that 'n' as a formula contains at most one @ label within each and-or path. @@ -105,6 +105,6 @@ namespace smt { void operator()(expr * n) override; }; -}; +} diff --git a/src/smt/smt_implied_equalities.h b/src/smt/smt_implied_equalities.h index 8a063a5d85..6357cc952f 100644 --- a/src/smt/smt_implied_equalities.h +++ b/src/smt/smt_implied_equalities.h @@ -36,6 +36,6 @@ namespace smt { unsigned* class_ids); -}; +} diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 3bb498882a..77fc5c0d84 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -1867,4 +1867,4 @@ namespace smt { } SASSERT(th->is_attached_to_var(n)); } -}; +} diff --git a/src/smt/smt_justification.cpp b/src/smt/smt_justification.cpp index 1ae6732173..03843f0a83 100644 --- a/src/smt/smt_justification.cpp +++ b/src/smt/smt_justification.cpp @@ -440,5 +440,5 @@ namespace smt { return m.mk_th_lemma(m_th_id, m.mk_or(lits), 0, nullptr, m_params.size(), m_params.data()); } -}; +} diff --git a/src/smt/smt_justification.h b/src/smt/smt_justification.h index 161ffe839f..14c1ce7483 100644 --- a/src/smt/smt_justification.h +++ b/src/smt/smt_justification.h @@ -423,6 +423,6 @@ namespace smt { char const * get_name() const override { return "theory-lemma"; } }; -}; +} diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 1e49a8d3ce..3453633f87 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -352,4 +352,4 @@ namespace smt { m_imp->m_kernel.user_propagate_initialize_value(var, value); } -}; +} diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 0a6faaa091..a5ddce96c3 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -346,4 +346,4 @@ namespace smt { context & get_context(); context const& get_context() const; }; -}; +} diff --git a/src/smt/smt_literal.cpp b/src/smt/smt_literal.cpp index 94ac5e5677..8ec28693dc 100644 --- a/src/smt/smt_literal.cpp +++ b/src/smt/smt_literal.cpp @@ -116,5 +116,5 @@ namespace smt { } -}; +} diff --git a/src/smt/smt_literal.h b/src/smt/smt_literal.h index 17ed9c6c47..cf773353d1 100644 --- a/src/smt/smt_literal.h +++ b/src/smt/smt_literal.h @@ -54,6 +54,6 @@ namespace smt { bool backward_subsumption(unsigned num_lits1, literal const * lits1, unsigned num_lits2, literal const * lits2); -}; +} diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index c6c914fe03..64dc77eb59 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -582,4 +582,4 @@ namespace smt { } } -}; +} diff --git a/src/smt/smt_model_checker.h b/src/smt/smt_model_checker.h index 3a8e816399..c0945689c7 100644 --- a/src/smt/smt_model_checker.h +++ b/src/smt/smt_model_checker.h @@ -104,5 +104,5 @@ namespace smt { void operator()(expr* e); }; -}; +} diff --git a/src/smt/smt_model_finder.h b/src/smt/smt_model_finder.h index 3b34e0192f..a8c1210492 100644 --- a/src/smt/smt_model_finder.h +++ b/src/smt/smt_model_finder.h @@ -64,7 +64,7 @@ namespace smt { class hint_solver; class non_auf_macro_solver; class instantiation_set; - }; + } class model_finder : public quantifier2macro_infos { typedef mf::quantifier_analyzer quantifier_analyzer; @@ -123,5 +123,5 @@ namespace smt { quantifier_macro_info* operator()(quantifier* q) override; }; -}; +} diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 8cf9508d6f..7ecbaca6c7 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -533,4 +533,4 @@ namespace smt { return m_model.get(); } -}; +} diff --git a/src/smt/smt_model_generator.h b/src/smt/smt_model_generator.h index fd99dc6d84..ffd1a1f963 100644 --- a/src/smt/smt_model_generator.h +++ b/src/smt/smt_model_generator.h @@ -240,7 +240,7 @@ namespace smt { } } }; -}; +} diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 19953be75d..672246beae 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -962,4 +962,4 @@ namespace smt { return alloc(default_qm_plugin); } -}; +} diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h index 6d9a448222..ad3fee18e4 100644 --- a/src/smt/smt_quantifier.h +++ b/src/smt/smt_quantifier.h @@ -187,4 +187,4 @@ namespace smt { vector>& used_enodes) { return false; } }; -}; +} diff --git a/src/smt/smt_quick_checker.cpp b/src/smt/smt_quick_checker.cpp index f267cb481a..ad54d185b0 100644 --- a/src/smt/smt_quick_checker.cpp +++ b/src/smt/smt_quick_checker.cpp @@ -404,5 +404,5 @@ namespace smt { return new_expr; } -}; +} diff --git a/src/smt/smt_quick_checker.h b/src/smt/smt_quick_checker.h index 8c8fd6c81f..b152ecd6d5 100644 --- a/src/smt/smt_quick_checker.h +++ b/src/smt/smt_quick_checker.h @@ -98,6 +98,6 @@ namespace smt { bool instantiate_not_sat(quantifier * q); bool instantiate_not_sat(quantifier * q, unsigned num_candidates, expr * const * candidates); }; -}; +} diff --git a/src/smt/smt_relevancy.cpp b/src/smt/smt_relevancy.cpp index 720eac6c22..3f24a4e11c 100644 --- a/src/smt/smt_relevancy.cpp +++ b/src/smt/smt_relevancy.cpp @@ -720,6 +720,6 @@ namespace smt { } relevancy_propagator * mk_relevancy_propagator(context & ctx) { return alloc(relevancy_propagator_imp, ctx); } -}; +} diff --git a/src/smt/smt_relevancy.h b/src/smt/smt_relevancy.h index 4827fffcb8..8bd7f7b95b 100644 --- a/src/smt/smt_relevancy.h +++ b/src/smt/smt_relevancy.h @@ -196,6 +196,6 @@ namespace smt { relevancy_propagator * mk_relevancy_propagator(context & ctx); -}; +} diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 69dec1348c..f13eed6fbc 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -941,6 +941,6 @@ namespace smt { setup_unknown(); } -}; +} diff --git a/src/smt/smt_setup.h b/src/smt/smt_setup.h index 897755ef71..ce00baf679 100644 --- a/src/smt/smt_setup.h +++ b/src/smt/smt_setup.h @@ -124,6 +124,6 @@ namespace smt { symbol const & get_logic() const { return m_logic; } void operator()(config_mode cm); }; -}; +} diff --git a/src/smt/smt_statistics.cpp b/src/smt/smt_statistics.cpp index 95acd48191..10c65401ac 100644 --- a/src/smt/smt_statistics.cpp +++ b/src/smt/smt_statistics.cpp @@ -25,5 +25,5 @@ namespace smt { memset(this, 0, sizeof(statistics)); } -}; +} diff --git a/src/smt/smt_statistics.h b/src/smt/smt_statistics.h index 11f7612e6f..831cf67b04 100644 --- a/src/smt/smt_statistics.h +++ b/src/smt/smt_statistics.h @@ -52,7 +52,7 @@ namespace smt { void reset(); }; -}; +} diff --git a/src/smt/smt_theory.cpp b/src/smt/smt_theory.cpp index be32edacb9..b762e757e5 100644 --- a/src/smt/smt_theory.cpp +++ b/src/smt/smt_theory.cpp @@ -261,5 +261,5 @@ namespace smt { return get_th_var(ctx.get_enode(e)); } -}; +} diff --git a/src/smt/smt_theory.h b/src/smt/smt_theory.h index 70b5556d68..79d8629e51 100644 --- a/src/smt/smt_theory.h +++ b/src/smt/smt_theory.h @@ -655,6 +655,6 @@ namespace smt { virtual bool is_fixed_propagated(theory_var v, expr_ref& val, literal_vector & explain) { return false; } }; -}; +} diff --git a/src/smt/smt_types.h b/src/smt/smt_types.h index 4b7fc4cc76..f8cff938f4 100644 --- a/src/smt/smt_types.h +++ b/src/smt/smt_types.h @@ -72,6 +72,6 @@ namespace smt { // if defined, then clauses have an extra mask field used to optimize backward subsumption, and backward/forward subsumption resolution. #define APPROX_LIT_SET -}; +} diff --git a/src/smt/smt_value_sort.h b/src/smt/smt_value_sort.h index 979afebf2d..e477a0b723 100644 --- a/src/smt/smt_value_sort.h +++ b/src/smt/smt_value_sort.h @@ -30,6 +30,6 @@ namespace smt { bool is_value_sort(ast_manager& m, expr* e); -}; +} diff --git a/src/smt/theory_arith.cpp b/src/smt/theory_arith.cpp index 6aee87408c..b97615c3e1 100644 --- a/src/smt/theory_arith.cpp +++ b/src/smt/theory_arith.cpp @@ -27,4 +27,4 @@ namespace smt { // template class theory_arith; template class smt::theory_arith; -}; +} diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index c5dc9df663..6b9a7dc75d 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -1277,6 +1277,6 @@ namespace smt { // typedef theory_arith theory_smi_arith; -}; +} diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index c8fd25dbae..553e945967 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -147,7 +147,7 @@ namespace smt { result_map[it->m_var] = -1; } } - }; + } #ifdef Z3DEBUG /** @@ -2295,6 +2295,6 @@ namespace smt { } #endif -}; +} diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 6ba5eef741..2c352a6a25 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -3570,5 +3570,5 @@ namespace smt { } -}; +} diff --git a/src/smt/theory_arith_eq.h b/src/smt/theory_arith_eq.h index b983475778..45dab16bfc 100644 --- a/src/smt/theory_arith_eq.h +++ b/src/smt/theory_arith_eq.h @@ -346,6 +346,6 @@ namespace smt { tout << enode_pp(_x, ctx) << " = " << enode_pp(_y, ctx) << "\n";); ctx.assign_eq(_x, _y, eq_justification(js)); } -}; +} diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index fe02fe8842..e1ea198e17 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -1110,6 +1110,6 @@ namespace smt { return m_liberal_final_check || !m_changed_assignment ? FC_DONE : FC_CONTINUE; } -}; +} diff --git a/src/smt/theory_arith_inv.h b/src/smt/theory_arith_inv.h index f69d69d2f7..0b52ef7f17 100644 --- a/src/smt/theory_arith_inv.h +++ b/src/smt/theory_arith_inv.h @@ -229,6 +229,6 @@ namespace smt { #endif -}; +} diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 749ac82512..30cc8cbac2 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -2410,7 +2410,7 @@ final_check_status theory_arith::process_non_linear() { } -}; +} diff --git a/src/smt/theory_arith_pp.h b/src/smt/theory_arith_pp.h index 81ed037623..be642f5b87 100644 --- a/src/smt/theory_arith_pp.h +++ b/src/smt/theory_arith_pp.h @@ -528,6 +528,6 @@ namespace smt { id++; } -}; +} diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index d35da46796..eadaf69c5d 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -505,4 +505,4 @@ namespace smt { st.update("array splits", m_stats.m_num_eq_splits); } -}; +} diff --git a/src/smt/theory_array.h b/src/smt/theory_array.h index 88f5678aea..135255ab78 100644 --- a/src/smt/theory_array.h +++ b/src/smt/theory_array.h @@ -114,5 +114,5 @@ namespace smt { ptr_vector const& parent_selects(enode* n) { return m_var_data[find(n->get_root()->get_th_var(get_id()))]->m_parent_selects; } }; -}; +} diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index 19e89bd656..9f6841760d 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -1053,4 +1053,4 @@ namespace smt { return result; } -}; +} diff --git a/src/smt/theory_array_base.h b/src/smt/theory_array_base.h index 629faec98c..34da46f93f 100644 --- a/src/smt/theory_array_base.h +++ b/src/smt/theory_array_base.h @@ -213,5 +213,5 @@ namespace smt { ~theory_array_base() override { restore_sorts(0); } }; -}; +} diff --git a/src/smt/theory_array_full.h b/src/smt/theory_array_full.h index 9dae2dcb96..8ea160507f 100644 --- a/src/smt/theory_array_full.h +++ b/src/smt/theory_array_full.h @@ -118,5 +118,5 @@ namespace smt { void propagate() override; }; -}; +} diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index b535838438..f09be95069 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -2071,4 +2071,4 @@ namespace smt { #endif -}; +} diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index 247424e18c..6d64b7a14d 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -296,4 +296,4 @@ namespace smt { bool check_invariant(); bool check_zero_one_bits(theory_var v); }; -}; +} diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 3782f54d12..6d58f0c2f4 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -1414,4 +1414,4 @@ namespace smt { } -}; +} diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index be6b3d61ab..d76740aed9 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -215,6 +215,6 @@ namespace smt { bool include_func_interp(func_decl* f) override; }; -}; +} diff --git a/src/smt/theory_dense_diff_logic.cpp b/src/smt/theory_dense_diff_logic.cpp index 3d352ee845..7057a47f24 100644 --- a/src/smt/theory_dense_diff_logic.cpp +++ b/src/smt/theory_dense_diff_logic.cpp @@ -23,4 +23,4 @@ namespace smt { template class theory_dense_diff_logic; template class theory_dense_diff_logic; template class theory_dense_diff_logic; -}; +} diff --git a/src/smt/theory_dense_diff_logic.h b/src/smt/theory_dense_diff_logic.h index 8c2d62aa9a..d60d9edaff 100644 --- a/src/smt/theory_dense_diff_logic.h +++ b/src/smt/theory_dense_diff_logic.h @@ -292,6 +292,6 @@ namespace smt { typedef theory_dense_diff_logic theory_dense_i; typedef theory_dense_diff_logic theory_dense_smi; typedef theory_dense_diff_logic theory_dense_si; -}; +} diff --git a/src/smt/theory_dense_diff_logic_def.h b/src/smt/theory_dense_diff_logic_def.h index 243629db79..eba0e0ab83 100644 --- a/src/smt/theory_dense_diff_logic_def.h +++ b/src/smt/theory_dense_diff_logic_def.h @@ -1123,6 +1123,6 @@ namespace smt { return f; } -}; +} diff --git a/src/smt/theory_diff_logic.cpp b/src/smt/theory_diff_logic.cpp index 1664dbfe2f..96593cdc00 100644 --- a/src/smt/theory_diff_logic.cpp +++ b/src/smt/theory_diff_logic.cpp @@ -31,9 +31,9 @@ template class theory_diff_logic; template class theory_diff_logic; -}; +} namespace simplex { template class simplex; template class sparse_matrix; -}; +} diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index ac73ca820f..3781042ef5 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -407,7 +407,7 @@ namespace smt { typedef theory_diff_logic theory_fidl; typedef theory_diff_logic theory_rdl; typedef theory_diff_logic theory_frdl; -}; +} diff --git a/src/smt/theory_dl.cpp b/src/smt/theory_dl.cpp index a3cd84853a..2783d7def4 100644 --- a/src/smt/theory_dl.cpp +++ b/src/smt/theory_dl.cpp @@ -291,4 +291,4 @@ namespace smt { theory* mk_theory_dl(context& ctx) { return alloc(theory_dl, ctx); } -}; +} diff --git a/src/smt/theory_dl.h b/src/smt/theory_dl.h index 4bcd94e83f..fb87c9f302 100644 --- a/src/smt/theory_dl.h +++ b/src/smt/theory_dl.h @@ -23,6 +23,6 @@ namespace smt { theory* mk_theory_dl(context& ctx); -}; +} diff --git a/src/smt/theory_dummy.cpp b/src/smt/theory_dummy.cpp index 7f8af5a9d0..58bdeaab6c 100644 --- a/src/smt/theory_dummy.cpp +++ b/src/smt/theory_dummy.cpp @@ -70,4 +70,4 @@ namespace smt { return m_name; } -}; +} diff --git a/src/smt/theory_dummy.h b/src/smt/theory_dummy.h index de77f292d6..bf4ace8db5 100644 --- a/src/smt/theory_dummy.h +++ b/src/smt/theory_dummy.h @@ -51,6 +51,6 @@ namespace smt { char const * get_name() const override; }; -}; +} diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 492595f609..b9fb4bf69d 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -721,4 +721,4 @@ namespace smt { out << r->get_id() << " --> " << enode_pp(n, ctx) << "\n"; } } -}; +} diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 14797f62a4..50493a30c6 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -126,5 +126,5 @@ namespace smt { app* get_ite_value(expr* e); }; -}; +} diff --git a/src/smt/theory_opt.cpp b/src/smt/theory_opt.cpp index 365315bf2e..f1917a3a86 100644 --- a/src/smt/theory_opt.cpp +++ b/src/smt/theory_opt.cpp @@ -74,4 +74,4 @@ namespace smt { return a.is_numeral(term); } -}; +} diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 73c9d5cba5..5fdcfbdcc3 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -424,4 +424,4 @@ namespace smt { void propagate() override; static literal assert_ge(context& ctx, unsigned k, unsigned n, literal const* xs); }; -}; +} diff --git a/src/smt/theory_polymorphism.h b/src/smt/theory_polymorphism.h index 8fd88c69b3..a10f9aa84e 100644 --- a/src/smt/theory_polymorphism.h +++ b/src/smt/theory_polymorphism.h @@ -100,6 +100,6 @@ namespace smt { void init_model(model_generator & mg) override { } }; -}; +} diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index ee2ae002ae..50a267d653 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -642,6 +642,6 @@ namespace smt { expr* expr2rep(expr* e) override; bool get_length(expr* e, rational& r) override; }; -}; +} diff --git a/src/smt/theory_seq_empty.h b/src/smt/theory_seq_empty.h index 9571f46b76..26ad3573d8 100644 --- a/src/smt/theory_seq_empty.h +++ b/src/smt/theory_seq_empty.h @@ -43,6 +43,6 @@ namespace smt { }; -}; +} diff --git a/src/smt/theory_user_propagator.h b/src/smt/theory_user_propagator.h index 439ffdb7ea..6f382dca07 100644 --- a/src/smt/theory_user_propagator.h +++ b/src/smt/theory_user_propagator.h @@ -167,4 +167,4 @@ namespace smt { void propagate() override; void display(std::ostream& out) const override {} }; -}; +} diff --git a/src/smt/theory_utvpi.h b/src/smt/theory_utvpi.h index e94df49ebc..eeb19da847 100644 --- a/src/smt/theory_utvpi.h +++ b/src/smt/theory_utvpi.h @@ -358,7 +358,7 @@ namespace smt { typedef theory_utvpi theory_rutvpi; typedef theory_utvpi theory_iutvpi; -}; +} diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index 9d011299dc..6c96bb92fa 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -965,6 +965,6 @@ namespace smt { } -}; +} diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index d3b190010f..53b5c0b5fa 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -362,4 +362,4 @@ namespace smt { m_normalize = false; } -}; +} diff --git a/src/smt/theory_wmaxsat.h b/src/smt/theory_wmaxsat.h index 65461eb708..42cfbb3fd6 100644 --- a/src/smt/theory_wmaxsat.h +++ b/src/smt/theory_wmaxsat.h @@ -134,5 +134,5 @@ namespace smt { }; -}; +} diff --git a/src/smt/watch_list.cpp b/src/smt/watch_list.cpp index 973e586faa..08c8f117b5 100644 --- a/src/smt/watch_list.cpp +++ b/src/smt/watch_list.cpp @@ -128,4 +128,4 @@ namespace smt { begin_lits_core() += sizeof(literal); } -}; +} diff --git a/src/smt/watch_list.h b/src/smt/watch_list.h index e974ea51c3..f866adf094 100644 --- a/src/smt/watch_list.h +++ b/src/smt/watch_list.h @@ -193,6 +193,6 @@ namespace smt { }; -}; +} diff --git a/src/solver/assertions/asserted_formulas.h b/src/solver/assertions/asserted_formulas.h index ba0b1f8406..14f9c93968 100644 --- a/src/solver/assertions/asserted_formulas.h +++ b/src/solver/assertions/asserted_formulas.h @@ -190,7 +190,7 @@ class asserted_formulas { } \ void post_op() override { if (REDUCE) af.reduce_and_solve(); } \ bool should_apply() const override { return APP; } \ - }; + } #define MK_SIMPLIFIERF(NAME, FUNCTOR, MSG, APP, REDUCE) MK_SIMPLIFIERA(NAME, FUNCTOR, MSG, APP, (af.m), REDUCE) diff --git a/src/tactic/bv/bv_bound_chk_tactic.cpp b/src/tactic/bv/bv_bound_chk_tactic.cpp index 4835eacd9c..e5c20462de 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.cpp +++ b/src/tactic/bv/bv_bound_chk_tactic.cpp @@ -26,7 +26,7 @@ struct bv_bound_chk_stats { unsigned m_unsats; unsigned m_singletons; unsigned m_reduces; - bv_bound_chk_stats() : m_unsats(0), m_singletons(0), m_reduces(0) {}; + bv_bound_chk_stats() : m_unsats(0), m_singletons(0), m_reduces(0) {} }; struct bv_bound_chk_rewriter_cfg : public default_rewriter_cfg { diff --git a/src/tactic/core/ctx_simplify_tactic.h b/src/tactic/core/ctx_simplify_tactic.h index 213f01f623..476e97eb1d 100644 --- a/src/tactic/core/ctx_simplify_tactic.h +++ b/src/tactic/core/ctx_simplify_tactic.h @@ -57,7 +57,7 @@ public: virtual simplifier * translate(ast_manager & m) = 0; virtual unsigned scope_level() const = 0; virtual void updt_params(params_ref const & p) {} - void set_occs(goal_num_occurs& occs) { m_occs = &occs; }; + void set_occs(goal_num_occurs& occs) { m_occs = &occs; } bool shared(expr* t) const; }; diff --git a/src/tactic/core/symmetry_reduce_tactic.cpp b/src/tactic/core/symmetry_reduce_tactic.cpp index c05116c0a1..194388bde8 100644 --- a/src/tactic/core/symmetry_reduce_tactic.cpp +++ b/src/tactic/core/symmetry_reduce_tactic.cpp @@ -341,7 +341,7 @@ private: } typedef hashtable uint_set; - typedef obj_map app_siblings;; + typedef obj_map app_siblings; class siblings { app_map const& m_colors; diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 22e0f498be..d91ae3192a 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -1012,7 +1012,7 @@ public: result.reset(); // assumes in is not strenthened to one of the branches throw tactic_exception("failed-if-branching tactical"); } - }; + } tactic * translate(ast_manager & m) override { tactic * new_t = m_t->translate(m); diff --git a/src/util/sat_literal.h b/src/util/sat_literal.h index fb22ce5e17..95209fef24 100644 --- a/src/util/sat_literal.h +++ b/src/util/sat_literal.h @@ -190,7 +190,7 @@ namespace sat { return out << mk_lits_pp(ls.size(), ls.data()); } -}; +} namespace std { @@ -198,4 +198,4 @@ namespace std { if (l.sign()) return "-" + to_string(l.var()); return to_string(l.var()); } -}; +} diff --git a/src/util/sat_sls.h b/src/util/sat_sls.h index 82b84bd03d..3289d8a29e 100644 --- a/src/util/sat_sls.h +++ b/src/util/sat_sls.h @@ -36,6 +36,6 @@ namespace sat { inline std::ostream& operator<<(std::ostream& out, clause_info const& ci) { return out << ci.m_clause << " w: " << ci.m_weight << " nt: " << ci.m_num_trues; } -}; +} diff --git a/src/util/sign.h b/src/util/sign.h index 5221b3f684..8c21716495 100644 --- a/src/util/sign.h +++ b/src/util/sign.h @@ -18,7 +18,7 @@ Author: #pragma once typedef enum { sign_neg = -1, sign_zero = 0, sign_pos = 1} sign; -static inline sign operator-(sign s) { switch (s) { case sign_neg: return sign_pos; case sign_pos: return sign_neg; default: return sign_zero; } }; +static inline sign operator-(sign s) { switch (s) { case sign_neg: return sign_pos; case sign_pos: return sign_neg; default: return sign_zero; } } static inline sign to_sign(int s) { return s == 0 ? sign_zero : (s > 0 ? sign_pos : sign_neg); } static inline sign operator*(sign a, sign b) { return to_sign((int)a * (int)b); } static inline bool is_zero(sign s) { return s == sign_zero; } diff --git a/src/util/util.h b/src/util/util.h index d580209e94..34eec199bd 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -270,7 +270,7 @@ public: scoped_ptr& operator=(scoped_ptr&& other) noexcept { *this = other.detach(); return *this; - }; + } T * detach() { T* tmp = m_ptr; From 2a8f66f22bf973d7d20f603880513507befe427d Mon Sep 17 00:00:00 2001 From: Lev Nachmanson <5377127+levnach@users.noreply.github.com> Date: Thu, 2 Jul 2026 14:00:51 -0700 Subject: [PATCH 06/48] [snapshot-regression-fix] Keep symbolic re.range non-empty; fix soundness regression on range membership (#10017) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fixes a **soundness regression** in the sequence/regex rewriter: a symbolic character range such as `(re.range x x)` was unsoundly collapsed to `re.empty`, causing a satisfiable membership constraint to be reported `unsat`. This was surfaced by the `snapshot-regression` corpus in `Z3Prover/bench`. - **Originating discussion:** https://github.com/Z3Prover/bench/discussions/2761 - **Benchmark:** `iss-5873/bug-2.smt2` (in `Z3Prover/bench`, under `inputs/issues/iss-5873/`) - **z3 under test at capture:** `z3-4.17.0-x64-glibc-2.39` (Nightly) ## Divergence The recorded oracle expects `sat`; current z3 returns `unsat`: ```diff --- bug-2.expected.out (expected) +++ produced (current z3) @@ -1,3 +1,4 @@ -sat -((tmp_str0 "\u{0}")) +unsat +(error "line 12 column 10: check annotation that says sat") +(error "line 14 column 22: model is not available") (:reason-unknown "") ``` The benchmark asserts (simplified): ```smt2 (assert (= (str.in_re (str.replace tmp_str0 tmp_str0 tmp_str0) (re.range tmp_str0 tmp_str0)) (str.contains tmp_str0 tmp_str0))) ``` `str.contains x x` is always true and `str.replace x x x = x`, so this requires `str.in_re x (re.range x x)` to hold, which is satisfiable exactly when `x` is a single character (`len(x) = 1`). ## Root cause `seq_rewriter::mk_re_range` treated any bound that is not a concrete single-character literal as making the whole range **empty**: ```cpp if (str().is_string(lo, slo) && slo.length() == 1) clo = slo[0]; else if (str().is_unit(lo, lo1) && m_util.is_const_char(lo1, clo)) ; else is_empty = true; // unsound for a symbolic bound ``` For a symbolic bound this is unsound: `(re.range x x)` denotes `{x}` whenever `x` is a single character, not `∅`. Collapsing it to `re.empty` makes `str.in_re x (re.range x x)` false, contradicting the (true) `str.contains x x`, so the solver derives an unsound `unsat`. `git blame` attributes this unsound collapse to z3 commit `15f33f458d` ("Derive with ranges (#9965)"), which post-dates the oracle capture. ## Fix Two surgical changes in `src/ast/rewriter/seq_rewriter.cpp`: 1. **`mk_re_range`** no longer assumes emptiness for symbolic bounds. It concludes `re.empty` only when it can *prove* emptiness — a bound whose length can never be 1, or two concrete bounds with `lo > hi`. When a bound is symbolic it returns `BR_FAILED` and keeps the range. Concrete single-character ranges keep their existing handling (`lo == hi → str.to_re`, inverted → `re.empty`). 2. **`mk_str_in_regexp`** reduces membership in a range that has a symbolic bound to the equivalent length/order constraints, which are sound and complete under SMT-LIB `re.range` semantics: `str.in_re e (re.range lo hi)` ⟶ `len(lo)=1 ∧ len(hi)=1 ∧ len(e)=1 ∧ lo ≤ e ∧ e ≤ hi` (using `str.<=`). The derivative engine only unfolds ranges whose bounds are concrete characters, so without this reduction a symbolic-bound range would otherwise be left unsolved. ## Validation Rebuilt z3 from this branch on the workflow runner (`./configure && make -C build -j$(nproc)`) and re-ran the failing benchmark with the same option the snapshot capture uses (`-T:20`): ``` $ z3 -T:20 inputs/issues/iss-5873/bug-2.smt2 sat ((tmp_str0 "A")) (:reason-unknown "") ``` The verdict is now **`sat`** (was `unsat`) — the soundness regression is resolved. A correctness battery over concrete and symbolic ranges all returns the expected results, e.g.: - `(str.in_re "b" (re.range "a" "c"))` → `sat`, `(str.in_re "d" (re.range "a" "c"))` → `unsat` - `(str.in_re x (re.range x x))` → `sat`; with `(= (str.len x) 2)` → `unsat` - `(str.in_re "b" (re.range x y))` → `sat`; with `(str.< y x)` → `unsat` - `(str.in_re "" (re.range x y))` → `unsat`; `(str.in_re "ab" (re.range "a" "c"))` → `unsat` The pre-existing concrete-range derivative fast path is unchanged. ### Note on the model value (benign, unrelated to this fix) The model value differs from the recorded oracle: current z3 prints `((tmp_str0 "A"))` whereas the oracle recorded `((tmp_str0 "\u{0}"))`. Both are valid single-character models (the formula has many). This difference is **pre-existing and unrelated to this fix**: even a bare `(assert (= (str.len x) 1))` yields `"A"` on current z3. It stems from the seq/char theory's default character assignment for otherwise-unconstrained characters (`theory_char.cpp` assigns fresh characters starting from `'A'`), not from range handling. I deliberately did **not** force the character to `\u{0}` — adding `x = "\u{0}"` would be unsound over-constraining, and changing the global default character is out of scope for this soundness fix and would perturb unrelated models. The output is therefore semantically equivalent to the oracle (same `sat` verdict and reason-unknown) but not byte-identical. --- *Draft for human review. Diagnosed and fixed by the `snapshot-regression-fixer` maintenance workflow.* > Generated by [Fix a Z3 snapshot-regression divergence](https://github.com/Z3Prover/bench/actions/runs/28502614658) · 890.7 AIC · ⌖ 46.8 AIC · ⊞ 9K · [◷](https://github.com/search?q=repo%3AZ3Prover%2Fz3+%22gh-aw-workflow-id%3A+snapshot-regression-fixer%22&type=pullrequests) --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- src/ast/rewriter/seq_rewriter.cpp | 89 +++++++++++++++++++++++-------- src/test/seq_rewriter.cpp | 88 ++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 22 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 9e4a6ca72c..d1df4133b1 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -3263,6 +3263,39 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) { return BR_DONE; } + // (str.in_re e (re.range lo hi)) where a bound is not a concrete character. + // By SMT-LIB semantics (re.range lo hi) is the set of single characters c + // with lo <= c <= hi when lo and hi are themselves single characters, and + // the empty language otherwise; so membership is equivalent to lo, hi and + // e all being single characters with lo <= e <= hi. The derivative engine + // only unfolds ranges whose bounds are concrete characters, so without this + // reduction a range with a symbolic bound is left unsolved (and mk_re_range + // deliberately keeps such a range symbolic rather than unsoundly collapsing + // it to re.empty). Ranges with two concrete single-character bounds keep + // their existing derivative-based handling. + { + expr* rlo = nullptr, *rhi = nullptr; + if (re().is_range(b, rlo, rhi)) { + auto concrete_char = [&](expr* e) { + zstring s; + expr* ch = nullptr; + unsigned uc = 0; + return (str().is_string(e, s) && s.length() == 1) || + (str().is_unit(e, ch) && m_util.is_const_char(ch, uc)); + }; + if (!concrete_char(rlo) || !concrete_char(rhi)) { + expr_ref_vector conj(m()); + conj.push_back(m().mk_eq(str().mk_length(rlo), one())); + conj.push_back(m().mk_eq(str().mk_length(rhi), one())); + conj.push_back(m().mk_eq(str().mk_length(a), one())); + conj.push_back(str().mk_lex_le(rlo, a)); + conj.push_back(str().mk_lex_le(a, rhi)); + result = m().mk_and(conj); + return BR_REWRITE_FULL; + } + } + } + zstring s; if (str().is_string(a, s) && re().is_ground(b)) { // Just check membership and replace by true/false @@ -4126,35 +4159,47 @@ br_status seq_rewriter::mk_re_range(expr* lo, expr* hi, expr_ref& result) { is_empty = true; if (max_length(hi) == std::make_pair(true, rational(0))) is_empty = true; - if (!is_empty) { - if (str().is_string(lo, slo) && slo.length() == 1) - clo = slo[0]; - else if (str().is_unit(lo, lo1) && m_util.is_const_char(lo1, clo)) - ; - else - is_empty = true; - } - if (!is_empty) { - if (str().is_string(hi, shi) && shi.length() == 1) - chi = shi[0]; - else if (str().is_unit(hi, hi1) && m_util.is_const_char(hi1, chi)) - ; - else - is_empty = true; - } - - // clo/chi are only meaningful once both bounds were extracted; an early - // is_empty (from the length checks) leaves them at their default 0, so the - // is_empty return must come before the singleton/ordering checks below. - if (!is_empty && clo > chi) - is_empty = true; + // A provable length constraint (a bound can never be a single character) + // is the only sound way to conclude emptiness for a possibly-symbolic + // bound, so decide emptiness here before attempting to read concrete + // characters. if (is_empty) { sort* srt = re().mk_re(lo->get_sort()); result = re().mk_empty(srt); return BR_DONE; } + // Try to read concrete single-character bounds. A bound that is not a + // syntactic single-character literal is *symbolic* (its value depends on + // the model), NOT empty: collapsing such a range to re.empty is unsound + // (e.g. (re.range x x) is {x} whenever x is a single character), so we + // leave the range unevaluated (BR_FAILED) and let the theory solver + // reason about it. + bool has_clo = false, has_chi = false; + if (str().is_string(lo, slo) && slo.length() == 1) { + clo = slo[0]; + has_clo = true; + } + else if (str().is_unit(lo, lo1) && m_util.is_const_char(lo1, clo)) + has_clo = true; + if (str().is_string(hi, shi) && shi.length() == 1) { + chi = shi[0]; + has_chi = true; + } + else if (str().is_unit(hi, hi1) && m_util.is_const_char(hi1, chi)) + has_chi = true; + + if (!has_clo || !has_chi) + return BR_FAILED; + + // Both bounds are concrete characters: an inverted range is empty. + if (clo > chi) { + sort* srt = re().mk_re(lo->get_sort()); + result = re().mk_empty(srt); + return BR_DONE; + } + // Singleton: re.range "a" "a" → str.to_re "a" if (clo == chi) { result = re().mk_to_re(str().mk_string(zstring(clo))); diff --git a/src/test/seq_rewriter.cpp b/src/test/seq_rewriter.cpp index 658675fa72..920a4ae4ac 100644 --- a/src/test/seq_rewriter.cpp +++ b/src/test/seq_rewriter.cpp @@ -10,12 +10,19 @@ Tests: 4. Range ∪ Range → merged range for overlapping/adjacent 5. Complement of range → one or two ranges 6. Downstream operators absorb empty ranges correctly + 15. Symbolic-bound range membership rewrite (structural) + 16. Symbolic-bound range membership: concrete element, symbolic bounds (structural) + 17. Solver: (str.in_re x (re.range x x)) sat when len(x)=1 + 18. Solver: (str.in_re x (re.range x x)) unsat when len(x)=2 + 19. Solver: inverted symbolic bounds make membership unsatisfiable --*/ +#include "ast/arith_decl_plugin.h" #include "ast/ast_pp.h" #include "ast/reg_decl_plugins.h" #include "ast/rewriter/th_rewriter.h" #include "ast/seq_decl_plugin.h" +#include "smt/smt_context.h" #include // Build a single-char string literal expression. @@ -167,5 +174,86 @@ void tst_seq_rewriter() { ENSURE(su.re.is_empty(e)); } + // ----------------------------------------------------------------------- + // 15. Symbolic-bound range membership rewrite (structural). + // (str.in_re x (re.range x x)) with symbolic x should be unfolded + // by the rewriter into a conjunction of length and ordering + // constraints, not left stuck as an uninterpreted membership term. + // ----------------------------------------------------------------------- + { + app_ref x(m.mk_fresh_const("x", str_sort), m); + expr_ref rng(su.re.mk_range(x, x), m); + expr_ref e(su.re.mk_in_re(x, rng), m); + rw(e); + std::cout << "symbolic range (x in [x,x]): " << mk_pp(e, m) << "\n"; + ENSURE(m.is_and(e)); + } + + // ----------------------------------------------------------------------- + // 16. Symbolic-bound range membership: concrete element, symbolic bounds. + // (str.in_re "b" (re.range lo hi)) should also be unfolded to a + // conjunction when lo/hi are free variables. + // ----------------------------------------------------------------------- + { + app_ref lo(m.mk_fresh_const("lo", str_sort), m); + app_ref hi(m.mk_fresh_const("hi", str_sort), m); + expr_ref b_str(su.str.mk_string(zstring('b')), m); + expr_ref rng(su.re.mk_range(lo, hi), m); + expr_ref e(su.re.mk_in_re(b_str, rng), m); + rw(e); + std::cout << "symbolic range (\"b\" in [lo,hi]): " << mk_pp(e, m) << "\n"; + ENSURE(m.is_and(e)); + } + + // ----------------------------------------------------------------------- + // Solver-level tests: the unfolded conjunction must be decidable. + // ----------------------------------------------------------------------- + { + arith_util a_util(m); + + // 17. sat: (str.in_re x (re.range x x)) ∧ len(x)=1 + { + smt_params sp; + smt::context ctx(m, sp); + app_ref x(m.mk_fresh_const("x", str_sort), m); + ctx.assert_expr(su.re.mk_in_re(x, su.re.mk_range(x, x))); + ctx.assert_expr(m.mk_eq(su.str.mk_length(x), a_util.mk_int(1))); + lbool res = ctx.check(); + std::cout << "symbolic range solver sat (len=1): " << res << "\n"; + ENSURE(res == l_true); + } + + // 18. unsat: (str.in_re x (re.range x x)) ∧ len(x)=2 + // The unfolded membership requires len(x)=1, which contradicts len(x)=2. + { + smt_params sp; + smt::context ctx(m, sp); + app_ref x(m.mk_fresh_const("x", str_sort), m); + ctx.assert_expr(su.re.mk_in_re(x, su.re.mk_range(x, x))); + ctx.assert_expr(m.mk_eq(su.str.mk_length(x), a_util.mk_int(2))); + lbool res = ctx.check(); + std::cout << "symbolic range solver unsat (len=2): " << res << "\n"; + ENSURE(res == l_false); + } + + // 19. unsat: inverted symbolic bounds make membership false. + // (str.in_re "b" (re.range lo hi)) ∧ lo="z" ∧ hi="a" + // The unfolded conjunction requires lo <=_lex "b" <=_lex hi, but + // "z" > "b" > "a" so the ordering constraints are unsatisfiable. + { + smt_params sp; + smt::context ctx(m, sp); + app_ref lo(m.mk_fresh_const("lo", str_sort), m); + app_ref hi(m.mk_fresh_const("hi", str_sort), m); + expr_ref b_str(su.str.mk_string(zstring('b')), m); + ctx.assert_expr(su.re.mk_in_re(b_str, su.re.mk_range(lo, hi))); + ctx.assert_expr(m.mk_eq(lo, su.str.mk_string(zstring('z')))); + ctx.assert_expr(m.mk_eq(hi, su.str.mk_string(zstring('a')))); + lbool res = ctx.check(); + std::cout << "symbolic range solver inverted bounds unsat: " << res << "\n"; + ENSURE(res == l_false); + } + } + std::cout << "tst_seq_rewriter: all tests passed\n"; } From f15584cdae319a44ae70854a319aa3aee715dd21 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Jul 2026 15:19:11 -0700 Subject: [PATCH 07/48] update epsilon encoding --- src/cmd_context/tptp_frontend.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/cmd_context/tptp_frontend.cpp b/src/cmd_context/tptp_frontend.cpp index 4dd535b765..f0c931369c 100644 --- a/src/cmd_context/tptp_frontend.cpp +++ b/src/cmd_context/tptp_frontend.cpp @@ -1467,8 +1467,28 @@ class tptp_parser { m_bound.push_back(scope); expr_ref body = parse_formula(is_boolean); m_bound.pop_back(); - // Approximate choice as existential quantification - return mk_quantifier(false, vars, body); + // Choice/description operator. @+ is Hilbert's choice (indefinite + // description) and @- is definite description. Both denote an ELEMENT of + // the bound sort T — a witness selected from those satisfying the predicate + // — NOT a Boolean. Encode as Z3's array OP_CHOICE applied to the predicate + // lambda (λX:T. body), which yields a term of sort T (cf. smt2parser). + if (vars.empty()) + return body; + expr_ref pred = ensure_bool(body); + // OP_CHOICE is single-arity. With several binders choose over the first + // variable and existentially bind the remainder inside the predicate. + if (vars.size() > 1) { + ptr_vector rest; + for (unsigned i = 1; i < vars.size(); ++i) rest.push_back(vars[i]); + pred = expr_ref(::mk_exists(m, rest.size(), rest.data(), pred.get()), m); + } + app* xvar = vars[0]; + expr_ref abs_body(m); + expr_abstract(m, 0, 1, (expr* const*)&xvar, pred, abs_body); + sort* xs = xvar->get_sort(); + symbol xnm = xvar->get_decl()->get_name(); + expr_ref lam(m.mk_lambda(1, &xs, &xnm, abs_body), m); + return expr_ref(m_array.mk_choice(lam), m); } expr_ref_vector args(m); From 7e9eef845fc287935c1fde9a4758653da8abf58b Mon Sep 17 00:00:00 2001 From: Lev Nachmanson <5377127+levnach@users.noreply.github.com> Date: Fri, 3 Jul 2026 09:53:04 -0700 Subject: [PATCH 08/48] smt: skip m_watches probe for unwatched literals in relevancy propagator (#10035) --- src/smt/smt_relevancy.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/smt/smt_relevancy.cpp b/src/smt/smt_relevancy.cpp index 3f24a4e11c..fcaf604558 100644 --- a/src/smt/smt_relevancy.cpp +++ b/src/smt/smt_relevancy.cpp @@ -141,6 +141,13 @@ namespace smt { typedef list relevancy_ehs; obj_map m_relevant_ehs; obj_map m_watches[2]; + // Over-approximating membership filter for m_watches: contains a superset + // of the expr ids that have (or ever had) a watch list for the given phase. + // It is monotonic (never cleared on erase/pop), so it can only yield false + // positives, never false negatives. This lets get_watches() skip the + // obj_map pointer-hash probe for the common unwatched-literal case at the + // assign_eh hotspot. + uint_set m_is_watched[2]; struct eh_trail { enum class kind { POS_WATCH, NEG_WATCH, HANDLER }; kind m_kind; @@ -185,17 +192,23 @@ namespace smt { } relevancy_ehs * get_watches(expr * n, bool val) { + unsigned idx = val ? 1 : 0; + if (!m_is_watched[idx].contains(n->get_id())) + return nullptr; relevancy_ehs * r = nullptr; - m_watches[val ? 1 : 0].find(n, r); - SASSERT(m_watches[val ? 1 : 0].contains(n) || r == 0); + m_watches[idx].find(n, r); + SASSERT(m_watches[idx].contains(n) || r == 0); return r; } void set_watches(expr * n, bool val, relevancy_ehs * ehs) { + unsigned idx = val ? 1 : 0; if (ehs == nullptr) - m_watches[val ? 1 : 0].erase(n); - else - m_watches[val ? 1 : 0].insert(n, ehs); + m_watches[idx].erase(n); + else { + m_watches[idx].insert(n, ehs); + m_is_watched[idx].insert(n->get_id()); + } } void push_trail(eh_trail const & t) { From 286146b4530f302a58c9db9d76b2e5c9ec57346b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 13:17:06 -0700 Subject: [PATCH 09/48] Bump actions/cache/save from 5.0.5 to 6.1.0 (#10024) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/cache/save](https://github.com/actions/cache) from 5.0.5 to 6.1.0.
Release notes

Sourced from actions/cache/save's releases.

v6.1.0

What's Changed

Full Changelog: https://github.com/actions/cache/compare/v6...v6.1.0

v6.0.0

What's Changed

Full Changelog: https://github.com/actions/cache/compare/v5...v6.0.0

v5.1.0

What's Changed

Full Changelog: https://github.com/actions/cache/compare/v5...v5.1.0

Changelog

Sourced from actions/cache/save's changelog.

Releases

How to prepare a release

[!NOTE] Relevant for maintainers with write access only.

  1. Switch to a new branch from main.
  2. Run npm test to ensure all tests are passing.
  3. Update the version in https://github.com/actions/cache/blob/main/package.json.
  4. Run npm run build to update the compiled files.
  5. Update this https://github.com/actions/cache/blob/main/RELEASES.md with the new version and changes in the ## Changelog section.
  6. Run licensed cache to update the license report.
  7. Run licensed status and resolve any warnings by updating the https://github.com/actions/cache/blob/main/.licensed.yml file with the exceptions.
  8. Commit your changes and push your branch upstream.
  9. Open a pull request against main and get it reviewed and merged.
  10. Draft a new release https://github.com/actions/cache/releases use the same version number used in package.json
    1. Create a new tag with the version number.
    2. Auto generate release notes and update them to match the changes you made in RELEASES.md.
    3. Toggle the set as the latest release option.
    4. Publish the release.
  11. Navigate to https://github.com/actions/cache/actions/workflows/release-new-action-version.yml
    1. There should be a workflow run queued with the same version number.
    2. Approve the run to publish the new version and update the major tags for this action.

Changelog

6.1.0

6.0.0

  • Updated @actions/cache to ^6.0.1, @actions/core to ^3.0.1, @actions/exec to ^3.0.0, @actions/io to ^3.0.2
  • Migrated to ESM module system
  • Upgraded Jest to v30 and test infrastructure to be ESM compatible

5.0.4

  • Bump minimatch to v3.1.5 (fixes ReDoS via globstar patterns)
  • Bump undici to v6.24.1 (WebSocket decompression bomb protection, header validation fixes)
  • Bump fast-xml-parser to v5.5.6

5.0.3

5.0.2

... (truncated)

Commits
  • 55cc834 Merge pull request #1768 from jasongin/readonly-cache
  • d8cd72f Bump @​actions/cache to v6.1.0 - handle cache write error due to RO token
  • 2c8a9bd Merge pull request #1760 from actions/samirat/esm_migration_and_package_update
  • e9b91fd Prettier fixes
  • e4884b8 Rebuild dist
  • 10baf01 Fixed licenses
  • e39b386 Fix test mock return order
  • b692820 PR feedback
  • 6074912 Rebuild dist bundles as ESM to match type:module
  • 5a912e8 Fix lint and jest issues
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/cache/save&package-manager=github_actions&previous-version=5.0.5&new-version=6.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/academic-citation-tracker.lock.yml | 4 ++-- .github/workflows/agentics-maintenance.yml | 4 ++-- .github/workflows/api-coherence-checker.lock.yml | 4 ++-- .github/workflows/code-conventions-analyzer.lock.yml | 4 ++-- .github/workflows/csa-analysis.lock.yml | 4 ++-- .github/workflows/issue-backlog-processor.lock.yml | 4 ++-- .github/workflows/memory-safety-report.lock.yml | 4 ++-- .github/workflows/smtlib-benchmark-finder.lock.yml | 4 ++-- .github/workflows/specbot-crash-analyzer.lock.yml | 4 ++-- .github/workflows/tactic-to-simplifier.lock.yml | 4 ++-- .github/workflows/workflow-suggestion-agent.lock.yml | 4 ++-- .github/workflows/zipt-code-reviewer.lock.yml | 4 ++-- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/academic-citation-tracker.lock.yml b/.github/workflows/academic-citation-tracker.lock.yml index 334003e1a8..47ffd856f3 100644 --- a/.github/workflows/academic-citation-tracker.lock.yml +++ b/.github/workflows/academic-citation-tracker.lock.yml @@ -33,7 +33,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1592,7 +1592,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/agentics-maintenance.yml b/.github/workflows/agentics-maintenance.yml index 2e3a02c579..fe7a49ef26 100644 --- a/.github/workflows/agentics-maintenance.yml +++ b/.github/workflows/agentics-maintenance.yml @@ -393,7 +393,7 @@ jobs: - name: Save activity report logs cache if: ${{ always() }} - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ./.cache/gh-aw/activity-report-logs key: ${{ steps.activity_report_logs_cache.outputs.cache-primary-key }} @@ -520,7 +520,7 @@ jobs: - name: Save forecast report logs cache if: ${{ always() }} - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ./.github/aw/logs key: ${{ runner.os }}-forecast-report-logs-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_id }} diff --git a/.github/workflows/api-coherence-checker.lock.yml b/.github/workflows/api-coherence-checker.lock.yml index 5f402f213c..831331fc67 100644 --- a/.github/workflows/api-coherence-checker.lock.yml +++ b/.github/workflows/api-coherence-checker.lock.yml @@ -33,7 +33,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1590,7 +1590,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/code-conventions-analyzer.lock.yml b/.github/workflows/code-conventions-analyzer.lock.yml index 09a87d5f21..8306bbe917 100644 --- a/.github/workflows/code-conventions-analyzer.lock.yml +++ b/.github/workflows/code-conventions-analyzer.lock.yml @@ -32,7 +32,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1647,7 +1647,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/csa-analysis.lock.yml b/.github/workflows/csa-analysis.lock.yml index 847be785ba..59150cf2f7 100644 --- a/.github/workflows/csa-analysis.lock.yml +++ b/.github/workflows/csa-analysis.lock.yml @@ -32,7 +32,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1593,7 +1593,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/issue-backlog-processor.lock.yml b/.github/workflows/issue-backlog-processor.lock.yml index d5dace3bf9..8da8a7f1a1 100644 --- a/.github/workflows/issue-backlog-processor.lock.yml +++ b/.github/workflows/issue-backlog-processor.lock.yml @@ -33,7 +33,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1615,7 +1615,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/memory-safety-report.lock.yml b/.github/workflows/memory-safety-report.lock.yml index 06242414b3..a2460b8095 100644 --- a/.github/workflows/memory-safety-report.lock.yml +++ b/.github/workflows/memory-safety-report.lock.yml @@ -35,7 +35,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1667,7 +1667,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/smtlib-benchmark-finder.lock.yml b/.github/workflows/smtlib-benchmark-finder.lock.yml index 6ce0fd5357..0250d434a5 100644 --- a/.github/workflows/smtlib-benchmark-finder.lock.yml +++ b/.github/workflows/smtlib-benchmark-finder.lock.yml @@ -32,7 +32,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1594,7 +1594,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/specbot-crash-analyzer.lock.yml b/.github/workflows/specbot-crash-analyzer.lock.yml index db5ec29ba1..219036aeab 100644 --- a/.github/workflows/specbot-crash-analyzer.lock.yml +++ b/.github/workflows/specbot-crash-analyzer.lock.yml @@ -32,7 +32,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1631,7 +1631,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/tactic-to-simplifier.lock.yml b/.github/workflows/tactic-to-simplifier.lock.yml index 9a6eb38dc2..418d2ebd6f 100644 --- a/.github/workflows/tactic-to-simplifier.lock.yml +++ b/.github/workflows/tactic-to-simplifier.lock.yml @@ -32,7 +32,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1599,7 +1599,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/workflow-suggestion-agent.lock.yml b/.github/workflows/workflow-suggestion-agent.lock.yml index a7d48b014d..49cd7630ef 100644 --- a/.github/workflows/workflow-suggestion-agent.lock.yml +++ b/.github/workflows/workflow-suggestion-agent.lock.yml @@ -32,7 +32,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1592,7 +1592,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/zipt-code-reviewer.lock.yml b/.github/workflows/zipt-code-reviewer.lock.yml index 81a7e7e5ed..6bb4ec1f01 100644 --- a/.github/workflows/zipt-code-reviewer.lock.yml +++ b/.github/workflows/zipt-code-reviewer.lock.yml @@ -32,7 +32,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1620,7 +1620,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory From b2ccb2552f2918972d432c713ddf2dc8d127291b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 13:18:39 -0700 Subject: [PATCH 10/48] Bump actions/cache from 6.0.0 to 6.1.0 (#10023) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [//]: # (dependabot-start) ⚠️ **Dependabot is rebasing this PR** ⚠️ Rebasing might not happen immediately, so don't worry if this takes some time. Note: if you make any changes to this PR yourself, they will take precedence over the rebase. --- [//]: # (dependabot-end) Bumps [actions/cache](https://github.com/actions/cache) from 6.0.0 to 6.1.0.
Release notes

Sourced from actions/cache's releases.

v6.1.0

What's Changed

Full Changelog: https://github.com/actions/cache/compare/v6...v6.1.0

Changelog

Sourced from actions/cache's changelog.

6.1.0

Commits
  • 55cc834 Merge pull request #1768 from jasongin/readonly-cache
  • d8cd72f Bump @​actions/cache to v6.1.0 - handle cache write error due to RO token
  • See full diff in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/cache&package-manager=github_actions&previous-version=6.0.0&new-version=6.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-z3-cache.yml | 2 +- .github/workflows/ocaml.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-z3-cache.yml b/.github/workflows/build-z3-cache.yml index 3898184c7e..74b91750a8 100644 --- a/.github/workflows/build-z3-cache.yml +++ b/.github/workflows/build-z3-cache.yml @@ -45,7 +45,7 @@ jobs: - name: Restore or create cache id: cache-z3 - uses: actions/cache@v6.0.0 + uses: actions/cache@v6.1.0 with: path: | build/z3 diff --git a/.github/workflows/ocaml.yaml b/.github/workflows/ocaml.yaml index 10eaa043fb..ce575ba646 100644 --- a/.github/workflows/ocaml.yaml +++ b/.github/workflows/ocaml.yaml @@ -21,7 +21,7 @@ jobs: # Cache ccache (shared across runs) - name: Cache ccache - uses: actions/cache@v6.0.0 + uses: actions/cache@v6.1.0 with: path: ~/.ccache key: ${{ runner.os }}-ccache-${{ github.sha }} @@ -30,7 +30,7 @@ jobs: # Cache opam (compiler + packages) - name: Cache opam - uses: actions/cache@v6.0.0 + uses: actions/cache@v6.1.0 with: path: ~/.opam key: ${{ runner.os }}-opam-${{ matrix.ocaml-version }}-${{ github.sha }} From a07b71cabe42137e93d40937c09a4410d970ab58 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Jul 2026 13:34:37 -0700 Subject: [PATCH 11/48] bugfix for empty ranges Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index d1df4133b1..5de672b1a2 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -4155,10 +4155,6 @@ br_status seq_rewriter::mk_re_range(expr* lo, expr* hi, expr_ref& result) { len = min_length(hi).second; if (len > 1) is_empty = true; - if (max_length(lo) == std::make_pair(true, rational(0))) - is_empty = true; - if (max_length(hi) == std::make_pair(true, rational(0))) - is_empty = true; // A provable length constraint (a bound can never be a single character) // is the only sound way to conclude emptiness for a possibly-symbolic From cc5a2dae5e3efd42ffae50c694e2128b660c5495 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson <5377127+levnach@users.noreply.github.com> Date: Fri, 3 Jul 2026 13:38:56 -0700 Subject: [PATCH 12/48] [snapshot-regression-fix] bv_rewriter: keep (= var concat) intact so DER can eliminate the bound variable (iss-4525/bug-7) (#10034) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fixes the snapshot-regression divergence reported in Z3Prover/bench discussion **#2977** — https://github.com/Z3Prover/bench/discussions/2977 — for benchmark **`iss-4525/bug-7.smt2`**. ## Divergence The benchmark's second query `(check-sat-using (then simplify ctx-solver-simplify))` regressed from `sat` to `unknown`: ```diff --- bug-7.expected.out (expected) +++ produced (current z3) @@ -1,2 +1,2 @@ sat -sat +unknown ``` The input sets `:rewriter.split_concat_eq true` and `:smt.threads 3`, and its core assertion has the shape `(not (forall ((q11 (_ BitVec 21)) ...) (not (= q11 q9 q11 (concat #b01111000010 s)))))`. ## Root cause With `split_concat_eq` enabled, `bv_rewriter::mk_eq_concat` rewrites an equality `(= x (concat ...))` into per-slice **extract** equalities, e.g. `(= (extract 9 0 x) s) ∧ (= (extract 20 10 x) #b01111000010)`. When `x` is a **bound (de Bruijn) variable**, this is harmful: destructive equality resolution (`der.cpp`) only recognises the pattern `(= VAR t)` to eliminate a bound variable. After the split, the variable only appears under `extract`, so DER can no longer eliminate it and a **residual quantifier** survives `simplify`. Discharging that residual quantifier is then left to the solver invoked inside `ctx-solver-simplify`. That solver is where the observable regression actually lives: with `smt.threads ≥ 2` the parallel solver (`smt_parallel.cpp`) now returns `unknown` on the quantified cube instead of solving it (the older, oracle-era parallel solver kept splitting and proved it), so `ctx-solver-simplify` can no longer reduce `(not (forall ...))` to `true` and reports `unknown`. Reproduced with an A/B comparison of an oracle-era build (`sat` / correct) vs. current tip (`unknown`); the sequential path (`threads=1`) is unaffected. Rather than touch the parallel solver — whose current early-exit behaviour is a deliberate termination fix and is risky to revert — this change removes the condition that *creates* the residual quantifier in the first place, so the goal is solved by `simplify` alone and no longer depends on the parallel solver's completeness. ## Fix In `bv_rewriter::is_concat_split_target`, exclude a bare variable from being a split target: ```diff - m_split_concat_eq || + (m_split_concat_eq && !is_var(t)) || m_util.is_concat(t) || m_util.is_numeral(t) || m_util.is_bv_or(t); ``` `split_concat_eq` is only a bit-blasting heuristic, so skipping it for `(= var concat)` is sound and restores DER-based variable elimination. Ground terms are `app` nodes (never `var` nodes), so **default behaviour** (`split_concat_eq` is off by default) **and all ground uses are completely unchanged** — only the explicitly-enabled option with a bound-variable operand is affected. ## Validation - Rebuilt the checkout (`./configure && make -C build`) with the fix. - Re-ran the benchmark with the capture options (`z3 -T:20 inputs/issues/iss-4525/bug-7.smt2`): output is now `sat` / `sat`, an **exact match** to the recorded `bug-7.expected.out` oracle, deterministic across repeated runs. - Confirmed the mechanism: `(apply (then simplify))` with `split_concat_eq` enabled now empties the goal (DER eliminates the bound variable), whereas before it left a residual quantifier. - Confirmed `split_concat_eq` still splits **ground** `(= (concat a b) c)` equalities into extract-equalities (intended behaviour preserved). - Ran the relevant `test-z3` unit suites — all pass: `ast`, `bit_vector`, `fixed_bit_vector`, `simplifier`, `bit_blaster`, `var_subst`, `arith_rewriter`, `seq_rewriter`, `factor_rewriter`, `quant_solve`, `euf_bv_plugin`. Opened as a **draft** for human review. Note the transparency caveat above: the deeper behavioural regression is in the parallel solver's handling of quantified cubes; this patch resolves the reported divergence robustly at the rewriter/DER layer instead of altering that solver. > Generated by [Fix a Z3 snapshot-regression divergence](https://github.com/Z3Prover/bench/actions/runs/28646063005) · 989.2 AIC · ⌖ 40.3 AIC · ⊞ 8.9K · [◷](https://github.com/search?q=repo%3AZ3Prover%2Fz3+%22gh-aw-workflow-id%3A+snapshot-regression-fixer%22&type=pullrequests) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/ast/rewriter/bv_rewriter.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 6f6a121e48..b2ae76dd78 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2678,8 +2678,15 @@ br_status bv_rewriter::mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result) { } bool bv_rewriter::is_concat_split_target(expr * t) const { + // A bare (de Bruijn) variable is deliberately excluded as a split target: + // splitting (= x (concat ...)) into per-slice extract equalities rewrites + // an eliminable (= VAR t) equality into (= (extract .. VAR) t) fragments + // that destructive equality resolution (der) can no longer use to eliminate + // the bound variable, turning solvable quantified goals into residual + // quantifiers. Splitting is only a bit-blasting heuristic, so skipping it + // here is sound and preserves der-based variable elimination. return - m_split_concat_eq || + (m_split_concat_eq && !is_var(t)) || m_util.is_concat(t) || m_util.is_numeral(t) || m_util.is_bv_or(t); From c8e5dd0ca5335a2a95595a5b2b313ee482a495bf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Jul 2026 17:17:27 -0700 Subject: [PATCH 13/48] TPTP: quoted numeric tokens are distinct-objects/functors, not numerals A double-quoted TPTP token such as "138" is a distinct object, and a single-quoted '138' is a functor name; neither is an arithmetic numeral. parse_name() strips the quotes, so the subsequent is_nonempty_digit_string check was converting them into Int literals (then boxed Int->U), mis-encoding distinct objects as equal numbers. Guard both numeral checks (parse_term_primary and the atomic-formula parser) with !m_last_name_quoted so only bare unquoted digit tokens become numerals. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/cmd_context/tptp_frontend.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd_context/tptp_frontend.cpp b/src/cmd_context/tptp_frontend.cpp index f0c931369c..0d5539c6d1 100644 --- a/src/cmd_context/tptp_frontend.cpp +++ b/src/cmd_context/tptp_frontend.cpp @@ -961,7 +961,7 @@ class tptp_parser { if (n == "$true") return expr_ref(m.mk_true(), m); if (n == "$false") return expr_ref(m.mk_false(), m); - if (is_nonempty_digit_string(n)) { + if (!m_last_name_quoted && is_nonempty_digit_string(n)) { return parse_numeral_from_name(n); } @@ -1416,7 +1416,7 @@ class tptp_parser { if (n == "$true") return expr_ref(m.mk_true(), m); if (n == "$false") return expr_ref(m.mk_false(), m); - if (is_nonempty_digit_string(n)) { + if (!m_last_name_quoted && is_nonempty_digit_string(n)) { return parse_numeral_from_name(n); } From 6b7725dcb8c71b59a2ffc87282559b89f203ee7f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Jul 2026 09:06:54 -0700 Subject: [PATCH 14/48] Fix use-after-free in polymorphism substitution over sorts In polymorphism::substitution::operator()(sort*), each substituted sub-sort was held only in a local sort_ref that was destroyed at the end of the loop iteration, while its raw pointer was retained in the parameter vector passed to mk_sort. When the sub-sort's refcount dropped to zero, its memory was freed and then reused by the next allocation, producing a self-referential sort. Structural sort traversals such as has_type_var (which has no cycle detection) then recursed infinitely, manifesting as a stack overflow. Pin each intermediate sub-sort in a sort_ref_vector so it stays alive until after mk_sort has taken its own references. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/ast/polymorphism_util.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ast/polymorphism_util.cpp b/src/ast/polymorphism_util.cpp index 62dd4e9494..555c697b34 100644 --- a/src/ast/polymorphism_util.cpp +++ b/src/ast/polymorphism_util.cpp @@ -39,11 +39,13 @@ namespace polymorphism { } unsigned n = s->get_num_parameters(); vector ps; + sort_ref_vector pin(m); // keep substituted sub-sorts alive until mk_sort below for (unsigned i = 0; i < n; ++i) { auto &p = s->get_parameter(i); if (p.is_ast() && is_sort(p.get_ast())) { - sort_ref s = (*this)(to_sort(p.get_ast())); - ps.push_back(parameter(s.get())); + sort_ref ss = (*this)(to_sort(p.get_ast())); + pin.push_back(ss); + ps.push_back(parameter(ss.get())); } else ps.push_back(p); From 5bd485eb03fecc4366e6384dae9b19c4f35b681a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Jul 2026 10:50:51 -0700 Subject: [PATCH 15/48] TPTP: encode $tType quantification as polymorphism; guard dependent types Fixes soundness/completeness of the TPTP frontend for polymorphic (TF1/TH1) problems, reducing TPTP-v9.2.1 BUG verdicts from 28 to 4. * Treat regular-forall "! [A: $tType] : ..." as genuine type quantification (bind A via mk_type_var) instead of monomorphizing it to the universe sort. This is the standard THF/TH1 way to quantify over types, and monomorphizing it silently prevented theory_polymorphism from instantiating the axioms. * Use the plain smt solver (mk_smt_solver_factory) for problems that contain type variables. The strategic solver's tactic preprocessing eliminates the unconstrained conjecture instance before the core can link it to its polymorphic axiom, yielding a spurious CounterSatisfiable. * Detect value-indexed dependent type families ("T > $tType"), which the parametric-polymorphism encoding cannot represent soundly, and downgrade both sat and unsat verdicts to GaveUp (previously produced unsound Theorems, e.g. SEV600/601/602). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/cmd_context/tptp_frontend.cpp | 431 ++++++++++++++++++++++++++++-- 1 file changed, 407 insertions(+), 24 deletions(-) diff --git a/src/cmd_context/tptp_frontend.cpp b/src/cmd_context/tptp_frontend.cpp index 0d5539c6d1..b4a1189000 100644 --- a/src/cmd_context/tptp_frontend.cpp +++ b/src/cmd_context/tptp_frontend.cpp @@ -12,9 +12,11 @@ #include "ast/array_decl_plugin.h" #include "ast/expr_abstract.h" #include "ast/ast_util.h" +#include "ast/polymorphism_util.h" #include "ast/rewriter/expr_safe_replace.h" #include "cmd_context/cmd_context.h" #include "cmd_context/tptp_frontend.h" +#include "smt/smt_solver.h" #include "solver/solver.h" #include "util/error_codes.h" #include "util/rational.h" @@ -293,6 +295,7 @@ class tptp_parser { sort* m_univ; bool m_has_conjecture = false; unsigned m_dropped_formulas = 0; // axioms/definitions skipped due to encoding errors + bool m_has_dependent_type = false; // a "T > $tType" (value-indexed type family) was declared bool m_last_name_quoted = false; bool m_last_name_dquoted = false; // last parsed name was a double-quoted distinct object // Distinct objects: TPTP double-quoted strings ("...") denote pairwise distinct @@ -306,8 +309,71 @@ class tptp_parser { func_decl_ref_vector m_pinned_decls; // prevents cached func_decls from being freed expr_ref_vector m_pinned_exprs; // prevents bound variable apps from being freed std::unordered_map, sort*>> m_typed_decls; + // Polymorphic (TF1/TH1) declarations: a symbol declared with !>[T:$tType] : ... + // keeps genuine type variables (ast_manager::mk_type_var) in its signature rather + // than monomorphizing them onto the universe sort U. m_decl_tvars records, per + // declared symbol name, the ordered list of type-variable sorts introduced by its + // !> binder (used to consume explicit type arguments at THF @-application sites and + // to instantiate the polymorphic declaration). m_poly_decl_arity records the value + // arity (number of non-type arguments) of such a declaration. + std::unordered_map> m_decl_tvars; + std::unordered_map m_poly_decl_arity; + // Canonical polymorphic root func_decls for each polymorphic symbol. Every concrete + // (or type-variable) use is created as an instance of the shared root via + // ast_manager::instantiate_polymorphic, so that z3's polymorphism engine links the + // instances (e.g. FINITE@real and the axiom's FINITE@A) to one root and instantiates + // type-variable axioms at the concrete types used elsewhere. m_poly_root_ho holds the + // curried-array (THF @-application) shape; m_poly_root_fo the first-order function shape. + std::unordered_map m_poly_root_ho; + std::unordered_map m_poly_root_fo; + // Type variables introduced by the !> binder while parsing a declaration's type. + // An insertion-ordered list of (name, mk_type_var sort): order matters because + // explicit THF type arguments (f @ T1 @ T2 @ ..) are consumed positionally and + // matched tvars[i] := targs[i]. A std::unordered_map would scramble that order. + std::vector> m_type_vars; std::vector> m_bound; bool m_in_at_arg = false; // true when parsing inside @ argument (lambda body stops consuming @) + unsigned m_tvar_counter = 0; // generates fresh, collision-proof polymorphic type-variable names + unsigned m_rec_depth = 0; + char* m_stack_base = nullptr; // approximate stack anchor captured at the outermost parse frame + // Recursive-descent stack guard. The THF fragment of TPTP admits pathologically + // deep nested applications (some ITP problems contain single formulas nested + // hundreds of levels deep). Each recursive parser frame is large (and frame size + // varies widely by construct), so such formulas can exhaust the process stack. + // A fixed recursion-depth cap is fragile: files with large frames overflow at a + // much smaller depth than files with small frames. Instead we measure the actual + // stack consumed (distance of the current frame from an anchor captured at the + // outermost parse frame) and bail out before the OS stack (/STACK:8MB) is + // exhausted. This adapts automatically to the real per-frame size. On overflow we + // raise a parse_error; the enclosing per-formula handler then drops that formula + // (and counts it, downgrading any later "sat" to GaveUp). + // Budget is well below the 8MB stack, leaving margin for un-guarded helper frames. + static const size_t STACK_BUDGET = 6 * 1024 * 1024; + // Hard depth cap as a backstop against genuine non-terminating recursion (parser + // bugs) independent of stack measurement; far higher than any real TPTP nesting. + static const unsigned RECURSION_LIMIT = 100000; + struct rec_guard { + tptp_parser& p; + rec_guard(tptp_parser& p): p(p) { + char local; + char* cur = &local; + if (!p.m_stack_base) + p.m_stack_base = cur; + else { + size_t used = (p.m_stack_base > cur) + ? static_cast(p.m_stack_base - cur) + : static_cast(cur - p.m_stack_base); + if (used > STACK_BUDGET) + throw parse_error("nesting too deep"); + } + if (++p.m_rec_depth > RECURSION_LIMIT) + throw parse_error("nesting too deep"); + } + ~rec_guard() { + if (--p.m_rec_depth == 0) + p.m_stack_base = nullptr; // re-anchor for the next top-level formula + } + }; struct implicit_var_scope { std::unordered_map vars; ptr_vector order; @@ -466,10 +532,145 @@ class tptp_parser { return s; } + // Parse a single explicit type argument following @ at a THF polymorphic + // application site (TH1). Parses exactly one atomic type (a type name or a + // parenthesized mapping type) without consuming the trailing @-application chain, + // which belongs to the value arguments. + sort* parse_type_at_arg() { + if (accept(token_kind::lparen)) { + parsed_type t = parse_type_expr(); + expect(token_kind::rparen, "')'"); + sort* s = t.domain.empty() ? t.range : get_ho_sort(t.domain, t.range); + return s ? s : m_univ; + } + std::string tn = parse_name(); + return get_sort(tn); + } + + // Substitute the polymorphic type variables tvars := targs throughout a template + // signature (domain/range), producing a concrete instance signature. + void instantiate_sig(ptr_vector const& tvars, ptr_vector const& targs, + ptr_vector const& dom_in, sort* rng_in, + ptr_vector& dom_out, sort_ref& rng_out) { + polymorphism::substitution sub(m); + for (unsigned i = 0; i < tvars.size() && i < targs.size(); ++i) + if (tvars[i] != targs[i]) // never insert a self-map: it makes substitution recurse forever + sub.insert(tvars[i], targs[i]); + for (sort* d : dom_in) { + sort_ref s = sub(d); + m_pinned_sorts.push_back(s); + dom_out.push_back(s.get()); + } + rng_out = sub(rng_in); + m_pinned_sorts.push_back(rng_out); + } + static bool is_ttype(sort* s) { return s->get_name() == symbol("$tType"); } + // True if the current token names a type (a builtin type keyword, a declared + // $tType sort, or an in-scope type variable). Used to detect TF1 explicit type + // arguments, which appear as type names in first-order application position. + bool current_is_type_name() const { + if (!is(token_kind::id)) return false; + std::string const& t = m_curr.text; + if (t == "$i" || t == "$o" || t == "$int" || t == "$rat" || t == "$real") + return true; + auto it = m_sorts.find(t); + return it != m_sorts.end() && it->second != nullptr; + } + + // Canonical polymorphic root for the THF curried-array (@-application) shape. + func_decl* poly_root_ho(std::string const& n, ptr_vector const& tdom, sort* trng) { + auto it = m_poly_root_ho.find(n); + if (it != m_poly_root_ho.end()) return it->second; + func_decl* root = m.mk_func_decl(symbol(n), 0, static_cast(nullptr), get_ho_sort(tdom, trng)); + m_pinned_decls.push_back(root); + m_poly_root_ho[n] = root; + return root; + } + + // Canonical polymorphic root for the first-order function shape. + func_decl* poly_root_fo(std::string const& n, ptr_vector const& tdom, sort* trng) { + auto it = m_poly_root_fo.find(n); + if (it != m_poly_root_fo.end()) return it->second; + func_decl* root = m.mk_func_decl(symbol(n), tdom.size(), tdom.data(), trng); + m_pinned_decls.push_back(root); + m_poly_root_fo[n] = root; + return root; + } + + // Instantiate the polymorphic root `root` at a concrete (or type-variable) signature. + // When the root actually carries type variables it is a genuine polymorphic root and + // the instance is registered against it (m_poly_roots) so z3 links the instances; + // otherwise a plain declaration suffices. + func_decl* mk_poly_instance(func_decl* root, unsigned arity, sort* const* dom, sort* rng) { + func_decl* f = root->is_polymorphic() + ? m.instantiate_polymorphic(root, arity, dom, rng) + : m.mk_func_decl(root->get_name(), arity, dom, rng); + m_pinned_decls.push_back(f); + return f; + } + + // Attempt to build an application of a polymorphic (TF1/TH1) declaration `n`. + // Handles three surface forms: + // * TF1 first-order explicit type application f(T.., v..) (fo_targs non-empty) + // * TH1 @-application f @ T.. @ v.. (args empty, @ ahead) + // * first-order type inference from arguments f(v..) with args.size()==value-arity + // On success sets `out` and returns true; otherwise returns false (out untouched). + bool try_poly_application(std::string const& n, expr_ref_vector& args, + ptr_vector const& fo_targs, expr_ref& out) { + auto tvit = m_decl_tvars.find(n); + if (tvit == m_decl_tvars.end()) return false; + ptr_vector const& tvars = tvit->second; + unsigned varity = m_poly_decl_arity[n]; + auto sigit = m_typed_decls.find(mk_typed_key(n, varity)); + if (sigit == m_typed_decls.end()) return false; + ptr_vector const& tdom = sigit->second.first; + sort* trng = sigit->second.second; + + if (!fo_targs.empty()) { + ptr_vector cdom; sort_ref crng(m); + instantiate_sig(tvars, fo_targs, tdom, trng, cdom, crng); + func_decl* f = mk_poly_instance(poly_root_fo(n, tdom, trng), cdom.size(), cdom.data(), crng.get()); + coerce_args(f, args); + out = expr_ref(m.mk_app(f, args.size(), args.data()), m); + return true; + } + + if (args.empty() && is(token_kind::at_tok)) { + ptr_vector targs; + for (unsigned j = 0; j < tvars.size() && is(token_kind::at_tok); ++j) { + next(); // consume @ + targs.push_back(parse_type_at_arg()); + } + ptr_vector cdom; sort_ref crng(m); + instantiate_sig(tvars, targs, tdom, trng, cdom, crng); + sort* ho = get_ho_sort(cdom, crng.get()); + func_decl* f = mk_poly_instance(poly_root_ho(n, tdom, trng), 0, static_cast(nullptr), ho); + out = expr_ref(m.mk_app(f, 0, static_cast(nullptr)), m); + return true; + } + + if (!args.empty() && args.size() == varity) { + polymorphism::substitution sub(m); + bool ok = true; + for (unsigned i = 0; i < varity; ++i) + if (!sub.match(tdom[i], args.get(i)->get_sort())) { ok = false; break; } + if (ok) { + ptr_vector cdom; + for (sort* d : tdom) { sort_ref s = sub(d); m_pinned_sorts.push_back(s); cdom.push_back(s.get()); } + sort_ref crng = sub(trng); m_pinned_sorts.push_back(crng); + func_decl* f = mk_poly_instance(poly_root_fo(n, tdom, trng), varity, cdom.data(), crng.get()); + coerce_args(f, args); + out = expr_ref(m.mk_app(f, args.size(), args.data()), m); + return true; + } + } + return false; + } + static bool is_nonempty_digit_string(std::string const& s) { if (s.empty()) return false; for (char c : s) { @@ -715,6 +916,7 @@ class tptp_parser { // () // ::= $oType | $o | $iType | $i | $tType | $real | $rat | $int parsed_type parse_type_atom() { + rec_guard g(*this); if (accept(token_kind::lparen)) { ptr_vector prod = parse_type_product_raw(); if (accept(token_kind::gt_tok)) { @@ -763,6 +965,7 @@ class tptp_parser { // | * // Product types form the domain in mapping types: (A * B) > C ptr_vector parse_type_product_raw() { + rec_guard g(*this); parsed_type first = parse_type_atom(); if (!first.domain.empty() && first.range == nullptr) { // Already a parenthesized product from nested parens @@ -814,6 +1017,7 @@ class tptp_parser { // ::= | // ::= > parsed_type parse_type_product() { + rec_guard g(*this); parsed_type first = parse_type_atom(); // If atom returned a function type and no '*' follows, return it directly if (!first.domain.empty() && first.range != nullptr && !is(token_kind::star_tok)) { @@ -848,30 +1052,40 @@ class tptp_parser { // ::= !> [] : // Parses: atom, atom > atom, (A * B) > C, !>[X:$tType] : T parsed_type parse_type_expr() { + rec_guard g(*this); // Handle type quantification at the expression level for proper domain/range preservation if (is(token_kind::type_forall_tok) || is(token_kind::type_exists_tok)) { next(); expect(token_kind::lbrack, "'['"); - ptr_vector type_params; if (!accept(token_kind::rbrack)) { do { std::string tv = parse_name(); if (accept(token_kind::colon)) parse_type_expr(); // consume $tType annotation - m_sorts.insert_or_assign(tv, m_univ); - type_params.push_back(m_univ); + // Genuine polymorphic type variable (ast_manager::mk_type_var) rather + // than a monomorphizing collapse onto the universe sort U. This keeps + // distinct type parameters distinct and makes the declaration a proper + // polymorphic root, so uses can be instantiated per concrete type. + // + // mk_type_var interns by name, so the name must be globally unique: + // TPTP reuses generic binder names (A, B, ...) across unrelated + // declarations and in formula-level type quantifiers. If a declaration + // binder shared a name with a use-site type variable, they would alias + // to the same sort and instantiate_sig would build a self-substitution + // A := A, which makes polymorphism::substitution recurse forever. A + // '!'-prefixed counter cannot collide with any TPTP identifier. + std::string fresh = "!" + std::to_string(m_tvar_counter++) + "_" + tv; + sort* tvs = m.mk_type_var(symbol(fresh)); + m_pinned_sorts.push_back(tvs); + m_sorts.insert_or_assign(tv, tvs); + m_type_vars.emplace_back(tv, tvs); } while (accept(token_kind::comma)); expect(token_kind::rbrack, "']'"); } expect(token_kind::colon, "':'"); - parsed_type inner = parse_type_expr(); - // Prepend type params to domain - if (!type_params.empty()) { - ptr_vector full_domain = type_params; - full_domain.append(inner.domain); - return parsed_type(full_domain, inner.range); - } - return inner; + // Type variables are type parameters, not value arguments: do NOT prepend + // them to the domain. The inner mapping type references them directly. + return parse_type_expr(); } parsed_type prod = parse_type_product(); if (accept(token_kind::gt_tok)) { @@ -943,6 +1157,7 @@ class tptp_parser { // Grammar: (same as parse_term, primary productions) expr_ref parse_term_primary() { + rec_guard g(*this); if (accept(token_kind::lparen)) { expr_ref e = parse_formula(false); expect(token_kind::rparen, "')'"); @@ -988,6 +1203,7 @@ class tptp_parser { return expr_ref(get_or_create_implicit_var(n), m); expr_ref_vector args(m); + ptr_vector fo_targs; // TF1 explicit leading type arguments, if any // $ite needs special parsing: first arg is formula, rest are formulas (branches can be equalities) if (n == "$ite") { expect(token_kind::lparen, "'('"); @@ -1003,7 +1219,23 @@ class tptp_parser { } else if (accept(token_kind::lparen)) { if (!accept(token_kind::rparen)) { - do { args.push_back(parse_term()); } while (accept(token_kind::comma)); + // TF1 explicit polymorphic type application: a first-order call to a + // polymorphic symbol supplies its k type arguments first, as type + // names, e.g. mixture(beverage, coffee, S). Parse those k leading + // arguments as sorts rather than terms; the remainder are values. + auto tvit = m_decl_tvars.find(n); + if (tvit != m_decl_tvars.end() && !tvit->second.empty() && current_is_type_name()) { + unsigned ntv = tvit->second.size(); + for (unsigned j = 0; j < ntv; ++j) { + fo_targs.push_back(parse_type_at_arg()); + if (j + 1 < ntv) expect(token_kind::comma, "','"); + } + if (accept(token_kind::comma)) + do { args.push_back(parse_term()); } while (accept(token_kind::comma)); + } + else { + do { args.push_back(parse_term()); } while (accept(token_kind::comma)); + } expect(token_kind::rparen, "')'"); } } @@ -1018,6 +1250,11 @@ class tptp_parser { return op_it->second.builder(args); } + // Polymorphic declaration (declared with !>[T:$tType] : ...): instantiate the + // declaration to the concrete type(s) at the use site rather than boxing onto U. + if (expr_ref pe(m); try_poly_application(n, args, fo_targs, pe)) + return pe; + func_decl* f = mk_decl_or_ho_const(n, args.size(), false); coerce_args(f, args); expr_ref term(args.empty() ? m.mk_const(f) : m.mk_app(f, args.size(), args.data()), m); @@ -1035,6 +1272,7 @@ class tptp_parser { // | @ // @ is THF function application, encoded via array select. expr_ref apply_at(expr_ref e) { + rec_guard g(*this); if (!is(token_kind::at_tok)) return e; // @ corresponds to array select (function application) @@ -1061,6 +1299,7 @@ class tptp_parser { // parenthesized formula, or lambda. Handles the right-operand of . // Parse an argument to @ — can be a term, a formula (negation, quantifier, parens with connectives), or a lambda expr_ref parse_at_arg() { + rec_guard g(*this); if (accept(token_kind::not_tok)) { expr_ref e = parse_at_arg(); return expr_ref(m.mk_not(ensure_bool(e)), m); @@ -1314,6 +1553,7 @@ class tptp_parser { // ::= = | != // Also handles: let-bound name resolution, implicit variable creation. expr_ref parse_atomic_formula(bool is_boolean) { + rec_guard g(*this); if (accept(token_kind::lparen)) { // Check for parenthesized connective used as higher-order term: (~), (&), (|), etc. if (is(token_kind::not_tok) || is(token_kind::and_tok) || is(token_kind::or_tok) || @@ -1492,6 +1732,7 @@ class tptp_parser { } expr_ref_vector args(m); + ptr_vector fo_targs; // TF1 explicit leading type arguments, if any // $ite needs special parsing: first arg is formula, rest are formulas (branches can be equalities) if (n == "$ite") { expect(token_kind::lparen, "'('"); @@ -1507,7 +1748,23 @@ class tptp_parser { } else if (accept(token_kind::lparen)) { if (!accept(token_kind::rparen)) { - do { args.push_back(parse_term()); } while (accept(token_kind::comma)); + // TF1 explicit polymorphic type application: a first-order call to a + // polymorphic symbol supplies its k type arguments first, as type + // names, e.g. mixture(beverage, coffee, S). Parse those k leading + // arguments as sorts rather than terms; the remainder are values. + auto tvit = m_decl_tvars.find(n); + if (tvit != m_decl_tvars.end() && !tvit->second.empty() && current_is_type_name()) { + unsigned ntv = tvit->second.size(); + for (unsigned j = 0; j < ntv; ++j) { + fo_targs.push_back(parse_type_at_arg()); + if (j + 1 < ntv) expect(token_kind::comma, "','"); + } + if (accept(token_kind::comma)) + do { args.push_back(parse_term()); } while (accept(token_kind::comma)); + } + else { + do { args.push_back(parse_term()); } while (accept(token_kind::comma)); + } expect(token_kind::rparen, "')'"); } } @@ -1534,6 +1791,12 @@ class tptp_parser { if (has_lhs) return lhs; + // Polymorphic declaration (declared with !>[T:$tType] : ...). Instead of the + // monomorphizing box coercions that collapse every type parameter onto U, we + // instantiate the declaration to the concrete type(s) at each use. + if (expr_ref pe(m); try_poly_application(n, args, fo_targs, pe)) + return pe; + auto typed = m_typed_decls.find(mk_typed_key(n, args.size())); if (typed != m_typed_decls.end()) { func_decl* f = args.empty() ? mk_decl_or_ho_const(n, 0, false) : mk_decl(n, args.size(), false); @@ -1612,6 +1875,7 @@ class tptp_parser { // ::= ! | ? // Also handles: $ite, $let, lambda (^), parenthesized formulas, and atomic formulas. expr_ref parse_unary_formula(bool is_boolean) { + rec_guard g(*this); if (accept(token_kind::not_tok)) { expr_ref e = parse_unary_formula(true); return expr_ref(m.mk_not(ensure_bool(e)), m); @@ -1696,6 +1960,10 @@ class tptp_parser { ptr_vector vars; std::unordered_map scope; + // $tType binders that we turn into genuine type variables so the body + // becomes a polymorphic axiom. Saved so we can restore the enclosing + // type-variable scope after parsing the body. + std::vector> saved_tvars; if (!accept(token_kind::rbrack)) { do { std::string v = parse_name(); @@ -1709,11 +1977,25 @@ class tptp_parser { s = t.range; } } - // Monomorphize: $tType-sorted variables become U-sorted - // and register them as sorts for subsequent type references + // A $tType-sorted binder is genuine type quantification (THF/TH1 + // "! [A: $tType] : ..." quantifies over types just like "!>"). + // For universal quantifiers keep the type variable (mk_type_var) + // so uses of v in the body are parametric and theory_polymorphism + // instantiates them on demand. Existential type quantification has + // no first-class encoding, so fall back to the universe sort U. + // Register v BEFORE parsing later binders so a subsequent value + // binder "X:A" resolves A to this type variable. if (is_ttype(s)) { - s = m_univ; - m_sorts.insert_or_assign(v, m_univ); + auto it = m_sorts.find(v); + saved_tvars.emplace_back(v, it == m_sorts.end() ? nullptr : it->second); + if (is_forall) { + sort* tvs = m.mk_type_var(symbol(v)); + m_pinned_sorts.push_back(tvs); + m_sorts.insert_or_assign(v, tvs); + } + else + m_sorts.insert_or_assign(v, m_univ); + continue; // not a value-level bound variable } app* c = m.mk_const(symbol(v), s); m_pinned_exprs.push_back(c); @@ -1733,25 +2015,54 @@ class tptp_parser { // and "! [X] : (...) => g" keeps "=> g" outside the quantifier scope. expr_ref body = parse_expr(PREC_EQ, true, is_boolean); m_bound.pop_back(); + // Restore the enclosing type-variable scope. + for (auto const& pr : saved_tvars) { + if (pr.second) m_sorts.insert_or_assign(pr.first, pr.second); + else m_sorts.erase(pr.first); + } + // Pure type quantification (no value binders): the body is already a + // polymorphic axiom, so return it directly. + if (vars.empty()) + return body; return mk_quantifier(is_forall, vars, body); } // Type quantification in formula context: !>[A: $tType, ...] : body - // Erase type variables and parse body as formula if (is(token_kind::type_forall_tok) || is(token_kind::type_exists_tok)) { + bool is_forall = is(token_kind::type_forall_tok); next(); expect(token_kind::lbrack, "'['"); + std::vector> saved; if (!accept(token_kind::rbrack)) { do { std::string tv = parse_name(); if (accept(token_kind::colon)) parse_type_expr(); // consume $tType annotation - m_sorts.insert_or_assign(tv, m_univ); + auto it = m_sorts.find(tv); + saved.emplace_back(tv, it == m_sorts.end() ? nullptr : it->second); + // Universal type quantification is genuine parametric polymorphism: + // keep the type variable (mk_type_var) so the body becomes a + // polymorphic axiom that theory_polymorphism instantiates on demand. + // Existential type quantification has no first-class encoding here, so + // fall back to the universe sort U for it. + if (is_forall) { + sort* tvs = m.mk_type_var(symbol(tv)); + m_pinned_sorts.push_back(tvs); + m_sorts.insert_or_assign(tv, tvs); + } + else + m_sorts.insert_or_assign(tv, m_univ); } while (accept(token_kind::comma)); expect(token_kind::rbrack, "']'"); } expect(token_kind::colon, "':'"); - return parse_formula(is_boolean); + expr_ref body = parse_formula(is_boolean); + // Restore the enclosing type-variable scope. + for (auto const& pr : saved) { + if (pr.second) m_sorts.insert_or_assign(pr.first, pr.second); + else m_sorts.erase(pr.first); + } + return body; } return parse_atomic_formula(is_boolean); @@ -1767,6 +2078,7 @@ class tptp_parser { // | & // Implements a Pratt-style (precedence climbing) parser for binary connectives. expr_ref parse_expr(unsigned min_prec, bool consume_at, bool is_boolean) { + rec_guard g(*this); expr_ref e = parse_unary_formula(is_boolean); return parse_binary_rest(e, min_prec, consume_at); } @@ -1775,6 +2087,7 @@ class tptp_parser { // Split out from parse_expr so callers that have consumed a leading unary unit // (e.g. a '~' immediately after '(') can resume binary-connective parsing. expr_ref parse_binary_rest(expr_ref e, unsigned min_prec, bool consume_at = true) { + rec_guard g(*this); for (;;) { // Handle @ (function application) with highest precedence // But NOT when we're inside a lambda body that's an @ argument @@ -1831,10 +2144,22 @@ class tptp_parser { while (accept(token_kind::lparen)) ++lparen_count; std::string name = parse_name(); expect(token_kind::colon, "':'"); + m_type_vars.clear(); parsed_type t = parse_type_expr(); while (lparen_count-- > 0) expect(token_kind::rparen, "')'"); + // Capture and tear down the type-variable scope introduced by a !> binder. + // The type_var sorts live on in the stored signature; only the name->sort + // bindings are removed so a later declaration reusing the same variable name + // (e.g. Tv0) does not see this declaration's variables. + ptr_vector tvars; + for (auto const& kv : m_type_vars) { + tvars.push_back(kv.second); + m_sorts.erase(kv.first); + } + m_type_vars.clear(); + if (t.domain.empty() && is_ttype(t.range)) { // Sort declaration: give every declared type its own distinct uninterpreted // sort. Collapsing all declared $tType sorts onto a single m_univ is unsound: @@ -1852,13 +2177,28 @@ class tptp_parser { return; } - // Monomorphize: replace $tType in domain/range with m_univ + // Monomorphize: replace any stray $tType in domain/range with m_univ (genuine + // type variables are already mk_type_var sorts and are left intact). for (auto& s : t.domain) { if (is_ttype(s)) s = m_univ; } - if (t.range && is_ttype(t.range)) t.range = m_univ; + if (t.range && is_ttype(t.range)) { + // A declaration "f: T.. > $tType" is a value-indexed type family (a + // dependent type constructor, e.g. "fin: nat > $tType"). Z3's parametric + // polymorphism cannot faithfully encode dependent types: we approximate + // "fin @ N" by a universe element, which is unsound (it can prove a + // conjecture that is only CounterSatisfiable). Flag the problem so any + // sat/unsat verdict is downgraded to GaveUp rather than reported as a + // (possibly spurious) Theorem/CounterSatisfiable. + m_has_dependent_type = true; + t.range = m_univ; + } m_typed_decls.insert_or_assign(mk_typed_key(name, t.domain.size()), std::make_pair(t.domain, t.range)); + if (!tvars.empty()) { + m_decl_tvars[name] = tvars; + m_poly_decl_arity[name] = t.domain.size(); + } } static bool file_exists(std::string const& f) { @@ -1951,7 +2291,23 @@ class tptp_parser { expect(token_kind::comma, "','"); if (role == "type") { - parse_type_decl_formula(); + try { + parse_type_decl_formula(); + } catch (std::exception const& ex) { + // A type declaration that is too deeply nested to parse within the + // stack budget (recursion guard) or otherwise malformed: drop it and + // resync. Dropping a type declaration is counted so a later "sat" + // verdict is downgraded to GaveUp rather than reported as a certified + // model (uses of the undeclared symbol would themselves be dropped). + ++m_dropped_formulas; + std::ostringstream oss; + oss << "skipping type declaration '" << formula_name << "' due to: " << ex.what(); + warning_msg(oss.str().c_str()); + while (!is(token_kind::eof_tok) && !is(token_kind::dot)) + next(); + if (is(token_kind::dot)) next(); + return; + } } else if (role == "logic") { // Modal logic declarations ($modal == [...]) — skip the formula body @@ -2313,6 +2669,10 @@ public: // makes the problem unsatisfiable). unsigned dropped_formulas() const { return m_dropped_formulas; } + // True if the problem declares a value-indexed type family ("T > $tType"), a + // dependent type that our polymorphic encoding cannot represent soundly. + bool has_dependent_type() const { return m_has_dependent_type; } + std::string const& expected_status() const { return m_expected_status; } // Scan TPTP comments for an SZS/Status annotation, e.g. @@ -2370,6 +2730,7 @@ public: }; expr_ref tptp_parser::parse_term() { + rec_guard g(*this); expr_ref e = parse_term_primary(); if (!is(token_kind::at_tok)) return e; // @ corresponds to array select (function application) @@ -2391,6 +2752,7 @@ expr_ref tptp_parser::parse_term() { } expr_ref tptp_parser::parse_formula(bool is_boolean) { + rec_guard g(*this); return parse_expr(PREC_IFF, true, is_boolean); } @@ -2429,17 +2791,38 @@ static unsigned read_tptp_stream(std::istream& in, char const* current_file) { register_on_timeout_proc(on_timeout); try { cmd_context ctx; - ctx.set_solver_factory(mk_smt_strategic_solver_factory()); tptp_parser p(ctx); p.parse_input(in, current_file ? current_file : "."); p.assert_distinct_objects(); + // Polymorphic (TF1/TH1) problems are instantiated on demand by + // theory_polymorphism inside the smt core. The strategic solver's tactic + // preprocessing (e.g. unconstrained-subterm elimination) runs before the + // core and can discard a monomorphic instance that only occurs in the + // conjecture, severing it from its polymorphic axiom. Use the plain smt + // solver in that case so instantiation is not defeated by preprocessing. + if (ctx.m().has_type_vars()) + ctx.set_solver_factory(mk_smt_solver_factory()); + else + ctx.set_solver_factory(mk_smt_strategic_solver_factory()); + // Suppress default check-sat output; TPTP frontend reports SZS status explicitly. std::ostringstream sink; scoped_regular_stream scoped_stream(ctx, sink); TRACE(parser, ctx.get_solver()->display(tout)); ctx.check_sat(0, nullptr); + // A value-indexed type family ("T > $tType") is a dependent type that our + // encoding approximates unsoundly (a universe element stands in for a type). + // Neither an unsat (Theorem/Unsatisfiable) nor a sat (CounterSatisfiable/ + // Satisfiable) verdict can be trusted, so downgrade both to GaveUp. + if (p.has_dependent_type() && + (ctx.cs_state() == cmd_context::css_unsat || ctx.cs_state() == cmd_context::css_sat)) { + std::cout << "% SZS status GaveUp\n"; + std::cout << "% SZS reason problem declares a dependent type family " + "(T > $tType); verdict is not certified\n"; + } + else switch (ctx.cs_state()) { case cmd_context::css_unsat: if (p.has_conjecture()) report_szs_status("Theorem", p.expected_status()); From 6d5e09e2fa19095a940bd323f27e4ce4b0cd6f50 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Jul 2026 11:22:33 -0700 Subject: [PATCH 16/48] polymorphism: prevent cyclic substitutions in unify to fix stack overflow When merging two type substitutions, util::unify(substitution, substitution, substitution) inserted bindings without an occurs-check. Merging maps such as A |-> list(B) and B |-> list(A) produced a self-referential binding B |-> list(list(B)), and applying that substitution recursed forever, causing a stack overflow during the first polymorphic instantiation round. This was exposed by encoding TPTP $tType quantification as polymorphism (8ee8a3cda): mutually-recursive polymorphic types in THF problems (e.g. COM/DAT/ITP Coq-derived files) triggered 60 stack-overflow crashes during check_sat. Add occurs-checks so a binding that would make the substitution cyclic causes the merge to fail (the instantiation is soundly skipped). Values are resolved against the current substitution before insertion, preserving the acyclic invariant. Verified: the 60 previously-crashing TPTP files now terminate cleanly; 92/92 unit tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/ast/polymorphism_util.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/ast/polymorphism_util.cpp b/src/ast/polymorphism_util.cpp index 555c697b34..35054346d1 100644 --- a/src/ast/polymorphism_util.cpp +++ b/src/ast/polymorphism_util.cpp @@ -244,15 +244,25 @@ namespace polymorphism { bool util::unify(substitution const& s1, substitution const& s2, substitution& sub) { sort* v2; - for (auto const& [k, v] : s1) + for (auto const& [k, v] : s1) { + // Guard against building a cyclic substitution (e.g. A |-> list(A)), + // which would make substitution application diverge. Such a binding + // means the two substitutions are not simultaneously unifiable. + if (occurs(k, v)) + return false; sub.insert(k, v); + } for (auto const& [k, v] : s2) { if (sub.find(k, v2)) { if (!sub.unify(sub(v), v2)) return false; } - else - sub.insert(k, sub(v)); + else { + sort_ref vr = sub(v); + if (occurs(k, vr)) + return false; + sub.insert(k, vr); + } } return true; } From 348bb3b6a46275c8b38c3c2250c6541e10028339 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Jul 2026 15:00:10 -0700 Subject: [PATCH 17/48] Fix memory leaks in polymorphism instantiation engine The polymorphism theory routed polymorphic (\) problems through theory_polymorphism, which instantiated axioms during search. Two leaks: 1. In inst::instantiate, insert_ref_map was constructed with an expr_ref argument, so its template parameter D deduced to expr_ref instead of expr*. Trail objects are region-allocated and freed without running destructors, so the embedded expr_ref never released its reference, leaking one AST subtree per instantiation. Pass e_inst.get() so D is expr*, matching the raw hashtable + manual inc_ref/dec_ref pattern. 2. trail_stack's destructor does not call reset(), so level-0 trail items (including the inc_ref balancing entries for m_from_instantiation) were never undone when the theory was destroyed. Added a ~theory_polymorphism destructor that calls m_trail.reset(). Also keeps a defensive alias check in util::unify and a fresh per-iteration substitution in inst::instantiate. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/ast/polymorphism_inst.cpp | 5 +++-- src/ast/polymorphism_util.cpp | 2 ++ src/smt/theory_polymorphism.h | 8 ++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/ast/polymorphism_inst.cpp b/src/ast/polymorphism_inst.cpp index be91c8f5e3..c34f03585c 100644 --- a/src/ast/polymorphism_inst.cpp +++ b/src/ast/polymorphism_inst.cpp @@ -107,13 +107,14 @@ namespace polymorphism { auto const& [tv, fns, substs] = m_instances[e]; for (auto* f2 : fns) { - substitution sub1(m), new_sub(m); + substitution sub1(m); if (!u.unify(f1, f2, sub1)) continue; if (substs->contains(&sub1)) continue; substitutions new_substs; for (auto* sub2 : *substs) { + substitution new_sub(m); if (!u.unify(sub1, *sub2, new_sub)) continue; if (substs->contains(&new_sub)) @@ -128,7 +129,7 @@ namespace polymorphism { new_substs.insert(new_sub1); m_from_instantiation.insert(e_inst); m.inc_ref(e_inst); - t.push(insert_ref_map(m, m_from_instantiation, e_inst)); + t.push(insert_ref_map(m, m_from_instantiation, e_inst.get())); } } for (auto* sub2 : new_substs) { diff --git a/src/ast/polymorphism_util.cpp b/src/ast/polymorphism_util.cpp index 35054346d1..a0c2bad502 100644 --- a/src/ast/polymorphism_util.cpp +++ b/src/ast/polymorphism_util.cpp @@ -244,6 +244,8 @@ namespace polymorphism { bool util::unify(substitution const& s1, substitution const& s2, substitution& sub) { sort* v2; + SASSERT(&s1 != &sub); + SASSERT(&s2 != &sub); for (auto const& [k, v] : s1) { // Guard against building a cyclic substitution (e.g. A |-> list(A)), // which would make substitution application diverge. Such a binding diff --git a/src/smt/theory_polymorphism.h b/src/smt/theory_polymorphism.h index a10f9aa84e..613c1a8dd5 100644 --- a/src/smt/theory_polymorphism.h +++ b/src/smt/theory_polymorphism.h @@ -96,6 +96,14 @@ namespace smt { theory(ctx, poly_family_id), m_inst(ctx.get_manager(), m_trail), m_assumption(ctx.get_manager()) {} + + ~theory_polymorphism() override { + // Undo level-0 trail items (e.g. the inc_ref balancing entries that + // m_inst pushes for m_from_instantiation). trail_stack's destructor + // does not call reset(), so without this the references those items + // hold would leak when the theory is destroyed. + m_trail.reset(); + } void init_model(model_generator & mg) override { } }; From 3d29d816075d6358dc5fd9e7d544dbbe5e0e554d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Jul 2026 20:32:04 -0700 Subject: [PATCH 18/48] Fix TPTP polymorphism crashes in final-check and model checking Root-caused and fixed 261 debug-assertion crashes found by running Z3 across the TPTP benchmarks (-tptp -T:5 model_validate=true): 1. theory_polymorphism::final_check_eh returned FC_DONE after assigning the negation of its (already-true) theory assumption, which creates a conflict. Returning FC_DONE reported l_true while the context was inconsistent, tripping SASSERT(status != l_true || !inconsistent()) in context::restart. Return FC_CONTINUE so conflict resolution turns it into l_false and the normal research loop runs. 2. model_evaluator::get_macro, polymorphic branch: def = subst(def) assigned an expr_ref temporary to a raw expr*&; the temporary freed the freshly substituted term, leaving def dangling (use-after-free during model evaluation). Pin the substituted def in m_pinned, as the as-array path already does. 3. smt_model_checker::add_instance: relax stale SASSERT(!m.is_model_value(sk_term)); get_inv may legitimately return a model value in polymorphic settings, already handled downstream by get_type_compatible_term. Unit tests: 92 passed, 0 failed. All 261 assertion crashes resolved; the 3 remaining files are controlled ERR_PARSER (exit 103) rejections. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/model/model_evaluator.cpp | 4 +++- src/smt/smt_model_checker.cpp | 3 ++- src/smt/theory_polymorphism.h | 12 +++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 8422006677..840c86730e 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -404,7 +404,9 @@ struct evaluator_cfg : public default_rewriter_cfg { polymorphism::substitution subst(m); polymorphism::util util(m); util.unify(f, m.poly_root(f), subst); - def = subst(def); + expr_ref d = subst(def); + m_pinned.push_back(d); + def = d; SASSERT(def != nullptr); } diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index 64dc77eb59..255254fe41 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -222,7 +222,8 @@ namespace smt { expr * sk_term = m_model_finder.get_inv(q, i, sk_value, *cex, sk_term_gen); if (sk_term != nullptr) { TRACE(model_checker, tout << "Found inverse " << mk_pp(sk_term, m) << "\n";); - SASSERT(!m.is_model_value(sk_term)); + // get_inv may return a model value in polymorphic settings; + // this is handled downstream by get_type_compatible_term. max_generation = std::max(sk_term_gen, max_generation); sk_value = sk_term; } diff --git a/src/smt/theory_polymorphism.h b/src/smt/theory_polymorphism.h index 613c1a8dd5..95e0afc136 100644 --- a/src/smt/theory_polymorphism.h +++ b/src/smt/theory_polymorphism.h @@ -67,8 +67,18 @@ namespace smt { } final_check_status final_check_eh(unsigned) override { - if (m_inst.pending()) + if (m_inst.pending()) { + // There are still polymorphic axioms to instantiate. Force the + // solver to fail under the theory assumption so that a new + // research round (see should_research) can assert the new + // instances. Assigning the negation of the (already true) + // assumption creates a conflict, so we must return FC_CONTINUE + // to let conflict resolution turn it into l_false; returning + // FC_DONE here would report l_true while the context is + // inconsistent, violating a core search invariant. ctx.assign(~mk_literal(m_assumption), nullptr); + return FC_CONTINUE; + } return FC_DONE; } From 70df91bc4ea5d132e4b3e6612f9787e3dd93d49a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 4 Jul 2026 12:42:50 -0700 Subject: [PATCH 19/48] fix #10039 and #10032 --- src/smt/smt_model_checker.cpp | 6 ++++-- src/smt/theory_array_full.cpp | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index 255254fe41..72dc51f8f0 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -346,7 +346,8 @@ namespace smt { return false; TRACE(model_checker, tout << "skolems:\n" << sks << "\n";); - flet l(m_aux_context->get_fparams().m_array_fake_support, true); + flet l1(m_aux_context->get_fparams().m_array_fake_support, true); + flet l2(m_aux_context->get_fparams().m_preprocess, true); lbool r = m_aux_context->check(); TRACE(model_checker, tout << "[complete] model-checker result: " << to_sat_str(r) << "\n";); @@ -363,7 +364,8 @@ namespace smt { unsigned num_new_instances = 0; while (true) { - flet l(m_aux_context->get_fparams().m_array_fake_support, true); + flet l1(m_aux_context->get_fparams().m_array_fake_support, true); + flet l2(m_aux_context->get_fparams().m_preprocess, true); lbool r = m_aux_context->check(); TRACE(model_checker, tout << "[restricted] model-checker (" << (num_new_instances+1) << ") result: " << to_sat_str(r) << "\n";); if (r != l_true) diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index e00f4cff93..4ead9d3cf9 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -847,14 +847,14 @@ namespace smt { bool theory_array_full::has_non_beta_as_array() { for (enode* n : m_as_array) { for (enode* p : n->get_parents()) - if (ctx.is_relevant(p) && !ctx.is_beta_redex(p, n)) { + if (ctx.is_relevant(p) && !m.is_eq(p->get_expr()) && !ctx.is_beta_redex(p, n)) { TRACE(array, tout << "not a beta redex " << enode_pp(p, ctx) << "\n"); return true; } } for (enode* n : m_lambdas) for (enode* p : n->get_parents()) - if (ctx.is_relevant(p) && !is_default(p) && !ctx.is_beta_redex(p, n)) { + if (ctx.is_relevant(p) && !is_default(p) && !m.is_eq(p->get_expr()) && !ctx.is_beta_redex(p, n)) { TRACE(array, tout << "lambda is not a beta redex " << enode_pp(p, ctx) << "\n"); return true; } From 208cc56861fbba7a5466e780a6c5d7630ce43f46 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 4 Jul 2026 12:51:52 -0700 Subject: [PATCH 20/48] fix build Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/elim_unconstrained.cpp | 2 ++ src/cmd_context/tptp_frontend.cpp | 24 ++++++++-------------- src/tactic/core/elim_uncnstr_tactic.cpp | 2 +- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 76a622a456..120fe06729 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -425,6 +425,8 @@ void elim_unconstrained::update_model_trail(generic_model_converter& mc, vector< void elim_unconstrained::reduce() { if (!m_config.m_enabled) return; + if (m.has_type_vars()) + return; generic_model_converter_ref mc = alloc(generic_model_converter, m, "elim-unconstrained"); m_inverter.set_model_converter(mc.get()); m_created_compound = true; diff --git a/src/cmd_context/tptp_frontend.cpp b/src/cmd_context/tptp_frontend.cpp index b4a1189000..57ab4c3fc0 100644 --- a/src/cmd_context/tptp_frontend.cpp +++ b/src/cmd_context/tptp_frontend.cpp @@ -8,20 +8,21 @@ #include #include +#include "util/error_codes.h" +#include "util/rational.h" +#include "util/timeout.h" +#include "util/z3_exception.h" #include "ast/arith_decl_plugin.h" #include "ast/array_decl_plugin.h" #include "ast/expr_abstract.h" #include "ast/ast_util.h" #include "ast/polymorphism_util.h" #include "ast/rewriter/expr_safe_replace.h" +#include "solver/solver.h" #include "cmd_context/cmd_context.h" #include "cmd_context/tptp_frontend.h" -#include "smt/smt_solver.h" -#include "solver/solver.h" -#include "util/error_codes.h" -#include "util/rational.h" -#include "util/timeout.h" -#include "util/z3_exception.h" + + bool g_display_statistics = false; bool g_display_model = false; @@ -2796,16 +2797,7 @@ static unsigned read_tptp_stream(std::istream& in, char const* current_file) { p.parse_input(in, current_file ? current_file : "."); p.assert_distinct_objects(); - // Polymorphic (TF1/TH1) problems are instantiated on demand by - // theory_polymorphism inside the smt core. The strategic solver's tactic - // preprocessing (e.g. unconstrained-subterm elimination) runs before the - // core and can discard a monomorphic instance that only occurs in the - // conjecture, severing it from its polymorphic axiom. Use the plain smt - // solver in that case so instantiation is not defeated by preprocessing. - if (ctx.m().has_type_vars()) - ctx.set_solver_factory(mk_smt_solver_factory()); - else - ctx.set_solver_factory(mk_smt_strategic_solver_factory()); + ctx.set_solver_factory(mk_smt_strategic_solver_factory()); // Suppress default check-sat output; TPTP frontend reports SZS status explicitly. std::ostringstream sink; diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 6807cdaa1e..a0eaeead94 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -945,7 +945,7 @@ class elim_uncnstr_tactic : public tactic { collect_occs p; p(*g, m_vars); disable_quantified(g); - if (m_vars.empty() || recfun::util(m()).has_rec_defs()) { + if (m_vars.empty() || recfun::util(m()).has_rec_defs() || m().has_type_vars()) { result.push_back(g.get()); // did not increase depth since it didn't do anything. return; From 0b40cfcd8e954a9f697efb78764f19d7feb34f7d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 4 Jul 2026 14:27:34 -0700 Subject: [PATCH 21/48] stop complaining abot Char in QF_S benchmarks Signed-off-by: Nikolaj Bjorner --- src/solver/check_logic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/check_logic.cpp b/src/solver/check_logic.cpp index bc92c8a30a..e81167f677 100644 --- a/src/solver/check_logic.cpp +++ b/src/solver/check_logic.cpp @@ -469,7 +469,7 @@ struct check_logic::imp { else if (m.is_builtin_family_id(fid)) { // nothing to check } - else if (fid == m_seq_util.get_family_id()) { + else if (fid == m_seq_util.get_family_id() || m_seq_util.is_char(s)) { // nothing to check } else if (fid == m_dt_util.get_family_id() && m_dt) { From 56c366009ab343669bf4b8e4ef5ae2c4dd448871 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 4 Jul 2026 14:34:06 -0700 Subject: [PATCH 22/48] updates to tptp_frontend Signed-off-by: Nikolaj Bjorner --- src/cmd_context/tptp_frontend.cpp | 167 ++++++++++++++++++++++++++---- src/model/model_evaluator.cpp | 9 ++ 2 files changed, 157 insertions(+), 19 deletions(-) diff --git a/src/cmd_context/tptp_frontend.cpp b/src/cmd_context/tptp_frontend.cpp index 57ab4c3fc0..ba04b29200 100644 --- a/src/cmd_context/tptp_frontend.cpp +++ b/src/cmd_context/tptp_frontend.cpp @@ -319,6 +319,13 @@ class tptp_parser { // arity (number of non-type arguments) of such a declaration. std::unordered_map> m_decl_tvars; std::unordered_map m_poly_decl_arity; + // Parametric type constructors declared as "c : ($tType * .. * $tType) > $tType" + // (e.g. list: $tType > $tType, fun: ($tType*$tType) > $tType). Maps the constructor + // name to its type-argument arity. A use "list(A)" / "fun(A,B)" is built as a genuine + // parametric uninterpreted sort (ast_manager::mk_uninterpreted_sort with sort + // parameters), so distinct instantiations stay distinct and can be matched and + // instantiated by the polymorphism substitution engine, instead of collapsing onto U. + std::unordered_map m_sort_ctors; // Canonical polymorphic root func_decls for each polymorphic symbol. Every concrete // (or type-variable) use is created as an instance of the shared root via // ast_manager::instantiate_polymorphic, so that z3's polymorphism engine links the @@ -523,6 +530,22 @@ class tptp_parser { return s; } + // Factory for parametric type-constructor sorts: builds (or reuses) the sort + // "name(targs..)" as a genuine uninterpreted sort carrying its type arguments as + // sort parameters. ast_manager::mk_uninterpreted_sort registers the constructor + // name once (assigning it a stable, non-null user-sort family_id / decl_kind) and + // interns instances, so the same name used at different instantiations yields the + // same constructor with distinct parameters — matchable/substitutable by the + // polymorphism engine (polymorphism::substitution recurses through sort parameters). + sort* mk_type_ctor(std::string const& name, ptr_vector const& targs) { + vector ps; + for (sort* a : targs) + ps.push_back(parameter(static_cast(a ? a : m_univ))); + sort* s = m.mk_uninterpreted_sort(symbol(name), ps.size(), ps.data()); + m_pinned_sorts.push_back(s); + return s; + } + // For higher-order types like ($i > $o), create an uninterpreted sort // Function type A > B is represented as Array(A, B). // Multi-argument A * B > C is represented as Array(A, Array(B, C)) (curried). @@ -545,9 +568,56 @@ class tptp_parser { return s ? s : m_univ; } std::string tn = parse_name(); + // Applied type constructor in explicit type-argument position: list(A), fun(A,B). + // Registered parametric constructors only; others monomorphize onto U. + if (accept(token_kind::lparen)) { + ptr_vector targs; + if (!accept(token_kind::rparen)) { + do { + parsed_type t = parse_type_expr(); + targs.push_back(t.domain.empty() ? t.range : get_ho_sort(t.domain, t.range)); + } while (accept(token_kind::comma)); + expect(token_kind::rparen, "')'"); + } + if (m_sort_ctors.find(tn) != m_sort_ctors.end()) + return mk_type_ctor(tn, targs); + return m_univ; + } return get_sort(tn); } + // Parse a single operand within a type-level @-application chain (c @ A @ B). + // Type application is LEFT-associative: c @ A @ B parses as (c @ A) @ B, i.e. + // the constructor c applied to the arguments A and B. Each operand must be + // parsed WITHOUT greedily consuming the trailing @-chain; a nested application + // used as an operand is parenthesized (e.g. list @ ( product_prod @ A @ B )). + // Calling the full parse_type_atom here instead would let the first operand + // swallow the rest of the chain (A @ B), collapsing product_prod @ A @ B into a + // single-argument product_prod(A@B) and desynchronizing the constructor arity. + sort* parse_type_app_operand() { + if (accept(token_kind::lparen)) { + parsed_type t = parse_type_expr(); + expect(token_kind::rparen, "')'"); + sort* s = t.domain.empty() ? t.range : get_ho_sort(t.domain, t.range); + return s ? s : m_univ; + } + std::string n = parse_name(); + if (accept(token_kind::lparen)) { + ptr_vector targs; + if (!accept(token_kind::rparen)) { + do { + parsed_type t = parse_type_expr(); + targs.push_back(t.domain.empty() ? t.range : get_ho_sort(t.domain, t.range)); + } while (accept(token_kind::comma)); + expect(token_kind::rparen, "')'"); + } + if (m_sort_ctors.find(n) != m_sort_ctors.end()) + return mk_type_ctor(n, targs); + return m_univ; + } + return get_sort(n); + } + // Substitute the polymorphic type variables tvars := targs throughout a template // signature (domain/range), producing a concrete instance signature. void instantiate_sig(ptr_vector const& tvars, ptr_vector const& targs, @@ -579,7 +649,9 @@ class tptp_parser { if (t == "$i" || t == "$o" || t == "$int" || t == "$rat" || t == "$real") return true; auto it = m_sorts.find(t); - return it != m_sorts.end() && it->second != nullptr; + if (it != m_sorts.end() && it->second != nullptr) + return true; + return m_sort_ctors.find(t) != m_sort_ctors.end(); } // Canonical polymorphic root for the THF curried-array (@-application) shape. @@ -939,26 +1011,37 @@ class tptp_parser { return parsed_type(prod, nullptr); } std::string n = parse_name(); - // Handle parameterized type constructors: fun(A, B), product_prod(A, B), etc. + // Parameterized type constructor applied with parentheses: fun(A, B), list(A), ... + // Only names registered as genuine parametric type constructors (all type + // arguments) are built as parametric sorts; a value-indexed family such as + // fin: nat > $tType is NOT a type constructor — its "argument" is a value, so it + // is monomorphized onto U (and already flagged as a dependent type at declaration). if (accept(token_kind::lparen)) { - // Consume type arguments — for monomorphization, we ignore them - // and return the base sort (or m_univ if the constructor result is $tType) + ptr_vector targs; if (!accept(token_kind::rparen)) { - do { parse_type_expr(); } while (accept(token_kind::comma)); + do { + parsed_type t = parse_type_expr(); + targs.push_back(t.domain.empty() ? t.range : get_ho_sort(t.domain, t.range)); + } while (accept(token_kind::comma)); expect(token_kind::rparen, "')'"); } - // Return m_univ as the monomorphized result of any type constructor application + if (m_sort_ctors.find(n) != m_sort_ctors.end()) + return parsed_type(mk_type_ctor(n, targs)); + return parsed_type(m_univ); + } + // Type-level application with @: list @ nat, pair @ A @ B, etc. Build the same + // parametric sort constructor from the @-separated type arguments (registered + // constructors only; otherwise monomorphize onto U). + if (is(token_kind::at_tok)) { + ptr_vector targs; + while (accept(token_kind::at_tok)) { + targs.push_back(parse_type_app_operand()); + } + if (m_sort_ctors.find(n) != m_sort_ctors.end()) + return parsed_type(mk_type_ctor(n, targs)); return parsed_type(m_univ); } sort* s = get_sort(n); - // Handle type-level application with @: list @ nat, pair @ A @ B, etc. - // Monomorphize by consuming all @ arguments and returning m_univ. - if (is(token_kind::at_tok)) { - while (accept(token_kind::at_tok)) { - parse_type_atom(); // consume the argument type - } - return parsed_type(m_univ); - } return parsed_type(s); } @@ -1732,6 +1815,36 @@ class tptp_parser { return expr_ref(m_array.mk_choice(lam), m); } + // Universal (!!) and existential (??) quantifier combinators (TPTP THF): + // !! : !>[A] : ((A > $o) > $o) !! @ A @ P == ! [X:A] : (P @ X) + // ?? : !>[A] : ((A > $o) > $o) ?? @ A @ P == ? [X:A] : (P @ X) + // These are the quantifier-as-operator forms (the files typically also carry + // a defining axiom of exactly this shape). A TH1 use supplies the domain type + // A explicitly first (!! @ A @ P); a TH0 use omits it and A is recovered from + // the predicate's array sort. The predicate P has sort (A > $o), encoded as + // Array(A, $o); it is applied to the fresh bound variable by array select, + // and the whole term is a Boolean quantifier (no boxing coercion). + if ((n == "!!" || n == "??") && is(token_kind::at_tok)) { + bool is_forall = (n == "!!"); + accept(token_kind::at_tok); + sort* dom = nullptr; + if (current_is_type_name()) { + dom = parse_type_at_arg(); + expect(token_kind::at_tok, "'@'"); + } + expr_ref pred = parse_at_arg(); + sort* ps = pred->get_sort(); + if (!dom) + dom = m_array.is_array(ps) ? get_array_domain(ps, 0) : m_univ; + app* c = m.mk_const(symbol(("!q" + std::to_string(m_tvar_counter++)).c_str()), dom); + m_pinned_exprs.push_back(c); + expr_ref body = ensure_bool(expr_ref(m_array.mk_select(pred.get(), c), m)); + app* cs[1] = { c }; + expr_ref q = is_forall ? ::mk_forall(m, 1, cs, body.get()) + : ::mk_exists(m, 1, cs, body.get()); + return q; + } + expr_ref_vector args(m); ptr_vector fo_targs; // TF1 explicit leading type arguments, if any // $ite needs special parsing: first arg is formula, rest are formulas (branches can be equalities) @@ -2178,17 +2291,33 @@ class tptp_parser { return; } + // A declaration whose result is $tType is a type constructor. If every argument + // is itself a type ($tType), it is a parametric type constructor (e.g. + // list: $tType > $tType, fun: ($tType*$tType) > $tType): register it so uses + // "list(A)" build genuine parametric sorts. Only a constructor with a *value* + // argument (e.g. fin: nat > $tType) is a dependent type family, which Z3 cannot + // encode faithfully; flag those so verdicts are downgraded to GaveUp. + if (t.range && is_ttype(t.range)) { + bool all_type_args = true; + for (sort* s : t.domain) + if (!is_ttype(s)) { all_type_args = false; break; } + if (all_type_args) { + m_sort_ctors[name] = t.domain.size(); + return; + } + } + // Monomorphize: replace any stray $tType in domain/range with m_univ (genuine // type variables are already mk_type_var sorts and are left intact). for (auto& s : t.domain) { if (is_ttype(s)) s = m_univ; } if (t.range && is_ttype(t.range)) { - // A declaration "f: T.. > $tType" is a value-indexed type family (a - // dependent type constructor, e.g. "fin: nat > $tType"). Z3's parametric - // polymorphism cannot faithfully encode dependent types: we approximate - // "fin @ N" by a universe element, which is unsound (it can prove a - // conjecture that is only CounterSatisfiable). Flag the problem so any + // A declaration "f: T.. > $tType" with a value argument is a value-indexed + // type family (a dependent type constructor, e.g. "fin: nat > $tType"). Z3's + // parametric polymorphism cannot faithfully encode dependent types: we + // approximate "fin @ N" by a universe element, which is unsound (it can prove + // a conjecture that is only CounterSatisfiable). Flag the problem so any // sat/unsat verdict is downgraded to GaveUp rather than reported as a // (possibly spurious) Theorem/CounterSatisfiable. m_has_dependent_type = true; diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 840c86730e..76de5d6e9b 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -405,6 +405,15 @@ struct evaluator_cfg : public default_rewriter_cfg { polymorphism::util util(m); util.unify(f, m.poly_root(f), subst); expr_ref d = subst(def); + // The polymorphic interpretation body may carry type variables that the + // instance/root unification does not fully resolve (e.g. when the body was + // built with type variables distinct from the root signature's, as happens + // for reified type constructors). If the substituted definition does not + // have the instance's range sort, it would produce an ill-sorted rewrite; + // treat the function as having no usable macro instead (sound: it is then + // evaluated as uninterpreted / by model completion). + if (!d || d->get_sort() != f->get_range()) + return false; m_pinned.push_back(d); def = d; SASSERT(def != nullptr); From 86eae5704679bf7020dd25f642ff9b4d7369b822 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 4 Jul 2026 15:42:30 -0700 Subject: [PATCH 23/48] disable unsound filter on equalities for beta redex completeness Signed-off-by: Nikolaj Bjorner --- src/smt/theory_array_full.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index 4ead9d3cf9..e00f4cff93 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -847,14 +847,14 @@ namespace smt { bool theory_array_full::has_non_beta_as_array() { for (enode* n : m_as_array) { for (enode* p : n->get_parents()) - if (ctx.is_relevant(p) && !m.is_eq(p->get_expr()) && !ctx.is_beta_redex(p, n)) { + if (ctx.is_relevant(p) && !ctx.is_beta_redex(p, n)) { TRACE(array, tout << "not a beta redex " << enode_pp(p, ctx) << "\n"); return true; } } for (enode* n : m_lambdas) for (enode* p : n->get_parents()) - if (ctx.is_relevant(p) && !is_default(p) && !m.is_eq(p->get_expr()) && !ctx.is_beta_redex(p, n)) { + if (ctx.is_relevant(p) && !is_default(p) && !ctx.is_beta_redex(p, n)) { TRACE(array, tout << "lambda is not a beta redex " << enode_pp(p, ctx) << "\n"); return true; } From fdc32d0e60a625ea8c7b3fd12880a0eb7acf6a00 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson <5377127+levnach@users.noreply.github.com> Date: Sat, 4 Jul 2026 17:28:42 -0700 Subject: [PATCH 24/48] Fix inconsistent optimization result with unvalidated LP bound (#10028) (#10040) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #10028. ## Problem Minimizing an integer variable over a problem containing a large `distinct` constraint returned an **inconsistent** result: the reported optimum did not match the returned model, and it was not the true optimum. Reproducer from the issue (a Golomb-ruler problem, true optimum = 55): ```python import z3 n, U = 10, 500 x = [z3.Int(f"x{i}") for i in range(n)] o = z3.Optimize() for xi in x: o.add(xi >= 0, xi <= U) o.add(x[0] == 0) for i in range(n - 1): o.add(x[i] < x[i + 1]) o.add(z3.Distinct([x[j] - x[i] for i in range(n) for j in range(i + 1, n)])) h = o.minimize(x[n - 1]) print(o.check(), o.lower(h), o.upper(h), o.model()[x[n - 1]]) # sat 20 20 500 <-- objective 20, but model has x9 = 500 (and 20 is unsat) ``` ## Root cause A `distinct` with more than 32 arguments is encoded with a fresh uninterpreted sort and function (`smt_internalizer.cpp`), so the objective variable becomes a *shared symbol* whose feasible values depend on EUF as well as arithmetic. The arithmetic relaxation therefore only produces a **hint** for the optimum, which may over-estimate it and be unachievable. Two combined defects: - `opt_solver::maximize_objective` committed the hint into `m_objective_values` **before** validating it with `check_bound`, and never rolled it back when validation failed. `update_objective` only ever *raises* the stored value, so the real (achievable) model value was discarded. - `optsmt::geometric_lex` **ignored** the boolean return value and asserted the blocker derived from the unachievable hint, so the very next `check_sat` was UNSAT and the search terminated prematurely, reporting the bogus bound together with a non-matching model. ## Fix - `opt_solver.cpp`: do not commit the hint before it is validated. On validation failure, `update_objective` now records the actual achievable model value. The no-model early-return keeps its previous behavior. - `optsmt.cpp`: `geometric_lex` now honors the validation result. When the hint could not be validated, it discards the poisoned blocker and tightens from the real model value, so the search keeps converging toward the true optimum. When the hint is valid, the condition reduces to the original expression and behavior is unchanged. After the fix the same reproducer produces consistent, monotonically-improving bounds (325 → 85 → … → 58 → … → 55), and the reported objective always matches the returned model. ## Testing Exact-optimum, fast-terminating checks (all correct): EUF-forced minimum (= 5), `distinct(x, 0..32)` minimize (= 33), Golomb n=8 (= 34), plus basic min/max, real objective, box, lex, pareto, and weighted soft/maxsat. Regression suites, rebuilt in **both Release and Debug**: | Suite | Release | Debug | |-------|---------|-------| | `test-z3 /a` | 92 passed, 0 failed | 92 passed, 0 failed | | z3test `regressions/smt2` (908 files, `model_validate=true`) | 0 failures | 0 failures | Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/opt/opt_solver.cpp | 24 ++++++++++++++++++++---- src/opt/optsmt.cpp | 11 +++++++++-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 586f22698b..6c71bed1af 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -319,12 +319,28 @@ namespace opt { m_models.set(i, m_last_model.get()); TRACE(opt, tout << "maximize " << i << " " << val << " " << m_objective_values[i] << " " << blocker << "\n";); - if (val > m_objective_values[i]) { - m_objective_values[i] = val; - } + // + // Do NOT commit 'val' to m_objective_values yet: 'val' is only an + // optimization hint from the arithmetic relaxation. When the + // objective shares symbols with other theories (e.g. it occurs inside + // an uninterpreted function such as the auxiliary function used to + // encode large 'distinct' constraints) the hint can over-estimate the + // true optimum and may not be achievable by any model. Committing it + // prematurely and then failing validation (check_bound below) would + // leave m_objective_values holding an unachievable bound that callers + // such as optsmt::geometric_lex report as the optimum, together with a + // model that does not attain it (issue #10028). The value is only + // committed after it has been validated, or replaced by the value of + // an actual model in update_objective(). + // - if (!m_last_model) + if (!m_last_model) { + // Without a model there is nothing to validate 'val' against; keep + // the previous behavior of adopting the (possibly infinite) hint. + if (val > m_objective_values[i]) + m_objective_values[i] = val; return true; + } // // retrieve value of objective from current model and update diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index f3ed1aaf91..5a2b4457b0 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -233,7 +233,7 @@ namespace opt { if (is_sat == l_true) m_s->display(tout); ); if (is_sat == l_true) { - m_s->maximize_objective(obj_index, bound); + bool bound_valid = m_s->maximize_objective(obj_index, bound); m_s->get_model(m_model); SASSERT(m_model); inf_eps obj = m_s->saved_objective_value(obj_index); @@ -250,7 +250,14 @@ namespace opt { else { ++steps; } - if (delta_per_step > rational::one() || (obj == last_objective && is_int)) { + // When maximize_objective could not validate its arithmetic + // hint (bound_valid == false), the blocker it produced refers to + // that unachievable hint and must not be used. 'obj' now holds + // the value of an actual model, so replace the blocker with a + // model-derived tightening so the search keeps making progress + // toward the true optimum instead of terminating prematurely + // (issue #10028). + if (!bound_valid || delta_per_step > rational::one() || (obj == last_objective && is_int)) { m_s->push(); ++num_scopes; bound = m_s->mk_ge(obj_index, obj + inf_eps(delta_per_step)); From 557a0cadabbdaf2538b9e5574c0d173401e58e48 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson <5377127+levnach@users.noreply.github.com> Date: Sat, 4 Jul 2026 17:32:46 -0700 Subject: [PATCH 25/48] opt_solver: clarify model member names (#10042) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Small readability refactor in `opt_solver`, no behavioral change. ## Rename - `m_models` → `m_objective_models` - `m_last_model` → `m_model` ## Rationale `m_models` is the per-objective vector of witnessing models, indexed by the objective index `i` exactly like `m_objective_vars`, `m_objective_values`, and `m_objective_terms`. It was the only member of that parallel family not following the `m_objective_*` naming, so `m_objective_models` makes the intent self-documenting. `m_last_model` is the single, transient model most recently obtained from the context and handed back to callers via `get_model_core`. Renaming it to `m_model` reads more naturally, and the two now-distinct names (`m_model` vs `m_objective_models`) avoid the previous one-letter `m_model`/`m_models` clash hazard. Both are private members of `opt_solver`, so the change is fully self-contained within `opt_solver.{h,cpp}`. A stale TRACE label ("last model") was updated to "current model" to match. ## Testing - Builds clean (CMake/Ninja, Release). - `test-z3 /a`: 92 passed, 0 failed. - Spot-checked optimization behavior (single-objective minimize with large `distinct`, box mode) — unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/opt/opt_solver.cpp | 62 +++++++++++++++++++++--------------------- src/opt/opt_solver.h | 6 ++-- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 6c71bed1af..eb8b4dd6cb 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -81,7 +81,7 @@ namespace opt { } void opt_solver::assert_expr_core(expr * t) { - m_last_model = nullptr; + m_model = nullptr; if (has_quantifiers(t)) { m_params.m_relevancy_lvl = 2; } @@ -178,7 +178,7 @@ namespace opt { verbose_stream().flush();); } lbool r; - m_last_model = nullptr; + m_model = nullptr; if (m_first && num_assumptions == 0 && m_context.get_scope_level() == 0) { r = m_context.setup_and_check(); } @@ -187,9 +187,9 @@ namespace opt { } r = adjust_result(r); if (r == l_true) { - m_context.get_model(m_last_model); - if (m_models.size() == 1) - m_models.set(0, m_last_model.get()); + m_context.get_model(m_model); + if (m_objective_models.size() == 1) + m_objective_models.set(0, m_model.get()); } m_first = false; if (dump_benchmarks()) { @@ -232,15 +232,15 @@ namespace opt { // Save results before popping inf_eps val = m_objective_values[i]; model_ref mdl; - if (m_models[i]) - mdl = m_models[i]; + if (m_objective_models[i]) + mdl = m_objective_models[i]; m_context.pop(1); // Restore the computed values after pop m_objective_values[i] = val; if (mdl) - m_models.set(i, mdl.get()); + m_objective_models.set(i, mdl.get()); // The baseline model may witness a greater value than the LP // optimizer returned, e.g. for non-linear objectives like mod @@ -260,8 +260,8 @@ namespace opt { expr_ref obj_val = (*baseline_model)(m_objective_terms.get(i)); if (a.is_numeral(obj_val, r) && inf_eps(r) > m_objective_values[i]) { m_objective_values[i] = inf_eps(r); - if (!m_models[i]) - m_models.set(i, baseline_model.get()); + if (!m_objective_models[i]) + m_objective_models.set(i, baseline_model.get()); expr* obj = m_objective_terms.get(i); if (a.is_int(obj)) blocker = a.mk_ge(obj, a.mk_numeral(r + 1, true)); @@ -301,7 +301,7 @@ namespace opt { bool opt_solver::maximize_objective(unsigned i, expr_ref& blocker) { smt::theory_var v = m_objective_vars[i]; bool has_shared = false; - m_last_model = nullptr; + m_model = nullptr; blocker = nullptr; // // compute an optimization hint. @@ -310,13 +310,13 @@ namespace opt { // relative to other theories. // inf_eps val = get_optimizer().maximize(v, blocker, has_shared); - m_context.get_model(m_last_model); + m_context.get_model(m_model); inf_eps val2; has_shared = true; TRACE(opt, tout << (has_shared?"has shared":"non-shared") << " " << val << " " << blocker << "\n"; - if (m_last_model) tout << *m_last_model << "\n";); - if (!m_models[i]) - m_models.set(i, m_last_model.get()); + if (m_model) tout << *m_model << "\n";); + if (!m_objective_models[i]) + m_objective_models.set(i, m_model.get()); TRACE(opt, tout << "maximize " << i << " " << val << " " << m_objective_values[i] << " " << blocker << "\n";); // @@ -334,7 +334,7 @@ namespace opt { // an actual model in update_objective(). // - if (!m_last_model) { + if (!m_model) { // Without a model there is nothing to validate 'val' against; keep // the previous behavior of adopting the (possibly infinite) hint. if (val > m_objective_values[i]) @@ -348,7 +348,7 @@ namespace opt { // auto update_objective = [&]() { rational r; - expr_ref value = (*m_last_model)(m_objective_terms.get(i)); + expr_ref value = (*m_model)(m_objective_terms.get(i)); if (arith_util(m).is_numeral(value, r) && r > m_objective_values[i]) m_objective_values[i] = inf_eps(r); }; @@ -369,12 +369,12 @@ namespace opt { } else if (m_context.get_context().update_model(has_shared)) { TRACE(opt, tout << "updated\n";); - m_last_model = nullptr; - m_context.get_model(m_last_model); - if (!m_last_model) + m_model = nullptr; + m_context.get_model(m_model); + if (!m_model) return false; else if (!has_shared || val == current_objective_value(i)) - m_models.set(i, m_last_model.get()); + m_objective_models.set(i, m_model.get()); else if (!check_bound()) return false; } @@ -385,8 +385,8 @@ namespace opt { tout << "objective: " << mk_pp(m_objective_terms.get(i), m) << "\n"; tout << "maximal value: " << val << "\n"; tout << "new condition: " << blocker << "\n"; - if (m_models[i]) model_smt2_pp(tout << "update model:\n", m, *m_models[i], 0); - if (m_last_model) model_smt2_pp(tout << "last model:\n", m, *m_last_model, 0); + if (m_objective_models[i]) model_smt2_pp(tout << "update model:\n", m, *m_objective_models[i], 0); + if (m_model) model_smt2_pp(tout << "current model:\n", m, *m_model, 0); }); return true; } @@ -398,8 +398,8 @@ namespace opt { lbool is_sat = m_context.check(0, nullptr); is_sat = adjust_result(is_sat); if (is_sat == l_true) { - m_context.get_model(m_last_model); - m_models.set(i, m_last_model.get()); + m_context.get_model(m_model); + m_objective_models.set(i, m_model.get()); } pop_core(1); return is_sat == l_true; @@ -422,13 +422,13 @@ namespace opt { } void opt_solver::get_model_core(model_ref & m) { - if (m_last_model.get()) { - m = m_last_model.get(); + if (m_model.get()) { + m = m_model.get(); return; } - for (unsigned i = m_models.size(); i-- > 0; ) { - auto* mdl = m_models[i]; + for (unsigned i = m_objective_models.size(); i-- > 0; ) { + auto* mdl = m_objective_models[i]; if (mdl) { TRACE(opt, tout << "get " << i << "\n" << *mdl << "\n";); m = mdl; @@ -436,7 +436,7 @@ namespace opt { } } TRACE(opt, tout << "get last\n";); - m = m_last_model.get(); + m = m_model.get(); } proof * opt_solver::get_proof_core() { @@ -478,7 +478,7 @@ namespace opt { m_objective_vars.push_back(v); m_objective_values.push_back(inf_eps(rational::minus_one(), inf_rational())); m_objective_terms.push_back(term); - m_models.push_back(nullptr); + m_objective_models.push_back(nullptr); return v; } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index d11e975202..4af90f7181 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -73,10 +73,10 @@ namespace opt { generic_model_converter& m_fm; progress_callback * m_callback; symbol m_logic; - model_ref m_last_model; + model_ref m_model; svector m_objective_vars; vector m_objective_values; - sref_vector m_models; + sref_vector m_objective_models; expr_ref_vector m_objective_terms; bool m_dump_benchmarks; static unsigned m_dump_count; @@ -171,7 +171,7 @@ namespace opt { void update_from_baseline_model(unsigned i, model_ref& baseline_model, expr_ref& blocker); inf_eps const & saved_objective_value(unsigned obj_index); inf_eps current_objective_value(unsigned obj_index); - model* get_model_idx(unsigned obj_index) { return m_models[obj_index]; } + model* get_model_idx(unsigned obj_index) { return m_objective_models[obj_index]; } bool was_unknown() const { return m_was_unknown; } From eccdffa78168015d5d21564c310c66ca2db0dd8e Mon Sep 17 00:00:00 2001 From: Lev Nachmanson <5377127+levnach@users.noreply.github.com> Date: Sun, 5 Jul 2026 09:15:19 -0700 Subject: [PATCH 26/48] [snapshot-regression-fix] opt: preserve strict supremum/infimum optima with infinitesimal component (#10052) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fixes a Z3 optimization regression where maximizing a real objective under a **strict** inequality returned a plain feasible model value instead of the strict supremum. Originating discussion: https://github.com/Z3Prover/bench/discussions/3053 Benchmark: `iss-5720/bug-1.smt2` (in `Z3Prover/bench`) ```smt2 (declare-const r Real) (assert (< r 1)) (maximize r) (check-sat) (get-objectives) ``` The optimum of `r` subject to `r < 1` is the strict supremum `1 - epsilon`, which the recorded oracle expects. Current z3 instead reports the feasible point `0`. ## Divergence ```diff --- bug-1.expected.out (expected) +++ produced (current z3) @@ -1,4 +1,4 @@ sat (objectives - (r (+ 1.0 (* (- 1.0) epsilon))) + (r 0) ) ``` ## Root cause Regression from commit `fdc32d0e6` ("Fix inconsistent optimization result with unvalidated LP bound", #10028). That change stopped committing the LP optimization hint `val` to `m_objective_values` up front in `opt_solver::maximize_objective`, deferring the commit until `check_bound()` validates it. Its goal is to reject **plain-rational** over-estimates produced when the objective shares symbols with other theories (e.g. the auxiliary uninterpreted function used to encode large `distinct` constraints); those over-estimates have a **zero** infinitesimal. For a strict real supremum/infimum the hint has a **non-zero** infinitesimal (here `val = 1 - epsilon`). `check_bound()` can never validate it, because `opt_solver::mk_ge` drops the negative infinitesimal (mathematically, `r >= 1 - epsilon` is equivalent over the reals to `r >= 1`), turning the validation bound into the unsatisfiable `r >= 1` given `r < 1`. Validation therefore fails, `maximize_objective` returns `false`, and `m_objective_values` is left holding the strictly smaller current **model** value (`0`), which `optsmt::geometric_lex` then reports as the optimum. ## Fix `src/opt/opt_solver.cpp`, `maximize_objective`: restore the pre-#10028 eager commit of the hint, **scoped to finite values with a non-zero infinitesimal**: ```cpp if (val.is_finite() && !val.get_infinitesimal().is_zero() && val > m_objective_values[i]) m_objective_values[i] = val; ``` A finite value with a non-zero infinitesimal is a strict optimum that no concrete model can attain and that `check_bound()` cannot validate, so the arithmetic hint is authoritative and must be preserved. Plain-rational (zero-infinitesimal) values — including **all integer objectives** and the `#10028` shared-symbol over-estimates — do not enter this branch and continue through the deferred-commit validation path unchanged, so `#10028` is structurally preserved. The change does not alter control flow or the return value, so the lex/box drivers behave as before. ## Validation Built the patched `./z3` checkout (`./configure && make -C build -j$(nproc)`) and re-ran the benchmark with the same options the snapshot capture uses: ``` $ ./build/z3 -T:20 inputs/issues/iss-5720/bug-1.smt2 sat (objectives (r (+ 1.0 (* (- 1.0) epsilon))) ) ``` This is a **byte-exact match** with the recorded `bug-1.expected.out` oracle. Additional before/after checks on the rebuilt binary (baseline = current nightly, unpatched): | case | baseline | patched | | --- | --- | --- | | single strict-real max `r<1` | `r=0` ❌ | `r=1-eps` ✅ (target) | | single strict-real min `r>1` | `r=0` ❌ | `r=1+eps` ✅ | | non-strict real max `r<=1` | `r=1` ✅ | `r=1` ✅ | | integer max `x<10` | `x=9` ✅ | `x=9` ✅ | | bounded strict `2= 1-epsilon` (which `mk_ge` reduces to `r >= 1`) contradicts `r < 1`. This corner is already mishandled by the current nightly (it returns `r=0`) and is not what discussion #3053 reports; this patch does not attempt to redefine that semantics. It changes only how that corner manifests, while fixing the reported single-objective divergence and all well-defined cases above. Draft for human review. > Generated by [Fix a Z3 snapshot-regression divergence](https://github.com/Z3Prover/bench/actions/runs/28733642068) · 691.9 AIC · ⌖ 44.2 AIC · ⊞ 8.9K · [◷](https://github.com/search?q=repo%3AZ3Prover%2Fz3+%22gh-aw-workflow-id%3A+snapshot-regression-fixer%22&type=pullrequests) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/opt/opt_solver.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index eb8b4dd6cb..88e81184fd 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -342,6 +342,24 @@ namespace opt { return true; } + // + // A finite hint with a non-zero infinitesimal is a strict + // supremum/infimum (e.g. maximizing r subject to r < 1 yields + // 1 - epsilon). No concrete model can attain such a value, and + // check_bound() below cannot validate it either: opt_solver::mk_ge + // drops the negative infinitesimal, turning the bound r >= 1 - epsilon + // into the unsatisfiable r >= 1. Commit it eagerly here so that it is + // neither overwritten by the strictly smaller current model value in + // update_objective() nor lost when validation fails and this routine + // returns false (callers such as optsmt::geometric_lex then report + // m_objective_values as the optimum). This restores the pre-#10028 + // behavior for strict optima while leaving the plain-rational + // (zero-infinitesimal) over-estimates that #10028 fixed to the + // deferred-commit logic below. + // + if (val.is_finite() && !val.get_infinitesimal().is_zero() && val > m_objective_values[i]) + m_objective_values[i] = val; + // // retrieve value of objective from current model and update // current optimal. From 165f79a05175464d7ccb824b07e5dbf02a731456 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Jul 2026 12:51:33 -0700 Subject: [PATCH 27/48] handle lambda equalities --- src/smt/theory_array_base.cpp | 11 +++++++++++ src/smt/theory_array_full.cpp | 25 ++++++++++++++++++++++++- src/smt/theory_array_full.h | 1 + 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index 9f6841760d..1d25d4893d 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -23,6 +23,7 @@ Revision History: #include "smt/smt_model_generator.h" #include "model/func_interp.h" #include "ast/ast_smt2_pp.h" +#include "ast/pattern/pattern_inference.h" namespace smt { @@ -413,6 +414,16 @@ namespace smt { expr * eq = m.mk_eq(sel1, sel2); expr_ref q(m.mk_forall(dimension, sorts.data(), names.data(), eq), m); ctx.get_rewriter()(q); + // The select terms are beta-reduced away by the rewriter, so the + // resulting quantifier carries no patterns. Infer patterns so that the + // e-matching engine can instantiate it (dynamically generated + // quantifiers bypass the pre-processing pattern inference pass). + if (is_forall(q) && to_quantifier(q)->get_num_patterns() == 0) { + pattern_inference_rw infer(m, ctx.get_fparams()); + expr_ref q2(m); + infer(q, q2); + q = q2; + } if (!ctx.b_internalized(q)) { ctx.internalize(q, true); } diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index e00f4cff93..865d5bca95 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -354,6 +354,14 @@ namespace smt { add_as_array(v1, n); for (enode* n : d2->m_lambdas) add_lambda(v1, n); + // When a lambda is equated to another array term, assert the congruence + // axiom n1 = n2 => forall k . select(n1, k) = select(n2, k). + // This lets positive equalities between lambdas (which have no select + // parents of their own) produce usable consequences. + enode* n1 = get_enode(v1); + enode* n2 = get_enode(v2); + if (is_lambda(n1->get_expr()) || is_lambda(n2->get_expr())) + assert_congruent(n1, n2); TRACE(array, tout << pp(get_enode(v1), m) << "\n"; tout << pp(get_enode(v2), m) << "\n"; @@ -854,13 +862,28 @@ namespace smt { } for (enode* n : m_lambdas) for (enode* p : n->get_parents()) - if (ctx.is_relevant(p) && !is_default(p) && !ctx.is_beta_redex(p, n)) { + if (ctx.is_relevant(p) && !is_default(p) && !ctx.is_beta_redex(p, n) && !is_congruent_eq(p)) { TRACE(array, tout << "lambda is not a beta redex " << enode_pp(p, ctx) << "\n"); return true; } return false; } + /** + \brief A relevant equality between two array terms whose roots coincide is + handled by the congruence axiom asserted on merge (see merge_eh / + assert_congruent). Such an equality parent does not make a lambda an + unsupported (non beta-redex) occurrence, so it should not trigger a + final-check give-up. + */ + bool theory_array_full::is_congruent_eq(enode* p) { + expr* a = nullptr, * b = nullptr; + if (!m.is_eq(p->get_expr(), a, b)) + return false; + return is_array_sort(p->get_arg(0)) && + p->get_arg(0)->get_root() == p->get_arg(1)->get_root(); + } + bool theory_array_full::instantiate_parent_stores_default(theory_var v) { SASSERT(v != null_theory_var); diff --git a/src/smt/theory_array_full.h b/src/smt/theory_array_full.h index 8ea160507f..c9d2a41d70 100644 --- a/src/smt/theory_array_full.h +++ b/src/smt/theory_array_full.h @@ -92,6 +92,7 @@ namespace smt { enode_vector m_as_array; enode_vector m_lambdas; bool has_non_beta_as_array(); + bool is_congruent_eq(enode* p); bool instantiate_select_const_axiom(enode* select, enode* cnst); bool instantiate_select_as_array_axiom(enode* select, enode* arr); From e1f99b569df24e7eebee6f79617d61effa690fa5 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson <5377127+levnach@users.noreply.github.com> Date: Sun, 5 Jul 2026 13:05:38 -0700 Subject: [PATCH 28/48] [snapshot-regression-fix] seq_rewriter: re.range with a provably-empty bound must be the empty language (#10047) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fixes a Z3 output regression detected by the `Z3Prover/bench` snapshot-regression corpus. - **Originating discussion:** https://github.com/Z3Prover/bench/discussions/3050 - **Benchmark:** `iss-5134/small.smt2` (`inputs/issues/iss-5134/small.smt2` in `Z3Prover/bench`) - **Kind:** `diff` — recorded oracle vs. current nightly z3 (`z3-4.17.0-x64-glibc-2.39`) ## Divergence The benchmark constrains a string `a` using a regex that contains `(re.range "" )`: ```smt2 (declare-fun a () String) (assert (str.in_re a (re.* (re.union (str.to_re "b") (str.to_re (ite (str.in_re a (re.* (re.range "" (ite (str.in_re a (str.to_re "")) "" a)))) "" "a")))))) (assert (not (str.in_re a (re.* (str.to_re ""))))) (check-sat) (get-model) ``` Recorded oracle (**expected**) vs. current z3 (**current**): ```diff -sat -( - (define-fun a () String - "a") -) +unknown +(error "line 7 column 10: model is not available") ``` ## Root cause Per SMT-LIB, `re.range` over an argument that is **not a single character** denotes the empty language, so `(re.range "" X)` is `re.none` regardless of `X` (the lower bound `""` is the empty string). Before the *"Derive with ranges"* refactor (#9963 / #9965), `seq_rewriter::mk_re_range` recognised this through several emptiness checks, including a concrete non-single-character test and a `max_length == 0` test: ```cpp if (str().is_string(lo, slo) && slo.length() != 1) is_empty = true; if (max_length(lo) == std::make_pair(true, rational(0))) is_empty = true; if (max_length(hi) == std::make_pair(true, rational(0))) is_empty = true; ``` The refactor rewrote `mk_re_range` and kept only the `min_length(..) > 1` emptiness test (a bound provably **≥ 2** characters). That misses a bound of length **exactly 0**: an empty-string bound has `min_length == 0`, so it is no longer detected as empty, and `mk_re_range` returns `BR_FAILED`, leaving `(re.range "" X)` symbolic. The new range-aware derivative engine (`seq_derive.cpp`) then produces a *stuck* derivative for such a range (its `is_unit_string("")` test fails), so the sequence theory can no longer decide membership and the solver answers `unknown` / "model is not available". ## Fix Restore the sound emptiness check the refactor dropped — a bound whose `max_length` is provably `0` can never be a single character, so the range is empty: ```cpp // A bound that is provably of length 0 (e.g. the empty string "") can // likewise never be a single character, so the range is empty. Unlike a // symbolic bound, max_length == 0 is a provable emptiness fact, so this is // sound (it is never true for a model-dependent bound such as a variable). if (max_length(lo) == std::make_pair(true, rational(0))) is_empty = true; if (max_length(hi) == std::make_pair(true, rational(0))) is_empty = true; ``` This does **not** reintroduce the unsoundness the refactor guarded against: `max_length == (true, 0)` is a *provable* emptiness fact and is never true for a model-dependent (symbolic) bound, so `(re.range x x)` is still correctly left symbolic (it denotes `{x}` whenever `x` is a single character). ## Validation Built the patched `./z3` checkout (`./configure && make -C build`) and re-ran the benchmark with the option the snapshot capture uses (`-T:20`): - **Before the fix:** `z3 -T:20 small.smt2` → `unknown` + `(error "... model is not available")` — reproduces the divergence. - **After the fix:** `z3 -T:20 small.smt2` → `sat` + `(define-fun a () String "a")` — **exactly matches** the recorded oracle. Additional checks with the rebuilt binary: - Sibling benchmarks `iss-5134/bug.smt2` and `iss-5134/small-2.smt2` still match their oracles. - Symbolic bound not over-collapsed: `(str.in_re "a" (re.range x x))` → `sat` (x = "a"). - `(re.range "" "a")` is the empty language: `(str.in_re "a" (re.range "" "a"))` and `(str.in_re "" (re.range "" "a"))` → `unsat`. - Ordinary ranges unaffected: `"b" ∈ (re.range "a" "c")` sat, `"d" ∈ (re.range "a" "c")` unsat, `(re.range "a" "a")` singleton. > Generated by [Fix a Z3 snapshot-regression divergence](https://github.com/Z3Prover/bench/actions/runs/28731229299) · 592.3 AIC · ⌖ 39.1 AIC · ⊞ 8.9K · [◷](https://github.com/search?q=repo%3AZ3Prover%2Fz3+%22gh-aw-workflow-id%3A+snapshot-regression-fixer%22&type=pullrequests) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/ast/rewriter/seq_rewriter.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 5de672b1a2..79c542f06b 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -4155,6 +4155,14 @@ br_status seq_rewriter::mk_re_range(expr* lo, expr* hi, expr_ref& result) { len = min_length(hi).second; if (len > 1) is_empty = true; + // A bound that is provably of length 0 (e.g. the empty string "") can + // likewise never be a single character, so the range is empty. Unlike a + // symbolic bound, max_length == 0 is a provable emptiness fact, so this is + // sound (it is never true for a model-dependent bound such as a variable). + if (max_length(lo) == std::make_pair(true, rational(0))) + is_empty = true; + if (max_length(hi) == std::make_pair(true, rational(0))) + is_empty = true; // A provable length constraint (a bound can never be a single character) // is the only sound way to conclude emptiness for a possibly-symbolic From f37b43592363d6ecaba8316d0fed0a8836deb160 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson <5377127+levnach@users.noreply.github.com> Date: Mon, 6 Jul 2026 10:39:22 -0700 Subject: [PATCH 29/48] [coz3-deepperf-fix] Batch fixed-column bound-witness linearization per row in lar_solver (#10029) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Summary `lp_bound_propagator::explain_fixed_in_row` explained every fixed column of a row independently, calling `lar_solver::explain_fixed_column` once per fixed column (`src/math/lp/lar_solver.cpp`). Each such call linearizes the lower- and upper-bound witnesses of a single column — a BFS over the `u_dependency` DAG using the dependency manager's mark bits — and inserts every reached leaf constraint into the `explanation`. Fixed columns of the same row routinely share large portions of their bound-witness sub-DAGs (common ancestor constraints). The per-column scheme therefore re-traverses those shared sub-DAGs and re-inserts their leaves once for *every* column, with an independent mark/unmark cycle per column. ### Change Add `lar_solver::explain_fixed_in_row(row, ex)`, which collects the lower/upper witnesses of all fixed columns in the row and linearizes them together in a single `u_dependency_manager::linearize` pass. `lp_bound_propagator::explain_fixed_in_row` and `explain_fixed_in_row_and_get_base` now delegate to it; the base-column lookup in the latter is unchanged. `explain_fixed_column` is kept for its single-column caller. ### Why it is correct `explanation` is a set — `push_back` deduplicates. Dependency reachability is monotone, so the union of the per-column leaf sets equals the leaf set of the union of all roots: the batched pass yields exactly the same explanation. The manager's mark bits guarantee each shared sub-DAG node is visited once, and the `linearize(ptr_vector, ...)` overload already skips null/duplicate roots. ### Complexity For a row with `N` fixed columns: - before: `O(Σ_j |witness-DAG(j)|)` traversal + `O(Σ_j leaves(j))` set insertions, with `N` mark/unmark cycles; - after: `O(|⋃_j witness-DAG(j)|)` traversal + `O(#distinct leaves)` set insertions, with a single mark/unmark cycle. Shared sub-DAGs are walked and their leaves inserted once instead of once per column. ### Measured effect Profiled with callgrind on a representative conflict-heavy `QF_SLIA` input (`model_validate=true`, bounded run), baseline vs. patched: - `lp::lar_solver::explain_fixed_column` on the hot path: `24,337,671,616 → 0` retired instructions (59.2% → 0% of the run), replaced by the single batched traversal; - total retired instructions: `41,113,093,210 → 35,983,363,256` (×0.875, ≈ 12.5% fewer) — the net work removed by de-duplicating shared sub-DAGs; - wall-clock: `6.428 s → 6.079 s` (≈ 5.4% faster); - differential correctness preserved (identical results across the validation inputs). --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/math/lp/lar_solver.cpp | 27 +++++++++++++++++++++++++++ src/math/lp/lar_solver.h | 1 + src/math/lp/lp_bound_propagator.h | 16 +++++----------- src/math/lp/lp_params_helper.pyg | 1 + src/math/lp/lp_settings.cpp | 1 + src/math/lp/lp_settings.h | 3 +++ 6 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 9e9d1add14..1144922bfb 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -63,6 +63,7 @@ namespace lp { unsigned_vector m_row_bounds_to_replay; u_dependency_manager m_dependencies; svector m_tmp_dependencies; + ptr_vector m_tmp_witnesses; u_dependency* m_crossed_bounds_deps = nullptr; lpvar m_crossed_bounds_column = null_lpvar; @@ -1132,6 +1133,32 @@ namespace lp { ex.push_back(ci); } + // Linearize the bound witnesses of all fixed columns in the row together, so the + // mark bits walk each dependency sub-DAG shared between columns only once. + // When lp.batch_explain_fixed_in_row is disabled, fall back to explaining each + // fixed column independently (the pre-batching behavior). + void lar_solver::explain_fixed_in_row(unsigned row, explanation& ex) { + if (!settings().batch_explain_fixed_in_row()) { + for (auto const& c : get_row(row)) + if (column_is_fixed(c.var())) + explain_fixed_column(c.var(), ex); + return; + } + auto& witnesses = m_imp->m_tmp_witnesses; + witnesses.reset(); + for (auto const& c : get_row(row)) { + if (!column_is_fixed(c.var())) + continue; + const column& ul = m_imp->m_columns[c.var()]; + witnesses.push_back(ul.lower_bound_witness()); + witnesses.push_back(ul.upper_bound_witness()); + } + m_imp->m_tmp_dependencies.reset(); + m_imp->m_dependencies.linearize(witnesses, m_imp->m_tmp_dependencies); + for (auto ci : m_imp->m_tmp_dependencies) + ex.push_back(ci); + } + void lar_solver::remove_fixed_vars_from_base() { // this will allow to disable and restore the tracking of the touched rows flet f(get_core_solver().m_r_solver.m_touched_rows, nullptr); diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 79c729e5d1..4588f1772f 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -521,6 +521,7 @@ public: } void explain_fixed_column(unsigned j, explanation& ex); + void explain_fixed_in_row(unsigned row, explanation& ex); u_dependency* join_deps(u_dependency* a, u_dependency *b) { return dep_manager().mk_join(a, b); } const constraint_set & constraints() const; void push(); diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index 2568c51fbd..3df2fbf741 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -248,22 +248,16 @@ public: void explain_fixed_in_row(unsigned row, explanation& ex) { TRACE(eq, tout << lp().get_row(row) << std::endl); - for (const auto& c : lp().get_row(row)) - if (lp().column_is_fixed(c.var())) - lp().explain_fixed_column(c.var(), ex); + lp().explain_fixed_in_row(row, ex); } unsigned explain_fixed_in_row_and_get_base(unsigned row, explanation& ex) { - unsigned base = UINT_MAX; TRACE(eq, tout << lp().get_row(row) << std::endl); - for (const auto& c : lp().get_row(row)) { - if (lp().column_is_fixed(c.var())) { - lp().explain_fixed_column(c.var(), ex); - } - else if (lp().is_base(c.var())) { + lp().explain_fixed_in_row(row, ex); + unsigned base = UINT_MAX; + for (const auto& c : lp().get_row(row)) + if (!lp().column_is_fixed(c.var()) && lp().is_base(c.var())) base = c.var(); - } - } return base; } diff --git a/src/math/lp/lp_params_helper.pyg b/src/math/lp/lp_params_helper.pyg index 29a10c2d52..89c9730bc0 100644 --- a/src/math/lp/lp_params_helper.pyg +++ b/src/math/lp/lp_params_helper.pyg @@ -15,5 +15,6 @@ def_module_params(module_name='lp', ('lcube_flips', UINT, 16, 'maximal number of coordinate flips when repairing the rounded largest cube center, only relevant when lcube is true'), ('int_hammer_period', UINT, 4, 'period (in final_check calls) for the integer cut/cube heuristics (find_cube, hnf, gomory); a smaller value calls them more often'), ('random_hammers', BOOL, True, 'draw the periodic integer heuristic gates (find_cube, lcube, hnf, gomory, dio) at random with the same 1/period rate instead of a deterministic every-k-th-call modulus'), + ('batch_explain_fixed_in_row', BOOL, True, 'linearize the bound witnesses of all fixed columns in a row in a single dependency pass (de-duplicating shared sub-DAGs) instead of explaining each fixed column independently'), )) diff --git a/src/math/lp/lp_settings.cpp b/src/math/lp/lp_settings.cpp index affc299788..14e60a5b9f 100644 --- a/src/math/lp/lp_settings.cpp +++ b/src/math/lp/lp_settings.cpp @@ -46,6 +46,7 @@ void lp::lp_settings::updt_params(params_ref const& _p) { m_dio_calls_period_decrease = lp_p.dio_calls_period_decrease(); m_dio_run_gcd = lp_p.dio_run_gcd(); m_random_hammers = lp_p.random_hammers(); + m_batch_explain_fixed_in_row = lp_p.batch_explain_fixed_in_row(); m_lcube = lp_p.lcube(); m_lcube_flips = lp_p.lcube_flips(); unsigned hammer_period = lp_p.int_hammer_period(); diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index bc1f2044f5..5aeb645b78 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -268,6 +268,7 @@ private: unsigned m_dio_calls_period_decrease = 2; bool m_dio_run_gcd = true; bool m_random_hammers = true; + bool m_batch_explain_fixed_in_row = true; bool m_lcube = true; unsigned m_lcube_flips = 16; public: @@ -279,6 +280,8 @@ public: unsigned & dio_calls_period_decrease() { return m_dio_calls_period_decrease; } bool random_hammers() const { return m_random_hammers; } bool & random_hammers() { return m_random_hammers; } + bool batch_explain_fixed_in_row() const { return m_batch_explain_fixed_in_row; } + bool & batch_explain_fixed_in_row() { return m_batch_explain_fixed_in_row; } bool print_external_var_name() const { return m_print_external_var_name; } bool propagate_eqs() const { return m_propagate_eqs;} unsigned hnf_cut_period() const { return m_hnf_cut_period; } From 835679b27d2d6db72a7ecd0e8ff08037aea1dd63 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson <5377127+levnach@users.noreply.github.com> Date: Mon, 6 Jul 2026 12:56:13 -0700 Subject: [PATCH 30/48] Revert #10052: eager-commit of infinitesimal LP hint is unsound for shared-symbol objectives (#10057) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Reverts #10052, whose eager-commit of infinitesimal LP hints is **unsound** for shared-symbol objectives. #10052 added, in `opt_solver::maximize_objective`: ```cpp if (val.is_finite() && !val.get_infinitesimal().is_zero() && val > m_objective_values[i]) m_objective_values[i] = val; ``` on the premise that *"a non-zero infinitesimal ⇒ an exact, unattainable strict optimum, so the LP hint is authoritative."* That holds for a **pure LP**, but is **false when the objective is a shared symbol** with another theory (e.g. the auxiliary uninterpreted function used to encode a `distinct` with > 32 arguments). There the LP relaxation only yields a *hint* that can be a strict **over-estimate**, and #10052 commits it without validation — exactly the class of bound that #10028's `check_bound` exists to reject. ## Counterexample A 6-mark Golomb ruler over integers `x0..x5`, with the `distinct` padded to > 32 arguments so `x5` becomes a shared symbol; objective is a real `obj` with `obj > x5` (full file attached to #5720): - Ground truth: `minimize x5` (integer) ⇒ **17**; since `obj > x5`, the true optimum is **`17 + ε`**. - With #10052, z3 reports **`(obj (+ 5.0 epsilon))`** — wrong and **infeasible** (`obj < 6` is `unsat`; the returned model itself has `x5 = 35, obj = 49.5`). | benchmark | with #10052 (master) | after this revert | | --- | --- | --- | | Golomb `bug.smt2` (shared symbol) | `(obj (+ 5.0 epsilon))` ❌ infeasible | `(obj 18)` ✅ consistent | | #5720 (`max r < 1`) | `1 - epsilon` ✅ | `0` ❌ (regression returns) | ## Tradeoff / follow-up This revert restores soundness on the shared-symbol case but **reintroduces the #5720 regression** (`max r<1` ⇒ `0`), which is why **#5720 has been reopened**. A correct fix should preserve the strict single-objective supremum **without** trusting an unvalidated shared-symbol hint — e.g. gate the eager commit on `!has_shared` (pure LP only), or validate the rational part of the hint while keeping the infinitesimal. The same blind spot affects the alternative `check_bound` guard proposed in #10051. Re: #5720 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/opt/opt_solver.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 88e81184fd..eb8b4dd6cb 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -342,24 +342,6 @@ namespace opt { return true; } - // - // A finite hint with a non-zero infinitesimal is a strict - // supremum/infimum (e.g. maximizing r subject to r < 1 yields - // 1 - epsilon). No concrete model can attain such a value, and - // check_bound() below cannot validate it either: opt_solver::mk_ge - // drops the negative infinitesimal, turning the bound r >= 1 - epsilon - // into the unsatisfiable r >= 1. Commit it eagerly here so that it is - // neither overwritten by the strictly smaller current model value in - // update_objective() nor lost when validation fails and this routine - // returns false (callers such as optsmt::geometric_lex then report - // m_objective_values as the optimum). This restores the pre-#10028 - // behavior for strict optima while leaving the plain-rational - // (zero-infinitesimal) over-estimates that #10028 fixed to the - // deferred-commit logic below. - // - if (val.is_finite() && !val.get_infinitesimal().is_zero() && val > m_objective_values[i]) - m_objective_values[i] = val; - // // retrieve value of objective from current model and update // current optimal. From e20945c7436d9cc0d332f765905e191046a69596 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Jul 2026 13:53:53 -0700 Subject: [PATCH 31/48] include code for dumpign tptp Signed-off-by: Nikolaj Bjorner --- src/cmd_context/tptp_frontend.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/cmd_context/tptp_frontend.cpp b/src/cmd_context/tptp_frontend.cpp index ba04b29200..1bfd0e0117 100644 --- a/src/cmd_context/tptp_frontend.cpp +++ b/src/cmd_context/tptp_frontend.cpp @@ -14,6 +14,7 @@ #include "util/z3_exception.h" #include "ast/arith_decl_plugin.h" #include "ast/array_decl_plugin.h" +#include "ast/decl_collector.h" #include "ast/expr_abstract.h" #include "ast/ast_util.h" #include "ast/polymorphism_util.h" @@ -2928,6 +2929,25 @@ static unsigned read_tptp_stream(std::istream& in, char const* current_file) { ctx.set_solver_factory(mk_smt_strategic_solver_factory()); + // Optional: dump the parsed goal as an SMT-LIB2 benchmark (env Z3_TPTP_DUMP_SMT2 + // gives the output file path). Used to produce SMTLIB versions of TPTP instances. + if (char const* dump_path = getenv("Z3_TPTP_DUMP_SMT2")) { + std::ofstream dout(dump_path); + if (dout) { + ast_manager& m = ctx.m(); + dout << "; Auto-generated from TPTP input: " + << (current_file ? current_file : "?") << "\n"; + dout << "(set-logic ALL)\n"; + decl_collector decls(m); + for (expr* a : ctx.assertions()) + decls.visit(a); + for (sort* s : decls.get_sorts()) + if (m.is_uninterp(s) && s->get_num_parameters() == 0) + dout << "(declare-sort " << s->get_name() << " 0)\n"; + ctx.display_smt2_benchmark(dout, ctx.assertions().size(), ctx.assertions().data()); + } + } + // Suppress default check-sat output; TPTP frontend reports SZS status explicitly. std::ostringstream sink; scoped_regular_stream scoped_stream(ctx, sink); From 72d27e1cbbd74f929eaf8057aff35bf95ab11bff Mon Sep 17 00:00:00 2001 From: NikolajBjorner Date: Sun, 5 Jul 2026 15:36:30 -0700 Subject: [PATCH 32/48] smt: instrument ho-matching and ho-var term-enumeration statistics Add -st statistics counters: - ho-matching refinements / instances (default_qm_plugin, gated on smt.ho_matching) - ho-var term-enum: terms produced by mf::ho_var::populate_inst_sets in the model finder Wired via a new quantifier_manager_plugin::collect_statistics virtual forwarded from quantifier_manager::collect_statistics. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/smt/smt_model_finder.cpp | 12 ++++++++++++ src/smt/smt_model_finder.h | 3 +++ src/smt/smt_quantifier.cpp | 15 +++++++++++++++ src/smt/smt_quantifier.h | 2 ++ 4 files changed, 32 insertions(+) diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 4ba66a51be..423669e0a1 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -38,9 +38,15 @@ Revision History: #include "smt/smt_model_finder.h" #include "smt/smt_context.h" #include "tactic/tactic_exception.h" +#include "util/statistics.h" namespace smt { + // Instrumentation: counts terms produced by ho_var term-enumeration + // (mf::ho_var::populate_inst_sets). One increment per enumerated term + // inserted into an instantiation set. Reset per model_finder instance. + static unsigned g_ho_var_term_enum = 0; + namespace mf { // ----------------------------------- @@ -1447,6 +1453,7 @@ namespace smt { unsigned generation = 0; // todo - inherited from sub-term of t? TRACE(model_finder, tout << "ho_var: adding term " << mk_ismt2_pp(t, m) << " to instantiation set of S" << std::endl;); + ++g_ho_var_term_enum; S->insert(t, generation); } } @@ -2408,12 +2415,17 @@ namespace smt { m_auf_solver(alloc(auf_solver, m)), m_dependencies(m), m_new_constraints(m) { + g_ho_var_term_enum = 0; } model_finder::~model_finder() { reset(); } + void model_finder::collect_statistics(::statistics & st) const { + st.update("ho-var term-enum", g_ho_var_term_enum); + } + void model_finder::checkpoint() { checkpoint("model_finder"); } diff --git a/src/smt/smt_model_finder.h b/src/smt/smt_model_finder.h index a8c1210492..86fdd4878f 100644 --- a/src/smt/smt_model_finder.h +++ b/src/smt/smt_model_finder.h @@ -52,6 +52,7 @@ Revision History: #include "tactic/tactic_exception.h" class model_instantiation_set; +class statistics; namespace smt { class context; @@ -122,6 +123,8 @@ namespace smt { quantifier_macro_info* operator()(quantifier* q) override; + void collect_statistics(::statistics & st) const; + }; } diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 672246beae..311c7a82d5 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -28,6 +28,7 @@ Revision History: #include "smt/smt_quick_checker.h" #include "smt/mam.h" #include "smt/qi_queue.h" +#include "util/statistics.h" #include "util/obj_hashtable.h" namespace smt { @@ -580,6 +581,7 @@ namespace smt { void quantifier_manager::collect_statistics(::statistics & st) const { m_imp->m_qi_queue.collect_statistics(st); + m_imp->m_plugin->collect_statistics(st); } void quantifier_manager::reset_statistics() { @@ -627,6 +629,8 @@ namespace smt { vector>* m_used_enodes = nullptr; }; ho_match_state m_ho_state; + unsigned m_stat_ho_refine = 0; // number of times ho-matching refinement is invoked + unsigned m_stat_ho_instances = 0; // number of instances added via ho-matching public: default_qm_plugin(): m_qm(nullptr), @@ -721,6 +725,7 @@ namespace smt { vector> used_enodes; m_context->add_instance(q, nullptr, new_bindings.size(), new_bindings.data(), max_gen, st.m_min_top_generation, st.m_max_top_generation, used_enodes); + ++m_stat_ho_instances; } bool try_ho_refine(quantifier* qa, app* pat, unsigned num_bindings, enode* const* bindings, @@ -751,11 +756,21 @@ namespace smt { verbose_stream() << " s[" << i << "] = " << mk_pp(s.get(i), m) << " sort=" << mk_pp(s.get(i)->get_sort(), m) << "\n";); m_ho_matcher->refine_ho_match(pat, s); + ++m_stat_ho_refine; return true; } bool model_based() const override { return m_fparams->m_mbqi; } + void collect_statistics(::statistics & st) const override { + if (m_fparams->m_ho_matching) { + st.update("ho-matching refinements", m_stat_ho_refine); + st.update("ho-matching instances", m_stat_ho_instances); + } + if (m_model_finder) + m_model_finder->collect_statistics(st); + } + bool mbqi_enabled(quantifier *q) const override { if (!m_fparams->m_mbqi_id) return true; const symbol &s = q->get_qid(); diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h index ad3fee18e4..d2c67a286b 100644 --- a/src/smt/smt_quantifier.h +++ b/src/smt/smt_quantifier.h @@ -186,5 +186,7 @@ namespace smt { unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, vector>& used_enodes) { return false; } + virtual void collect_statistics(::statistics & st) const {} + }; } From 6c8a5cd853ebe0cdf60872697ab6e9f4f22bd831 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Jul 2026 17:25:01 -0700 Subject: [PATCH 33/48] fix HO-matcher imitation curry-order and instance-assembly ordering bugs The higher-order matcher produced ill-typed instantiations that aborted the solve (sort-mismatch / unbound-variable exceptions), making smt.ho_matching=true net-negative on the TPTP THF benchmarks. Two root causes: 1. Imitation rule (ho_matcher.cpp): the select chain 'pats' is collected outermost-first, i.e. in reverse application order. The imitating lambda must curry arguments in application order (first-applied select binds the outermost lambda). Reversing 'pats' before building the domain/argument/body vectors and the lambda-wrapping loop makes the constructed lambda's sort agree with the flex head variable. Fixes unit-test ho_matcher test6c/test6d (previously asserted at add_binding: v->get_sort() == t->get_sort()). 2. Instance assembly (smt_quantifier.cpp on_ho_match): the fixpoint binding substitution used var_subst with the default std_order=true while the binding vector is directly indexed (binding[k] = value for var k). This resolved chained HO variable references against the wrong slots and built ill-sorted terms (assertion at rewriter_def.h:52). Use direct (std_order=false) substitution to match the binding layout. Also adds defensive guards as belt-and-suspenders: subst_sorts_match skips sort-inconsistent substitutions, an is_ground check skips bindings with leftover de Bruijn variables, and on_ho_match catches z3_exception to skip an unusable heuristic instance rather than aborting the solve (re-raising only on cancellation/resource-limit). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/ast/euf/ho_matcher.cpp | 55 ++++++++++++++++++++++++++++++++++++++ src/ast/euf/ho_matcher.h | 7 +++++ src/smt/smt_quantifier.cpp | 30 ++++++++++++++++++++- 3 files changed, 91 insertions(+), 1 deletion(-) diff --git a/src/ast/euf/ho_matcher.cpp b/src/ast/euf/ho_matcher.cpp index a740167ad3..e52a65144c 100644 --- a/src/ast/euf/ho_matcher.cpp +++ b/src/ast/euf/ho_matcher.cpp @@ -421,6 +421,16 @@ namespace euf { // H (p1) (p2) = f(t1, .., tn) // H -> \x1 \x2 f(H1(x1, x2), .., Hn(x1, x2)) // H1(p1, p2) = t1, .., Hn(p1, p2) = tn + // + // The select chain `pats` was collected from the outermost + // select down to the flex head, i.e. in reverse order of + // application. The imitating lambda must curry the arguments in + // application order (the first-applied select binds the + // outermost lambda), so process the applications inner-to-outer. + // Without this the constructed lambda has the argument arities + // in the wrong nesting order and its sort disagrees with the + // flex head variable (producing an ill-typed binding). + pats.reverse(); ptr_vector domain, pat_domain; ptr_vector pat_args; expr_ref_vector args(m), pat_vars(m), bound_args(m); @@ -824,6 +834,16 @@ namespace euf { TRACE(ho_matching, tout << "refine " << mk_pp(p, m) << "\n" << s << "\n"); unsigned num_bound = 0, level = 0; + for (auto [v, pat] : m_pat2abs[fo_pat]) { + // Defensive: if the abstraction-variable indices in the stored + // pattern do not line up (sort-wise) with the current substitution, + // building the refined term would be ill-typed and abort the solve. + // Skip the whole refinement; a missed heuristic instance is sound. + if (!subst_sorts_match(m, pat, s, true)) { + m_trail.pop_scope(1); + return; + } + } for (auto [v, pat] : m_pat2abs[fo_pat]) { var_subst sub(m, true); auto pat_refined = sub(pat, s); @@ -835,6 +855,41 @@ namespace euf { m_trail.pop_scope(1); } + bool ho_matcher::subst_sorts_match(ast_manager& m, expr* t, expr_ref_vector const& s, bool std_order) { + unsigned sz = s.size(); + ptr_buffer es; + svector offs; + es.push_back(t); + offs.push_back(0); + while (!es.empty()) { + expr* e = es.back(); es.pop_back(); + unsigned off = offs.back(); offs.pop_back(); + if (is_var(e)) { + unsigned idx = to_var(e)->get_idx(); + if (idx < off) + continue; + unsigned k = idx - off; + if (k >= sz) + continue; + expr* r = std_order ? s.get(sz - k - 1) : s.get(k); + if (r && r->get_sort() != e->get_sort()) + return false; + } + else if (is_app(e)) { + for (expr* arg : *to_app(e)) { + es.push_back(arg); + offs.push_back(off); + } + } + else if (is_quantifier(e)) { + quantifier* q = to_quantifier(e); + es.push_back(q->get_expr()); + offs.push_back(off + q->get_num_decls()); + } + } + return true; + } + std::ostream& ho_matcher::display(std::ostream& out) const { m_subst.display(out << "subst\n"); m_goals.display(out << "goals\n"); diff --git a/src/ast/euf/ho_matcher.h b/src/ast/euf/ho_matcher.h index 0235559261..e513332fe2 100644 --- a/src/ast/euf/ho_matcher.h +++ b/src/ast/euf/ho_matcher.h @@ -400,6 +400,13 @@ namespace euf { void refine_ho_match(app* p, expr_ref_vector& s); + // Returns true iff applying the substitution s to t (with the given + // variable ordering) is sort-safe: every free variable of t that is + // bound by s maps to a value of the same sort. Used to defensively + // skip higher-order matches whose bindings would produce ill-typed + // instantiation terms (which would otherwise abort the whole solve). + static bool subst_sorts_match(ast_manager& m, expr* t, expr_ref_vector const& s, bool std_order); + bool is_free(app* p, unsigned i) const { return m_hopat2free_vars[p].contains(i); } quantifier* hoq2q(quantifier* q) const { return m_hoq2q[q]; } diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 311c7a82d5..3af5953a96 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -667,6 +667,21 @@ namespace smt { quantifier_manager_plugin * mk_fresh() override { return alloc(default_qm_plugin); } void on_ho_match(euf::ho_subst& s) { + ast_manager& m = m_context->get_manager(); + try { + on_ho_match_core(s); + } + catch (z3_exception &) { + // A higher-order binding produced an ill-typed or otherwise + // unusable instantiation term. Adding a heuristic HO instance is + // optional, so we skip this match rather than aborting the solve. + // Re-raise only if the failure was due to cancellation/resource limits. + if (!m.inc()) + throw; + } + } + + void on_ho_match_core(euf::ho_subst& s) { ast_manager& m = m_context->get_manager(); auto& st = m_ho_state; auto* hoq = st.m_q; @@ -684,12 +699,20 @@ namespace smt { << "\n" << binding << "\n";); if (binding.size() > q->get_num_decls()) { - var_subst sub(m); + // binding is indexed directly (binding[k] = value for var k), + // so the substitution must use direct (non-standard) order to + // resolve chained HO variable references; the sort guard below + // is checked with the matching order. + var_subst sub(m, false); bool change = true; while (change) { change = false; for (unsigned i = 1; i < binding.size(); ++i) { if (!binding.get(i)) continue; + // Skip ill-typed substitutions: a misaligned higher-order + // binding would build an ill-sorted term and abort the solve. + if (!euf::ho_matcher::subst_sorts_match(m, binding.get(i), binding, false)) + return; auto r = sub(binding.get(i), binding); change |= r != binding.get(i); binding[i] = r; @@ -708,6 +731,11 @@ namespace smt { for (expr* e : binding) { if (!e) return; // incomplete binding + // A leftover free (de Bruijn) variable means the binding is + // incomplete/misaligned; adding such a term would raise + // "Formulas should not contain unbound variables". Skip it. + if (!is_ground(e)) + return; if (!m_context->e_internalized(e)) { m_context->internalize(e, false); } From 470e9667918a14551023c7e67c7141f821bd083b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Jul 2026 15:29:02 -0700 Subject: [PATCH 34/48] bugfixes to front-end and matcher --- src/ast/euf/ho_matcher.cpp | 67 +++++++++---- src/ast/rewriter/array_rewriter.cpp | 2 + src/ast/rewriter/rewriter_def.h | 3 + src/ast/well_sorted.cpp | 77 ++++++++++----- src/cmd_context/tptp_frontend.cpp | 2 + src/smt/smt_model_finder.cpp | 23 +++-- src/smt/smt_quantifier.cpp | 23 +---- src/test/ho_matcher.cpp | 145 ++++++++++++++++++++++++++++ 8 files changed, 275 insertions(+), 67 deletions(-) diff --git a/src/ast/euf/ho_matcher.cpp b/src/ast/euf/ho_matcher.cpp index e52a65144c..4a793e2159 100644 --- a/src/ast/euf/ho_matcher.cpp +++ b/src/ast/euf/ho_matcher.cpp @@ -43,6 +43,7 @@ Author: --*/ #include "ast/euf/ho_matcher.h" +#include "ast/well_sorted.h" @@ -373,6 +374,9 @@ namespace euf { pats.push_back(to_app(p1)); p1 = to_app(p1)->get_arg(0); } + // innermost select is a meta variable, + // order patterns from inner-most application to outer-most. + pats.reverse(); auto v = to_var(p1); if (wi.is_init()) wi.set_project(); @@ -430,32 +434,44 @@ namespace euf { // Without this the constructed lambda has the argument arities // in the wrong nesting order and its sort disagrees with the // flex head variable (producing an ill-typed binding). - pats.reverse(); + ptr_vector domain, pat_domain; ptr_vector pat_args; + svector pat_pos; // forward binder position (in domain) of each distinct index expr_ref_vector args(m), pat_vars(m), bound_args(m); vector names; pat_args.push_back(nullptr); pat_vars.push_back(nullptr); + pat_pos.push_back(0); // placeholder for the flex-head slot 0 unsigned num_bound = 0; expr_mark seen; for (auto pat : pats) { for (auto pi : array_select_indices(pat)) { + if (!seen.is_marked(pi)) { + pat_domain.push_back(pi->get_sort()); + pat_args.push_back(pi); + pat_pos.push_back(num_bound); + seen.mark(pi); + } ++num_bound; domain.push_back(pi->get_sort()); names.push_back(symbol(num_bound)); - if (seen.is_marked(pi)) - continue; - pat_domain.push_back(pi->get_sort()); - pat_args.push_back(pi); - seen.mark(pi); } } - for (unsigned i = pat_args.size(); i-- > 1; ) { - auto pi = pat_args.get(i); - pat_vars.push_back(m.mk_var(pat_args.size() - i - 1, pi->get_sort())); - } + // pat_vars[k] references the lambda binder for the k-th distinct + // index and must carry that index' sort, so the reconstructed + // select stays aligned with the flex head's array domain + // (pat_domain). The binder at forward position p has de Bruijn + // index num_bound-1-p (the outermost binder has the highest + // index). Emitting in forward slot order keeps the select + // arguments in the same order as pat_domain even when the + // indices have heterogeneous sorts (otherwise the array plugin + // rejects the ill-ordered select). + for (unsigned k = 1; k < pat_args.size(); ++k) { + unsigned db = num_bound - 1 - pat_pos[k]; + pat_vars.push_back(m.mk_var(db, pat_args.get(k)->get_sort())); + } for (auto ti : *ta) { sort* v_sort = m_array.mk_array_sort(pat_domain.size(), pat_domain.data(), ti->get_sort()); @@ -463,7 +479,8 @@ namespace euf { auto w = m.mk_var(m_subst.size() + wi.pat_offset() + num_bound, v_sort); // shifted by number of bound m_subst.resize(m_subst.size() + 1); pat_args[0] = v; - auto sel = m_array.mk_select(pat_args.size(), pat_args.data()); + expr_ref sel(m); + sel = m_array.mk_select(pat_args.size(), pat_args.data()); m_goals.push(wi.level + 1, wi.term_offset(), sel, ti); pat_vars[0] = w; sel = m_array.mk_select(pat_vars.size(), pat_vars.data()); @@ -479,6 +496,7 @@ namespace euf { num_bound -= sz; lam = m.mk_lambda(sz, domain.data() + num_bound, names.data() + num_bound, lam); } + add_binding(v, wi.pat_offset(), lam); wi.set_done(); return true; @@ -591,6 +609,7 @@ namespace euf { } lam = m.mk_lambda(names.size(), sorts.data(), names.data(), lam); } + SASSERT(is_well_sorted(m, lam)); return lam; } @@ -632,6 +651,8 @@ namespace euf { SASSERT(var_sort); body = m.mk_var(num_binders - i - 1, var_sort); bind_lambdas(num_lambdas, s, body); + SASSERT(body->get_sort() == s); + SASSERT(is_well_sorted(m, body)); return body; } @@ -646,6 +667,8 @@ namespace euf { decl_names.push_back(symbol(i)); } body = m.mk_lambda(sz, decl_sorts.data(), decl_names.data(), body); + SASSERT(s == body->get_sort()); + SASSERT(is_well_sorted(m, body)); } void ho_matcher::add_binding(var* v, unsigned offset, expr* t) { @@ -665,7 +688,6 @@ namespace euf { } auto is_ho = any_of(subterms::all(expr_ref(p, m)), [&](expr* t) { return m_unitary.is_flex(0, t) || - // m.is_lambda_def(t) || is_lambda(t); }); if (!is_ho) @@ -684,8 +706,7 @@ namespace euf { todo.pop_back(); continue; } - if ((m_unitary.is_flex(0, t) && lvl > 1) || // m.is_lambda_def(t) || - is_lambda(t)) { + if ((m_unitary.is_flex(0, t) && lvl > 1) || is_lambda(t)) { if (!contains_pat2abs) m_pat2abs.insert_if_not_there(p, svector>()).push_back({ nb, t }); auto v = m.mk_var(nb++, t->get_sort()); @@ -817,6 +838,7 @@ namespace euf { auto& abs = m_pat2abs[fo_pat]; verbose_stream() << " m_pat2abs size: " << abs.size() << "\n"; for (auto [v, pat] : abs) verbose_stream() << " v=" << v << " pat=" << mk_pp(pat, m) << "\n";); + unsigned base_scope = m_trail.get_num_scopes(); m_trail.push_scope(); m_subst.resize(0); m_subst.resize(s.size()); @@ -835,12 +857,18 @@ namespace euf { unsigned num_bound = 0, level = 0; for (auto [v, pat] : m_pat2abs[fo_pat]) { - // Defensive: if the abstraction-variable indices in the stored - // pattern do not line up (sort-wise) with the current substitution, - // building the refined term would be ill-typed and abort the solve. - // Skip the whole refinement; a missed heuristic instance is sound. + // If a binding's sort disagrees with the pattern variable it would + // fill, substituting it would build an ill-sorted term. This can + // arise for deeply nested multi-select patterns whose de Bruijn + // remapping does not line up, or when E-matching delivers a + // candidate binding whose sort is incompatible with the abstracted + // higher-order pattern. Discard this refinement candidate (produce + // no instance) instead of aborting the whole solve. if (!subst_sorts_match(m, pat, s, true)) { m_trail.pop_scope(1); + IF_VERBOSE(0, verbose_stream() << "refine_ho_match: sorts do not match for " << mk_pp(pat, m) << " and " + << s << "\n";); + UNREACHABLE(); return; } } @@ -850,8 +878,8 @@ namespace euf { TRACE(ho_matching, tout << mk_pp(pat, m) << " -> " << pat_refined << "\n"); m_goals.push(level, num_bound, pat_refined, m_subst.get(v)); } - search(); + m_trail.pop_scope(1); } @@ -908,6 +936,7 @@ namespace euf { }; void match_goals::push(unsigned level, unsigned offset, expr_ref const& pat, expr_ref const& t) { + SASSERT(pat->get_sort() == t->get_sort()); match_goal* wi = new (ho.trail().get_region()) match_goal(level, offset, pat, t); ho.trail().push(retire_match_goal(*wi)); // reset on undo wi->init(wi); diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index 5d3ddf1ddb..55135ba591 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -21,6 +21,7 @@ Notes: #include "ast/ast_util.h" #include "ast/ast_pp.h" #include "ast/ast_ll_pp.h" +#include "ast/well_sorted.h" #include "ast/rewriter/var_subst.h" #include "params/array_rewriter_params.hpp" #include "util/util.h" @@ -818,6 +819,7 @@ expr_ref array_rewriter::expand_store(expr* s) { result = m().mk_ite(mk_and(eqs), tmp, result); } result = m().mk_lambda(sorts.size(), sorts.data(), names.data(), result); + SASSERT(is_well_sorted(m(), result)); return result; } diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index ad4702de50..b9e4b4f27d 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -21,6 +21,7 @@ Notes: #include "ast/rewriter/rewriter.h" #include "ast/ast_smt2_pp.h" #include "ast/ast_ll_pp.h" +#include "ast/well_sorted.h" #include "ast/ast_pp.h" template @@ -552,6 +553,7 @@ void rewriter_tpl::process_quantifier(quantifier * q, frame & fr) { SASSERT(fr.m_spos + num_children == result_stack().size()); expr * const * it = result_stack().data() + fr.m_spos; expr * new_body = *it; + SASSERT(is_well_sorted(m_manager, q)); unsigned num_pats = q->get_num_patterns(); unsigned num_no_pats = q->get_num_no_patterns(); expr_ref_vector new_pats(m_manager, num_pats, q->get_patterns()); @@ -604,6 +606,7 @@ void rewriter_tpl::process_quantifier(quantifier * q, frame & fr) { if (!m_cfg.reduce_quantifier(q, new_body, new_pats.data(), new_no_pats.data(), m_r, m_pr)) { if (fr.m_new_child) { m_r = m().update_quantifier(q, num_pats, new_pats.data(), num_no_pats, new_no_pats.data(), new_body); + SASSERT(is_well_sorted(m(), m_r)); } else { TRACE(rewriter_reuse, tout << "reusing:\n" << mk_ismt2_pp(q, m()) << "\n";); diff --git a/src/ast/well_sorted.cpp b/src/ast/well_sorted.cpp index cb8b8b93d2..36aed72153 100644 --- a/src/ast/well_sorted.cpp +++ b/src/ast/well_sorted.cpp @@ -25,31 +25,57 @@ Revision History: #include "util/warning.h" #include "ast/ast_smt2_pp.h" + namespace { struct well_sorted_proc { - ast_manager & m_manager; - bool m_error; + ast_manager & m; + bool m_error; + ptr_vector m_binding; - well_sorted_proc(ast_manager & m):m_manager(m), m_error(false) {} - - void operator()(var * v) {} + well_sorted_proc(ast_manager & m):m(m), m_error(false) {} - void operator()(quantifier * n) { - expr const * e = n->get_expr(); - if (!is_lambda(n) && !m_manager.is_bool(e)) { - warning_msg("quantifier's body must be a boolean."); - m_error = true; - UNREACHABLE(); + void check(expr* e) { + for (auto term : subterms::ground(expr_ref(e, m))) { + if (is_app(term)) + check_app(to_app(term)); + else if (is_var(term)) + check_var(to_var(term)); + else if (is_quantifier(term)) + check_quantifier(to_quantifier(term)); } } - void operator()(app * n) { + void check_quantifier(quantifier * n) { + if (!is_lambda(n) && !m.is_bool(n->get_expr())) { + warning_msg("quantifier's body must be a boolean."); + m_error = true; + // UNREACHABLE(); + } + unsigned sz = m_binding.size(); + m_binding.append(n->get_num_decls(), n->get_decl_sorts()); + check(n->get_expr()); + m_binding.shrink(sz); + } + + void check_var(var* v) { + if (v->get_idx() >= m_binding.size()) { + return; + } + sort *s = m_binding[m_binding.size() - v->get_idx() - 1]; + if (s != v->get_sort()) { + warning_msg("variable sort does not match binding sort."); + m_error = true; + // UNREACHABLE(); + } + } + + void check_app(app * n) { unsigned num_args = n->get_num_args(); func_decl * decl = n->get_decl(); if (num_args != decl->get_arity() && !decl->is_associative() && !decl->is_right_associative() && !decl->is_left_associative()) { - TRACE(ws, tout << "unexpected number of arguments.\n" << mk_ismt2_pp(n, m_manager);); + TRACE(ws, tout << "unexpected number of arguments.\n" << mk_ismt2_pp(n, m);); warning_msg("unexpected number of arguments."); m_error = true; return; @@ -59,19 +85,20 @@ struct well_sorted_proc { sort * actual_sort = n->get_arg(i)->get_sort(); sort * expected_sort = decl->is_associative() ? decl->get_domain(0) : decl->get_domain(i); if (expected_sort != actual_sort) { - TRACE(tc, tout << "sort mismatch on argument #" << i << ".\n" << mk_ismt2_pp(n, m_manager); - tout << "Sort mismatch for argument " << i+1 << " of " << mk_ismt2_pp(n, m_manager, false) << "\n"; - tout << "Expected sort: " << mk_pp(expected_sort, m_manager) << "\n"; - tout << "Actual sort: " << mk_pp(actual_sort, m_manager) << "\n"; - tout << "Function sort: " << mk_pp(decl, m_manager) << "."; + TRACE(tc, tout << "sort mismatch on argument #" << i << ".\n" << mk_ismt2_pp(n, m); + tout << "Sort mismatch for argument " << i+1 << " of " << mk_ismt2_pp(n, m, false) << "\n"; + tout << "Expected sort: " << mk_pp(expected_sort, m) << "\n"; + tout << "Actual sort: " << mk_pp(actual_sort, m) << "\n"; + tout << "Function sort: " << mk_pp(decl, m) << "."; ); std::ostringstream strm; - strm << "Sort mismatch for argument " << i+1 << " of " << mk_ll_pp(n, m_manager, false) << "\n"; - strm << "Expected sort: " << mk_pp(expected_sort, m_manager) << '\n'; - strm << "Actual sort: " << mk_pp(actual_sort, m_manager) << '\n'; - strm << "Function sort: " << mk_pp(decl, m_manager) << '.'; + strm << "Sort mismatch for argument " << i+1 << " of " << mk_ll_pp(n, m, false) << "\n"; + strm << "Expected sort: " << mk_pp(expected_sort, m) << '\n'; + strm << "Actual sort: " << mk_pp(actual_sort, m) << '\n'; + strm << "Function sort: " << mk_pp(decl, m) << '.'; warning_msg("%s", std::move(strm).str().c_str()); m_error = true; + // UNREACHABLE(); return; } } @@ -82,7 +109,11 @@ struct well_sorted_proc { bool is_well_sorted(ast_manager const & m, expr * n) { well_sorted_proc p(const_cast(m)); - for_each_expr(p, n); + p.check(n); + if (p.m_error) { + IF_VERBOSE(0, verbose_stream() << "expression is not well sorted.\n" << mk_pp(n, const_cast(m)) << "\n";); + IF_VERBOSE(0, verbose_stream() << mk_ll_pp(n, const_cast(m)) << "\n";); + } return !p.m_error; } diff --git a/src/cmd_context/tptp_frontend.cpp b/src/cmd_context/tptp_frontend.cpp index 1bfd0e0117..8ab6b31672 100644 --- a/src/cmd_context/tptp_frontend.cpp +++ b/src/cmd_context/tptp_frontend.cpp @@ -18,6 +18,7 @@ #include "ast/expr_abstract.h" #include "ast/ast_util.h" #include "ast/polymorphism_util.h" +#include "ast/well_sorted.h" #include "ast/rewriter/expr_safe_replace.h" #include "solver/solver.h" #include "cmd_context/cmd_context.h" @@ -2461,6 +2462,7 @@ class tptp_parser { m_has_conjecture = true; f = m.mk_not(f); } + SASSERT(is_well_sorted(m, f)); m_cmd.assert_expr(f); } catch (z3_exception const& ex) { // Sort mismatch or other semantic error in this formula — skip it. diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 423669e0a1..4d06e09d71 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -42,10 +42,6 @@ Revision History: namespace smt { - // Instrumentation: counts terms produced by ho_var term-enumeration - // (mf::ho_var::populate_inst_sets). One increment per enumerated term - // inserted into an instantiation set. Reset per model_finder instance. - static unsigned g_ho_var_term_enum = 0; namespace mf { @@ -1173,6 +1169,7 @@ namespace smt { virtual char const* get_kind() const = 0; virtual bool is_equal(qinfo const* qi) const = 0; virtual void display(std::ostream& out) const { out << "[" << get_kind() << "]"; } + virtual void collect_statistics(::statistics &st) const {} // AUF fragment solver virtual void process_auf(quantifier* q, auf_solver& s, context* ctx) = 0; @@ -1385,10 +1382,15 @@ namespace smt { class ho_var : public qinfo { unsigned m_var_i; + unsigned m_ho_var_term_enum = 0; public: ho_var(ast_manager& m, unsigned i) : qinfo(m), m_var_i(i) { } + void collect_statistics(::statistics &st) const override { + st.update("mbqi.ho-var-term-enum", m_ho_var_term_enum); + } + char const *get_kind() const override { return "ho_var"; } @@ -1453,7 +1455,7 @@ namespace smt { unsigned generation = 0; // todo - inherited from sub-term of t? TRACE(model_finder, tout << "ho_var: adding term " << mk_ismt2_pp(t, m) << " to instantiation set of S" << std::endl;); - ++g_ho_var_term_enum; + ++m_ho_var_term_enum; S->insert(t, generation); } } @@ -1779,6 +1781,11 @@ namespace smt { public: typedef ptr_vector::const_iterator macro_iterator; + void collect_statistics(::statistics &st) const { + for (auto *qi : m_qinfo_vect) + qi->collect_statistics(st); + } + static quantifier_ref mk_flat(ast_manager& m, quantifier* q) { if (has_quantifiers(q->get_expr())) { proof_ref pr(m); @@ -2415,7 +2422,6 @@ namespace smt { m_auf_solver(alloc(auf_solver, m)), m_dependencies(m), m_new_constraints(m) { - g_ho_var_term_enum = 0; } model_finder::~model_finder() { @@ -2423,7 +2429,10 @@ namespace smt { } void model_finder::collect_statistics(::statistics & st) const { - st.update("ho-var term-enum", g_ho_var_term_enum); + // Retrieve the ho-var term-enumeration counters from the embedded + // qinfo objects (mf::ho_var) held by each registered quantifier_info. + for (auto const &[k, v] : m_q2info) + v->collect_statistics(st); } void model_finder::checkpoint() { diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 3af5953a96..b7dcb70623 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -657,7 +657,7 @@ namespace smt { if (m_fparams->m_ho_matching) { m_ho_matcher = alloc(euf::ho_matcher, m, m_context->get_trail_stack()); - std::function on_match = [&](euf::ho_subst& s) { + std::function on_match = [this](euf::ho_subst& s) { on_ho_match(s); }; m_ho_matcher->set_on_match(on_match); @@ -667,21 +667,6 @@ namespace smt { quantifier_manager_plugin * mk_fresh() override { return alloc(default_qm_plugin); } void on_ho_match(euf::ho_subst& s) { - ast_manager& m = m_context->get_manager(); - try { - on_ho_match_core(s); - } - catch (z3_exception &) { - // A higher-order binding produced an ill-typed or otherwise - // unusable instantiation term. Adding a heuristic HO instance is - // optional, so we skip this match rather than aborting the solve. - // Re-raise only if the failure was due to cancellation/resource limits. - if (!m.inc()) - throw; - } - } - - void on_ho_match_core(euf::ho_subst& s) { ast_manager& m = m_context->get_manager(); auto& st = m_ho_state; auto* hoq = st.m_q; @@ -709,8 +694,9 @@ namespace smt { change = false; for (unsigned i = 1; i < binding.size(); ++i) { if (!binding.get(i)) continue; - // Skip ill-typed substitutions: a misaligned higher-order - // binding would build an ill-sorted term and abort the solve. + // A misaligned higher-order binding would build an + // ill-sorted term. Abandon this refinement (no instance) + // rather than aborting the whole solve. if (!euf::ho_matcher::subst_sorts_match(m, binding.get(i), binding, false)) return; auto r = sub(binding.get(i), binding); @@ -770,6 +756,7 @@ namespace smt { for (unsigned i = 0; i < num_bindings; ++i) s.push_back(bindings[i]->get_expr()); + unsigned num_instances = m_stat_ho_instances; m_ho_state.m_q = qa; m_ho_state.m_pat = pat; m_ho_state.m_num_bindings = num_bindings; diff --git a/src/test/ho_matcher.cpp b/src/test/ho_matcher.cpp index dccd8af082..a6dee5891b 100644 --- a/src/test/ho_matcher.cpp +++ b/src/test/ho_matcher.cpp @@ -170,6 +170,147 @@ namespace euf { m_matcher.add_pattern(pat.get()); m_matcher(pat, t, 3, 1); } + + // Structural regression test derived from TPTP ANA067^1 (which fails + // under smt.ho_matching=true inside the full solver). + // pattern: (select (select v0 v3) v2) with v0 a doubly-nested array (flex head) + // term: (select K ...) matched term is itself array-sorted. + // Exercises imitation/projection of a flex head against an array-sorted + // term. The matcher must build only well-sorted bindings; the debug + // asserts in match_goals::push and mk_project catch any regression that + // commits an ill-sorted (extra array level) lambda/select. + void test7() { + sort_ref r(m_arith.mk_real(), m); + sort_ref arr_rb(m_array.mk_array_sort(r, m.mk_bool_sort()), m); // (Array Real Bool) + sort_ref arr_r_rb(m_array.mk_array_sort(r, arr_rb), m); // (Array Real (Array Real Bool)) + sort_ref arr_r_r_rb(m_array.mk_array_sort(r, arr_r_rb), m); // v0 sort + + expr_ref v0(m.mk_var(0, arr_r_r_rb), m); + expr_ref v2(m.mk_var(2, r), m); + expr_ref v3(m.mk_var(3, r), m); + expr_ref pat(m_array.mk_select(v0, v3), m); + pat = m_array.mk_select(pat, v2); + + expr_ref K(m.mk_const(symbol("K"), arr_r_rb), m); + expr_ref b(m.mk_const(symbol("b"), r), m); + expr_ref t(m_array.mk_select(K, b), m); + + IF_VERBOSE(0, verbose_stream() << "test7: " << pat << " =?= " << t << "\n";); + m_matcher.add_pattern(pat.get()); + m_matcher(pat, t, 5); + + // Faithful variant: the term index argument is itself + // (select fun (lambda (t) c)) as in ANA067^1, i.e. a term whose + // subterm is a function(array)-valued lambda. This forces the + // matcher to decompose/imitate against a lambda-bearing term. + sort_ref arr_rr(m_array.mk_array_sort(r, r), m); // (Array Real Real) + sort_ref fun_sort(m_array.mk_array_sort(arr_rr, r), m); // (Array (Array Real Real) Real) + symbol tt("t"); + sort* r_s = r.get(); + expr_ref c0(m.mk_const(symbol("c0"), r), m); + expr_ref lam(m.mk_lambda(1, &r_s, &tt, c0), m); // (lambda (t Real) c0) + expr_ref fun(m.mk_const(symbol("fun"), fun_sort), m); + expr_ref idx(m_array.mk_select(fun, lam), m); // : Real + expr_ref t2(m_array.mk_select(K, idx), m); + IF_VERBOSE(0, verbose_stream() << "test7b: " << pat << " =?= " << t2 << "\n";); + m_matcher.add_pattern(pat.get()); + m_matcher(pat, t2, 5); + } + + // Structural regression test derived from TPTP PHI008^4 (which fails + // under smt.ho_matching=true inside the full solver). + // pattern: (select v3 v4) v3 flex head, v4 a flex arg of an array sort + // term: (select P ...) P a concrete array constant. + // Exercises projecting/imitating a flex head over a function(array)-sorted + // argument (incl. a lambda-valued term arg). The matcher must build only + // well-sorted bindings; debug asserts guard against regressions. + void test8() { + sort_ref i(m.mk_uninterpreted_sort(symbol("qML_i")), m); + sort_ref mu(m.mk_uninterpreted_sort(symbol("qML_mu")), m); + sort_ref arr_ib(m_array.mk_array_sort(i, m.mk_bool_sort()), m); // (Array qML_i Bool) + sort_ref arr_mu_ib(m_array.mk_array_sort(mu, arr_ib), m); // (Array qML_mu (Array qML_i Bool)) + sort_ref p_sort(m_array.mk_array_sort(arr_mu_ib, arr_ib), m); // P sort + + expr_ref v3(m.mk_var(3, p_sort), m); + expr_ref v4(m.mk_var(4, arr_mu_ib), m); + expr_ref pat(m_array.mk_select(v3, v4), m); + + expr_ref P(m.mk_const(symbol("P"), p_sort), m); + expr_ref ell(m.mk_const(symbol("ell"), arr_mu_ib), m); + expr_ref t(m_array.mk_select(P, ell), m); + + IF_VERBOSE(0, verbose_stream() << "test8: " << pat << " =?= " << t << "\n";); + m_matcher.add_pattern(pat.get()); + m_matcher(pat, t, 9); + + // Variant with a lambda-valued term argument, mirroring PHI008's + // (select scott_P (lambda (Y) (lambda (Z) ...))) goal that forces + // the matcher to decompose a flex head against a lambda term. + symbol yv("Y"); + sort* mu_s = mu.get(); + expr_ref cbody(m.mk_const(symbol("C"), arr_ib), m); + expr_ref lam(m.mk_lambda(1, &mu_s, &yv, cbody), m); // (lambda (Y qML_mu) C) : arr_mu_ib + expr_ref t2(m_array.mk_select(P, lam), m); + IF_VERBOSE(0, verbose_stream() << "test8b: " << pat << " =?= " << t2 << "\n";); + m_matcher.add_pattern(pat.get()); + m_matcher(pat, t2, 9); + } + + // Structural regression test for the ITP127-style shape (fails under + // smt.ho_matching=true inside the full solver). The flex head H has an + // applied result sort that is *itself* an array (monomo = (Array d Bool)). + // Matching (select (select H x1) x2) =?= f where f is array-sorted is a + // case where imitation could build a lambda with an extra array level + // (an ill-sorted select). The matcher must build only well-sorted + // bindings; debug asserts guard against regressions. + void test9() { + sort_ref c(m.mk_uninterpreted_sort(symbol("c")), m); + sort_ref d(m.mk_uninterpreted_sort(symbol("d")), m); + sort_ref monomo(m_array.mk_array_sort(d, m.mk_bool_sort()), m); // (Array d Bool) + sort_ref h1(m_array.mk_array_sort(c, monomo), m); // (Array c monomo) + sort_ref h2(m_array.mk_array_sort(c, h1), m); // (Array c (Array c monomo)) + + expr_ref H(m.mk_var(0, h2), m); + expr_ref x1(m.mk_var(1, c), m); + expr_ref x2(m.mk_var(2, c), m); + expr_ref pat(m_array.mk_select(H, x1), m); + pat = m_array.mk_select(pat, x2); // (select (select H x1) x2) : monomo + + expr_ref f(m.mk_const(symbol("f"), monomo), m); // f : (Array d Bool) + IF_VERBOSE(0, verbose_stream() << "test9: " << pat << " =?= " << f << "\n";); + m_matcher.add_pattern(pat.get()); + m_matcher(pat, f, 3); + } + + // Faithful isolation test for the refine-time sort guard used by + // ho_matcher::refine_ho_match (throws "sort mismatch ..." on failure). + // Mirrors the SEV510^1 family where a bound-variable binding's sort + // disagrees with the pattern variable it would fill. subst_sorts_match + // must detect the mismatch (return false) and accept the matching case. + void test10() { + sort_ref int2int(m_array.mk_array_sort(m_int, m_int), m); + // pattern (select v0 v1): v0 is the array (idx 0), v1 the index (idx 1) + expr_ref v0(m.mk_var(0, int2int), m); + expr_ref v1(m.mk_var(1, m_int), m); + expr_ref pat(m_array.mk_select(v0, v1), m); + + // std_order=true: var idx maps to s[size-idx-1], so idx0->s[1], idx1->s[0]. + expr_ref arr(m.mk_const(symbol("arr"), int2int), m); + expr_ref i0(m_arith.mk_int(0), m); + + // Well-sorted substitution: idx0 -> arr (array), idx1 -> 0 (int). + expr_ref_vector s_ok(m); + s_ok.push_back(i0); // s[0] -> var idx 1 (Int) OK + s_ok.push_back(arr); // s[1] -> var idx 0 (Array) OK + VERIFY(ho_matcher::subst_sorts_match(m, pat, s_ok, true)); + + // Ill-sorted substitution: idx0 (array var) bound to an Int -> mismatch. + expr_ref_vector s_bad(m); + s_bad.push_back(i0); // s[0] -> var idx 1 (Int) OK + s_bad.push_back(i0); // s[1] -> var idx 0 expects Array, got Int -> mismatch + VERIFY(!ho_matcher::subst_sorts_match(m, pat, s_bad, true)); + IF_VERBOSE(0, verbose_stream() << "test10: subst_sorts_match detects sort mismatch\n";); + } }; } @@ -183,6 +324,10 @@ void tst_ho_matcher() { tm.test4(); tm.test5(); tm.test6(); + tm.test7(); + tm.test8(); + tm.test9(); + tm.test10(); } catch (std::exception const& ex) { std::cout << ex.what() << "\n"; From 5534dba680c2a56c841a351e67cd3a9248ecfee3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Jul 2026 16:57:52 -0700 Subject: [PATCH 35/48] update well_sorted to check patterns, fix variable shift in pattern inference --- src/ast/pattern/pattern_inference.cpp | 29 ++++++++++++++++++--------- src/ast/well_sorted.cpp | 4 +++- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp index 6fd8c684da..52a6bd3c56 100644 --- a/src/ast/pattern/pattern_inference.cpp +++ b/src/ast/pattern/pattern_inference.cpp @@ -42,9 +42,7 @@ bool smaller_pattern::process(expr * p1, expr * p2) { m_cache.reset(); save(p1, p2); while (!m_todo.empty()) { - expr_pair & curr = m_todo.back(); - p1 = curr.first; - p2 = curr.second; + auto [p1, p2] = m_todo.back(); m_todo.pop_back(); ast_kind k1 = p1->get_kind(); if (k1 != AST_VAR && k1 != p2->get_kind()) @@ -126,9 +124,7 @@ void pattern_inference_cfg::collect::operator()(expr * n, unsigned num_bindings) m_num_bindings = num_bindings; m_todo.push_back(entry(n, 0)); while (!m_todo.empty()) { - entry & e = m_todo.back(); - n = e.m_node; - unsigned delta = e.m_delta; + entry [n, delta] = m_todo.back(); TRACE(collect, tout << "processing: " << n->get_id() << " " << delta << " kind: " << n->get_kind() << "\n";); TRACE(collect_info, tout << mk_pp(n, m) << "\n";); if (visit_children(n, delta)) { @@ -264,11 +260,24 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) { return; } // The lambda/quantifier itself is a valid sub-term in a pattern. - // Propagate the free variables from the body (they already refer - // to the outer quantifier's bindings) and keep the node as-is. - expr * new_body = body_info->m_node.get(); + // body_info->m_node was normalized into the *outer* quantifier's de + // Bruijn space (the enclosing binders, including this lambda's own + // num_decls binders, were stripped). Re-wrapping it under the lambda + // therefore requires shifting the (outer) free variables back up by + // num_decls so they do not collide with the lambda's bound variables. + // The lambda's own bound variables never occur in body_info (any + // sub-term referring to them was rejected as a candidate), so the + // shift is always sound. + expr * body = body_info->m_node.get(); + expr_ref new_body(m); + if (num_decls > 0) { + var_shifter shift(m); + shift(body, num_decls, new_body); + } + else + new_body = body; quantifier_ref new_q(m); - if (new_body != q->get_expr()) + if (new_body.get() != q->get_expr()) new_q = m.update_quantifier(q, new_body); else new_q = q; diff --git a/src/ast/well_sorted.cpp b/src/ast/well_sorted.cpp index 36aed72153..a498b0dae5 100644 --- a/src/ast/well_sorted.cpp +++ b/src/ast/well_sorted.cpp @@ -50,10 +50,12 @@ struct well_sorted_proc { if (!is_lambda(n) && !m.is_bool(n->get_expr())) { warning_msg("quantifier's body must be a boolean."); m_error = true; - // UNREACHABLE(); } + unsigned sz = m_binding.size(); m_binding.append(n->get_num_decls(), n->get_decl_sorts()); + for (unsigned i = 0; i < n->get_num_patterns(); i++) + check(n->get_pattern(i)); check(n->get_expr()); m_binding.shrink(sz); } From ca6d6e3977844cbc8633b892110673bd2a37a7b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Jul 2026 17:14:22 -0700 Subject: [PATCH 36/48] pattern_inference: use auto for structured binding; drop debug well_sorted asserts in rewriter Fixes a build error (C3694) from an illegal specifier in the structured binding at pattern_inference.cpp:127, and removes the temporary is_well_sorted SASSERTs (and well_sorted.h include) from rewriter_def.h that were used during pattern-inference diagnosis. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/ast/pattern/pattern_inference.cpp | 2 +- src/ast/rewriter/rewriter_def.h | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp index 52a6bd3c56..b02aac4eab 100644 --- a/src/ast/pattern/pattern_inference.cpp +++ b/src/ast/pattern/pattern_inference.cpp @@ -124,7 +124,7 @@ void pattern_inference_cfg::collect::operator()(expr * n, unsigned num_bindings) m_num_bindings = num_bindings; m_todo.push_back(entry(n, 0)); while (!m_todo.empty()) { - entry [n, delta] = m_todo.back(); + auto [n, delta] = m_todo.back(); TRACE(collect, tout << "processing: " << n->get_id() << " " << delta << " kind: " << n->get_kind() << "\n";); TRACE(collect_info, tout << mk_pp(n, m) << "\n";); if (visit_children(n, delta)) { diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index b9e4b4f27d..ad4702de50 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -21,7 +21,6 @@ Notes: #include "ast/rewriter/rewriter.h" #include "ast/ast_smt2_pp.h" #include "ast/ast_ll_pp.h" -#include "ast/well_sorted.h" #include "ast/ast_pp.h" template @@ -553,7 +552,6 @@ void rewriter_tpl::process_quantifier(quantifier * q, frame & fr) { SASSERT(fr.m_spos + num_children == result_stack().size()); expr * const * it = result_stack().data() + fr.m_spos; expr * new_body = *it; - SASSERT(is_well_sorted(m_manager, q)); unsigned num_pats = q->get_num_patterns(); unsigned num_no_pats = q->get_num_no_patterns(); expr_ref_vector new_pats(m_manager, num_pats, q->get_patterns()); @@ -606,7 +604,6 @@ void rewriter_tpl::process_quantifier(quantifier * q, frame & fr) { if (!m_cfg.reduce_quantifier(q, new_body, new_pats.data(), new_no_pats.data(), m_r, m_pr)) { if (fr.m_new_child) { m_r = m().update_quantifier(q, num_pats, new_pats.data(), num_no_pats, new_no_pats.data(), new_body); - SASSERT(is_well_sorted(m(), m_r)); } else { TRACE(rewriter_reuse, tout << "reusing:\n" << mk_ismt2_pp(q, m()) << "\n";); From d1aaae68560c5ece880171053b201be55f1a09e4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Jul 2026 17:43:01 -0700 Subject: [PATCH 37/48] allow lambdas in select positions for model, ignore beta redex incompletness when using arrays for MBQI --- src/smt/theory_array_full.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index 865d5bca95..86652d12ba 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -853,6 +853,8 @@ namespace smt { } bool theory_array_full::has_non_beta_as_array() { + if (ctx.get_fparams().m_array_fake_support) + return false; for (enode* n : m_as_array) { for (enode* p : n->get_parents()) if (ctx.is_relevant(p) && !ctx.is_beta_redex(p, n)) { @@ -862,7 +864,7 @@ namespace smt { } for (enode* n : m_lambdas) for (enode* p : n->get_parents()) - if (ctx.is_relevant(p) && !is_default(p) && !ctx.is_beta_redex(p, n) && !is_congruent_eq(p)) { + if (ctx.is_relevant(p) && !is_default(p) && !is_select(p) && !ctx.is_beta_redex(p, n) && !is_congruent_eq(p)) { TRACE(array, tout << "lambda is not a beta redex " << enode_pp(p, ctx) << "\n"); return true; } From d9d3be959c7ffa961a5d002282a544b5b28e885e Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Jul 2026 17:55:01 -0700 Subject: [PATCH 38/48] Pin macOS wheel target to 13.0 in release and nightly workflows (#10054) Wheels started inheriting `macosx_15_0` tags because macOS jobs run on newer runners and no deployment target was pinned. That blocks wheel installation on macOS 13/14 hosts and forces source builds. - **macOS deployment target pinning** - Added `MACOSX_DEPLOYMENT_TARGET: "13.0"` to both macOS build jobs (`x64`, `arm64`) in: - `.github/workflows/release.yml` - `.github/workflows/nightly.yml` - **Stable macOS artifact OS metadata** - Updated macOS `mk_unix_dist.py` invocations to pass `--os=osx-13.0` in both workflows, so artifact metadata stays aligned with the intended minimum macOS compatibility used for Python wheel tagging. ```yaml mac-build-x64: runs-on: macos-15 env: MACOSX_DEPLOYMENT_TARGET: "13.0" steps: - name: Build run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=x64 --os=osx-13.0 ``` --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- .github/workflows/nightly.yml | 8 ++++++-- .github/workflows/release.yml | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index d2febd8e83..df36d1f73d 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -33,6 +33,8 @@ jobs: name: "Mac Build x64" runs-on: macos-latest timeout-minutes: 90 + env: + MACOSX_DEPLOYMENT_TARGET: "13.0" steps: - name: Checkout code uses: actions/checkout@v7.0.0 @@ -43,7 +45,7 @@ jobs: python-version: '3.x' - name: Build - run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=x64 + run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=x64 --os=osx-13.0 - name: Validate libz3.dylib and z3 architecture (must be x86_64) run: | @@ -69,6 +71,8 @@ jobs: name: "Mac ARM64 Build" runs-on: macos-latest timeout-minutes: 90 + env: + MACOSX_DEPLOYMENT_TARGET: "13.0" steps: - name: Checkout code uses: actions/checkout@v7.0.0 @@ -79,7 +83,7 @@ jobs: python-version: '3.x' - name: Build - run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=arm64 + run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=arm64 --os=osx-13.0 - name: Validate libz3.dylib and z3 architecture (must be arm64) run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 07387885bc..1e280e056c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,6 +34,8 @@ jobs: name: "Mac Build x64" runs-on: macos-15 timeout-minutes: 90 + env: + MACOSX_DEPLOYMENT_TARGET: "13.0" steps: - name: Checkout code uses: actions/checkout@v7.0.0 @@ -44,7 +46,7 @@ jobs: python-version: '3.x' - name: Build - run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=x64 + run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=x64 --os=osx-13.0 - name: Validate libz3.dylib and z3 architecture (must be x86_64) run: | @@ -76,6 +78,8 @@ jobs: name: "Mac ARM64 Build" runs-on: macos-15 timeout-minutes: 90 + env: + MACOSX_DEPLOYMENT_TARGET: "13.0" steps: - name: Checkout code uses: actions/checkout@v7.0.0 @@ -86,7 +90,7 @@ jobs: python-version: '3.x' - name: Build - run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=arm64 + run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=arm64 --os=osx-13.0 - name: Validate libz3.dylib and z3 architecture (must be arm64) run: | From b2f0d0682aaef74c6b9c62419c2ff28912c8168f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 7 Jul 2026 09:20:14 -0700 Subject: [PATCH 39/48] fix loop bug in ho_matching and add throttle configurations --- src/ast/euf/ho_matcher.cpp | 14 ++++++++++++++ src/ast/euf/ho_matcher.h | 6 ++++++ src/params/smt_params.cpp | 2 ++ src/params/smt_params.h | 2 ++ src/params/smt_params_helper.pyg | 2 ++ src/smt/smt_model_finder.cpp | 9 ++++++++- src/smt/smt_quantifier.cpp | 1 + 7 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/ast/euf/ho_matcher.cpp b/src/ast/euf/ho_matcher.cpp index 4a793e2159..03eb319614 100644 --- a/src/ast/euf/ho_matcher.cpp +++ b/src/ast/euf/ho_matcher.cpp @@ -67,7 +67,15 @@ namespace euf { void ho_matcher::search() { IF_VERBOSE(10, display(verbose_stream())); + + unsigned budget = m_max_iterations; while (m.inc()) { + if (budget-- == 0) { + IF_VERBOSE(2, verbose_stream() << "ho_matcher: search budget exhausted\n"); + while (!m_backtrack.empty()) + backtrack(); + break; + } // Q, B -> Q', B'. Push work on the backtrack stack and new work items // e, Bw -> Q', B'. Consume backtrack stack if (!m_goals.empty()) @@ -271,6 +279,11 @@ namespace euf { if (wi.is_done()) return false; + if (wi.level > m_max_depth) { + wi.set_done(); + return false; + } + reduce(wi); auto t = wi.t; @@ -349,6 +362,7 @@ namespace euf { if (qp->get_decl_sort(i) != qt->get_decl_sort(i)) return false; m_goals.push(wi.level, wi.term_offset() + td, qp->get_expr(), qt->get_expr()); + wi.set_done(); return true; } diff --git a/src/ast/euf/ho_matcher.h b/src/ast/euf/ho_matcher.h index e513332fe2..1c952bcbbd 100644 --- a/src/ast/euf/ho_matcher.h +++ b/src/ast/euf/ho_matcher.h @@ -315,6 +315,8 @@ namespace euf { match_goals m_goals; unitary_patterns m_unitary; ptr_vector m_backtrack; + unsigned m_max_depth = 10; // bound on imitation/projection depth (secondary safety cap) + unsigned m_max_iterations = 10000; // per-search expansion-step budget to guarantee termination mutable array_rewriter m_rewriter; array_util m_array; obj_map m_pat2hopat, m_hopat2pat; @@ -386,6 +388,10 @@ namespace euf { void set_on_match(std::function& on_match) { m_on_match = on_match; } + void set_max_depth(unsigned d) { m_max_depth = d; } + + void set_max_iterations(unsigned n) { m_max_iterations = n; } + void operator()(expr *pat, expr *t, unsigned num_vars); void operator()(expr* pat, expr* t, unsigned num_bound, unsigned num_vars); diff --git a/src/params/smt_params.cpp b/src/params/smt_params.cpp index a64075204c..bd58aeb311 100644 --- a/src/params/smt_params.cpp +++ b/src/params/smt_params.cpp @@ -28,6 +28,8 @@ void smt_params::updt_local_params(params_ref const & _p) { m_relevancy_lvl = p.relevancy(); m_ematching = p.ematching(); m_ho_matching = p.ho_matching(); + m_ho_matching_bound = p.ho_matching_bound(); + m_term_enumeration = p.term_enumeration(); m_induction = p.induction(); m_clause_proof = p.clause_proof(); m_phase_selection = static_cast(p.phase_selection()); diff --git a/src/params/smt_params.h b/src/params/smt_params.h index 7b5efa9919..3d696504ee 100644 --- a/src/params/smt_params.h +++ b/src/params/smt_params.h @@ -110,6 +110,8 @@ struct smt_params : public preprocessor_params, bool m_new_core2th_eq = true; bool m_ematching = true; bool m_ho_matching = false; + unsigned m_ho_matching_bound = 10000; + bool m_term_enumeration = true; bool m_induction = false; bool m_clause_proof = false; symbol m_proof_log; diff --git a/src/params/smt_params_helper.pyg b/src/params/smt_params_helper.pyg index d3f164f3bb..8dc181a2f9 100644 --- a/src/params/smt_params_helper.pyg +++ b/src/params/smt_params_helper.pyg @@ -11,6 +11,8 @@ def_module_params(module_name='smt', ('restricted_quasi_macros', BOOL, False, 'try to find universally quantified formulas that are restricted quasi-macros'), ('ematching', BOOL, True, 'E-Matching based quantifier instantiation'), ('ho_matching', BOOL, False, 'higher-order matching for quantifier instantiation'), + ('ho_matching_bound', UINT, 10000, 'per-problem expansion-step budget of the higher-order matching search; bounds the (undecidable) HO unification to guarantee termination'), + ('term_enumeration', BOOL, True, 'use term enumeration to populate instantiation sets for higher-order variables during model-based quantifier instantiation'), ('phase_selection', UINT, 3, 'phase selection heuristic: 0 - always false, 1 - always true, 2 - phase caching, 3 - phase caching conservative, 4 - phase caching conservative 2, 5 - random, 6 - number of occurrences, 7 - theory'), ('phase_caching_on', UINT, 400, 'number of conflicts while phase caching is on'), ('phase_caching_off', UINT, 100, 'number of conflicts while phase caching is off'), diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 4d06e09d71..62fab4b14c 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -1411,10 +1411,14 @@ namespace smt { } void populate_inst_sets(quantifier *q, auf_solver &s, context *ctx) override { + bool use_term_enum = ctx->get_fparams().m_term_enumeration; + if (!use_term_enum) + return; node *S = s.get_uvar(q, m_var_i); sort *srt = S->get_sort(); IF_VERBOSE(3, verbose_stream() << "ho_var::populate_inst_sets: " << q->get_id() << " " << mk_pp(srt, m) << "\n";); + term_enumeration tn(m); // Add ground terms of type S. // Add productions for functions in E-graph @@ -1423,6 +1427,7 @@ namespace smt { ast_mark visited; tn.add_production(m.mk_true()); tn.add_production(m.mk_false()); + for (enode *n : ctx->enodes()) { if (!ctx->is_relevant(n)) continue; @@ -1431,6 +1436,8 @@ namespace smt { TRACE(model_finder, tout << "inserting " << mk_pp(e, m) << " into inst set\n"); S->insert(e, n->get_generation()); } + else if (!use_term_enum) + continue; else if (is_app(e) && to_app(e)->get_decl()->is_skolem()) ; else if (is_uninterp_const(e)) { @@ -1446,7 +1453,7 @@ namespace smt { tn.add_production(f); } } - + unsigned max_count = 20; for (auto t : tn.enum_terms(srt)) { if (max_count == 0) diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index b7dcb70623..156f9ef80a 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -657,6 +657,7 @@ namespace smt { if (m_fparams->m_ho_matching) { m_ho_matcher = alloc(euf::ho_matcher, m, m_context->get_trail_stack()); + m_ho_matcher->set_max_iterations(m_fparams->m_ho_matching_bound); std::function on_match = [this](euf::ho_subst& s) { on_ho_match(s); }; From ff7e22c05541627f80a52206d04b3ff7f6a70dac Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 7 Jul 2026 10:15:07 -0700 Subject: [PATCH 40/48] make the batch explanation of fixed in row the default --- src/math/lp/lar_solver.cpp | 8 -------- src/math/lp/lp_params_helper.pyg | 1 - src/math/lp/lp_settings.cpp | 1 - src/math/lp/lp_settings.h | 3 --- 4 files changed, 13 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 1144922bfb..d743c5342d 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -1135,15 +1135,7 @@ namespace lp { // Linearize the bound witnesses of all fixed columns in the row together, so the // mark bits walk each dependency sub-DAG shared between columns only once. - // When lp.batch_explain_fixed_in_row is disabled, fall back to explaining each - // fixed column independently (the pre-batching behavior). void lar_solver::explain_fixed_in_row(unsigned row, explanation& ex) { - if (!settings().batch_explain_fixed_in_row()) { - for (auto const& c : get_row(row)) - if (column_is_fixed(c.var())) - explain_fixed_column(c.var(), ex); - return; - } auto& witnesses = m_imp->m_tmp_witnesses; witnesses.reset(); for (auto const& c : get_row(row)) { diff --git a/src/math/lp/lp_params_helper.pyg b/src/math/lp/lp_params_helper.pyg index 89c9730bc0..29a10c2d52 100644 --- a/src/math/lp/lp_params_helper.pyg +++ b/src/math/lp/lp_params_helper.pyg @@ -15,6 +15,5 @@ def_module_params(module_name='lp', ('lcube_flips', UINT, 16, 'maximal number of coordinate flips when repairing the rounded largest cube center, only relevant when lcube is true'), ('int_hammer_period', UINT, 4, 'period (in final_check calls) for the integer cut/cube heuristics (find_cube, hnf, gomory); a smaller value calls them more often'), ('random_hammers', BOOL, True, 'draw the periodic integer heuristic gates (find_cube, lcube, hnf, gomory, dio) at random with the same 1/period rate instead of a deterministic every-k-th-call modulus'), - ('batch_explain_fixed_in_row', BOOL, True, 'linearize the bound witnesses of all fixed columns in a row in a single dependency pass (de-duplicating shared sub-DAGs) instead of explaining each fixed column independently'), )) diff --git a/src/math/lp/lp_settings.cpp b/src/math/lp/lp_settings.cpp index 14e60a5b9f..affc299788 100644 --- a/src/math/lp/lp_settings.cpp +++ b/src/math/lp/lp_settings.cpp @@ -46,7 +46,6 @@ void lp::lp_settings::updt_params(params_ref const& _p) { m_dio_calls_period_decrease = lp_p.dio_calls_period_decrease(); m_dio_run_gcd = lp_p.dio_run_gcd(); m_random_hammers = lp_p.random_hammers(); - m_batch_explain_fixed_in_row = lp_p.batch_explain_fixed_in_row(); m_lcube = lp_p.lcube(); m_lcube_flips = lp_p.lcube_flips(); unsigned hammer_period = lp_p.int_hammer_period(); diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index 5aeb645b78..bc1f2044f5 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -268,7 +268,6 @@ private: unsigned m_dio_calls_period_decrease = 2; bool m_dio_run_gcd = true; bool m_random_hammers = true; - bool m_batch_explain_fixed_in_row = true; bool m_lcube = true; unsigned m_lcube_flips = 16; public: @@ -280,8 +279,6 @@ public: unsigned & dio_calls_period_decrease() { return m_dio_calls_period_decrease; } bool random_hammers() const { return m_random_hammers; } bool & random_hammers() { return m_random_hammers; } - bool batch_explain_fixed_in_row() const { return m_batch_explain_fixed_in_row; } - bool & batch_explain_fixed_in_row() { return m_batch_explain_fixed_in_row; } bool print_external_var_name() const { return m_print_external_var_name; } bool propagate_eqs() const { return m_propagate_eqs;} unsigned hnf_cut_period() const { return m_hnf_cut_period; } From 334f4fa32b48c354eba7f2ee77baa64d7e798a1e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 7 Jul 2026 11:30:33 -0700 Subject: [PATCH 41/48] reduce leaks for sorts --- src/ast/polymorphism_inst.cpp | 4 +++- src/cmd_context/tptp_frontend.cpp | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ast/polymorphism_inst.cpp b/src/ast/polymorphism_inst.cpp index c34f03585c..5070f66d67 100644 --- a/src/ast/polymorphism_inst.cpp +++ b/src/ast/polymorphism_inst.cpp @@ -57,9 +57,11 @@ namespace polymorphism { m_assertions.push_back(e); t.push(push_back_vector(m_assertions)); u.collect_type_vars(e, inst.m_tvs); + auto* init = alloc(substitution, m); inst.m_subst = alloc(substitutions); - inst.m_subst->insert(alloc(substitution, m)); + inst.m_subst->insert(init); m_instances.insert(e, inst); + t.push(new_obj_trail(init)); t.push(new_obj_trail(inst.m_subst)); t.push(insert_map(m_instances, e)); } diff --git a/src/cmd_context/tptp_frontend.cpp b/src/cmd_context/tptp_frontend.cpp index 8ab6b31672..ff656b7ef4 100644 --- a/src/cmd_context/tptp_frontend.cpp +++ b/src/cmd_context/tptp_frontend.cpp @@ -553,8 +553,10 @@ class tptp_parser { // Multi-argument A * B > C is represented as Array(A, Array(B, C)) (curried). sort* get_ho_sort(ptr_vector const& domain, sort* range) { sort* s = range; - for (int i = (int)domain.size() - 1; i >= 0; --i) + for (int i = (int)domain.size() - 1; i >= 0; --i) { s = m_array.mk_array_sort(domain[i], s); + m_pinned_sorts.push_back(s); + } return s; } @@ -1369,6 +1371,7 @@ class tptp_parser { sort* arg_sort = arg->get_sort(); sort* result_sort = m.is_bool(arg_sort) ? m.mk_bool_sort() : m_univ; sort* arr_sort = m_array.mk_array_sort(arg_sort, result_sort); + m_pinned_sorts.push_back(arr_sort); e = coerce_arg(e, arr_sort); } else { // Array but domain may not match arg sort — coerce arg @@ -2217,6 +2220,7 @@ class tptp_parser { // If arg is Bool-sorted, result is likely Bool too (modal/connective application) sort* result_sort = m.is_bool(arg_sort) ? m.mk_bool_sort() : m_univ; sort* arr_sort = m_array.mk_array_sort(arg_sort, result_sort); + m_pinned_sorts.push_back(arr_sort); e = coerce_arg(e, arr_sort); } else { // Array but domain may not match arg sort — coerce arg From 5f70ba10a9eaad09623ae4c996c7b61300d01d9a Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Jul 2026 13:01:10 -0700 Subject: [PATCH 42/48] Remove temporary LP batching parameter and make batched explanation unconditional (#10066) This removes the temporary `lp.batch_explain_fixed_in_row` knob added with the recent LP changes. The batched fixed-column explanation path is kept as the only implementation, matching the follow-up review comments. - **Problem** - The new LP setting exposed a temporary fallback path that is no longer needed. - Keeping both paths added parameter surface area and settings plumbing without a lasting behavioral distinction. - **Changes** - **Remove parameter definition** - Delete `lp.batch_explain_fixed_in_row` from LP parameter generation. - **Remove settings plumbing** - Drop the stored field, accessor methods, and parameter update wiring from `lp_settings`. - **Keep batched explanation as default behavior** - Remove the runtime branch in `lar_solver::explain_fixed_in_row`. - Always linearize fixed-column witnesses together in a single dependency pass. - **Resulting simplification** - The solver no longer carries a dead configuration toggle for fixed-row explanation. - The batched dependency-linearization path remains intact and is now the sole code path. ```c++ void lar_solver::explain_fixed_in_row(unsigned row, explanation& ex) { auto& witnesses = m_imp->m_tmp_witnesses; witnesses.reset(); for (auto const& c : get_row(row)) { if (!column_is_fixed(c.var())) continue; const column& ul = m_imp->m_columns[c.var()]; witnesses.push_back(ul.lower_bound_witness()); witnesses.push_back(ul.upper_bound_witness()); } m_imp->m_tmp_dependencies.reset(); m_imp->m_dependencies.linearize(witnesses, m_imp->m_tmp_dependencies); for (auto ci : m_imp->m_tmp_dependencies) ex.push_back(ci); } ``` Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Nikolaj Bjorner --- src/math/lp/lar_solver.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index d743c5342d..8be0cca91b 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -3025,4 +3025,3 @@ namespace lp { } } // namespace lp - From 5fc2b04dea9e53c7f194a55f36f01381d8da64d1 Mon Sep 17 00:00:00 2001 From: Can Cebeci Date: Tue, 7 Jul 2026 13:01:44 -0700 Subject: [PATCH 43/48] Mark quantifier instances that lead to conflicts as relevant (#10064) This patch fixes a corner case where quantifier conflicts can create fresh terms that aren't marked as relevant. I couldn't easily produce a minimal query that this patch turns stable, nor did the patch stabilize the query I have been working on, but I think the example below still illustrates the problem: ``` (set-option :auto_config false) (set-option :type_check true) (set-option :smt.case_split 3) (set-option :smt.mbqi false) (declare-fun R (Int) Bool) (declare-fun S (Int) Bool) (declare-fun dummy (Int) Bool) (assert (or (R 0) (dummy 0))) (assert (forall ((x Int)) (! (and (not (R x)) (not (S x))) :pattern ((R x)) :qid not_r_not_s ))) (assert (forall ((x Int)) (! (S x) :pattern ((S x)) :qid s_true ))) (check-sat) ``` The query is unstable (due to the same interaction between relevancy and triggers in https://github.com/Z3Prover/z3/issues/7444): if the solver assigns `(dummy 0)` first, it returns `unknown`. If the solver assigns `(R 0)` first, we would expect an `unsat`. The current implementation returns `unknown` because `not_r_not_s` leads to a quantifier conflict, which creates `S(x)` without marking it (or any of its ancestors) as relevant. --------- Co-authored-by: Can Cebeci Co-authored-by: Nikolaj Bjorner --- src/smt/smt_context.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 8786e73bae..191afdeac6 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1733,8 +1733,16 @@ namespace smt { void internalize_instance(expr * body, proof * pr, unsigned generation) { internalize_assertion(body, pr, generation); - if (relevancy()) + if (relevancy()) { + // if the instantiation creates a conflict, we backtrack immediately. + // to retain the conflict clause being relevant we mark it here. + // if the instantiation does not create a conflict, default relevancy propagation applies. + if (inconsistent() && is_app(body)) { + for (auto arg : *to_app(body)) + mark_as_relevant(arg); + } m_case_split_queue->internalize_instance_eh(body, generation); + } } unsigned get_unsat_core_size() const { From 22c779c77c79e327bc96b17eff72c8b4cff347f1 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson <5377127+levnach@users.noreply.github.com> Date: Tue, 7 Jul 2026 13:02:37 -0700 Subject: [PATCH 44/48] [snapshot-regression-fix] Fix elim_uncnstr disabled by manager-wide has_type_vars() flag (iss-6260/small-2) (#10063) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fixes a completeness regression where `elim_uncnstr` was silently disabled for ordinary (non-polymorphic) goals, detected by the `snapshot-regression` corpus. - **Originating discussion:** https://github.com/Z3Prover/bench/discussions/3054 - **Benchmark:** `iss-6260/small-2.smt2` (corpus `Z3Prover/bench`, `inputs/issues/iss-6260/`) - **Divergence:** recorded oracle `sat` → current z3 produces `unknown` ### Divergence diff ```diff --- small-2.expected.out (expected) +++ produced (current z3) @@ -1,3 +1,3 @@ -sat +unknown (error "line 17 column 0: unexpected character") (error "line 17 column 1: unexpected character") ``` (The `(error ...)` lines are expected: the benchmark contains a stray ```` ``` ```` fence on line 17. Only the `sat` → `unknown` change is the regression.) ## Root cause `git bisect` over the regression window pins the flip to commit `208cc5686` ("fix build"), which added `|| m().has_type_vars()` to the `elim_uncnstr_tactic` guard and an equivalent `if (m.has_type_vars()) return;` to the `elim_unconstrained` simplifier. `ast_manager::has_type_vars()` is a **manager-wide, sticky** flag: it is set to `true` as soon as *any* type variable is created, and is never reset. In particular `finite_set_decl_plugin::init()` creates type variables `A`/`B` to define its polymorphic signatures. Those type variables never occur in the user's assertions, but once the finite_set plugin is initialized — which happens while processing this benchmark — the flag is globally `true` (confirmed by instrumenting `mk_type_var`: the only type vars created for this benchmark are the finite_set signature vars `A` and `B`). As a result `elim_uncnstr` bails out for goals that contain **no** polymorphic terms at all, i.e. it is effectively disabled. Unconstrained subterms that used to be eliminated now reach the theory solvers. For this benchmark the (single) assertion is `(not (xor (>= x 0) (>= x1 0) (>= x 0) x4 (str.contains ...)))`. The duplicated `(>= x 0)` cancels (`a xor a = false`), and the free Boolean `x4` can fix the parity regardless of the value of the `str.contains` term, so the goal is trivially `sat`. That `str.contains`/`str.replace_re` subterm is unconstrained and was previously removed by `elim_uncnstr`; without that elimination it reaches `theory_seq`, which marks `str.replace_re` as unhandled and gives up in `final_check` → `unknown` (`incomplete (theory seq)`). ## Fix Make the guard precise. Keep `has_type_vars()` as a cheap pre-filter (matching existing usage in `ast_translation.cpp` and `ast_manager::has_type_var`), but only bail out when the goal / asserted formulas **actually** contain type-variable typed terms, using the existing `polymorphism::util::has_type_vars(expr*)`. This preserves the polymorphism crash-protection (goals with genuine type-variable terms still skip `elim_uncnstr`) while restoring `elim_uncnstr` for the vast majority of goals that merely triggered a polymorphic-plugin initialization. Both twin guards (the `elim_uncnstr` tactic and the `elim_unconstrained` simplifier) are fixed consistently. ## Validation Built this checkout and re-ran the benchmark (step 5 of the fixer workflow): - `./configure && make -C build -j$(nproc)` — Z3 version 4.17.0. - Unpatched master reproduced the divergence: `z3 -T:20 iss-6260/small-2.smt2` → `unknown`. - After the fix, `z3 -T:20 inputs/issues/iss-6260/small-2.smt2` produces **exactly** the recorded oracle: ``` sat (error "line 17 column 0: unexpected character") (error "line 17 column 1: unexpected character") (error "line 17 column 2: unexpected character") ``` - Regression sanity checks: sibling `iss-6260/small.smt2` unchanged (`sat`); plain arithmetic unconstrained goals unchanged; polymorphic goals with genuine type-variable terms (including `declare-type-var` and forcing `(check-sat-using (then elim-uncnstr smt))`) still solve without crashing — the guard still fires for those. Opened as a **draft** for human review. > Generated by [Fix a Z3 snapshot-regression divergence](https://github.com/Z3Prover/bench/actions/runs/28844840657) · 861.2 AIC · ⌖ 45.8 AIC · ⊞ 8.9K · [◷](https://github.com/search?q=repo%3AZ3Prover%2Fz3+%22gh-aw-workflow-id%3A+snapshot-regression-fixer%22&type=pullrequests) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/ast/simplifiers/elim_unconstrained.cpp | 15 +++++++++++++-- src/tactic/core/elim_uncnstr_tactic.cpp | 18 +++++++++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 120fe06729..c7742861b1 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -116,6 +116,7 @@ eliminate: #include "ast/ast_ll_pp.h" #include "ast/ast_pp.h" #include "ast/recfun_decl_plugin.h" +#include "ast/polymorphism_util.h" #include "ast/simplifiers/elim_unconstrained.h" elim_unconstrained::elim_unconstrained(ast_manager& m, dependent_expr_state& fmls) : @@ -425,8 +426,18 @@ void elim_unconstrained::update_model_trail(generic_model_converter& mc, vector< void elim_unconstrained::reduce() { if (!m_config.m_enabled) return; - if (m.has_type_vars()) - return; + // has_type_vars() is a manager-wide flag that is set as soon as any type variable is + // created, including the ones used to define polymorphic signatures of builtin plugins + // (e.g. finite_set) that never occur in the asserted formulas. Only bail out when the + // formulas actually contain type-variable typed terms, which this simplifier cannot invert. + if (m.has_type_vars()) { + polymorphism::util u(m); + for (unsigned i : indices()) { + auto [f, p, d] = m_fmls[i](); + if (u.has_type_vars(f)) + return; + } + } generic_model_converter_ref mc = alloc(generic_model_converter, m, "elim-unconstrained"); m_inverter.set_model_converter(mc.get()); m_created_compound = true; diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index a0eaeead94..7aecd4d505 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -27,6 +27,7 @@ Notes: #include "ast/datatype_decl_plugin.h" #include "ast/seq_decl_plugin.h" #include "ast/for_each_expr.h" +#include "ast/polymorphism_util.h" #include "tactic/core/collect_occs.h" #include "ast/ast_smt2_pp.h" #include "ast/ast_ll_pp.h" @@ -936,6 +937,21 @@ class elim_uncnstr_tactic : public tactic { m_rw = alloc(rw, m(), produce_proofs, m_vars, m_nonvars, m_disabled, m_mc.get(), m_max_memory, m_max_steps); } + // The manager-wide has_type_vars() flag is a coarse over-approximation: it becomes + // true as soon as any type variable is created, including the type variables used to + // define the polymorphic signatures of builtin plugins (e.g. finite_set). Those never + // occur in the actual goal, so relying on the global flag needlessly disables this + // tactic. Check whether the goal itself contains type-variable typed terms instead. + bool goal_has_type_vars(goal_ref const & g) { + if (!m().has_type_vars()) + return false; + polymorphism::util u(m()); + for (unsigned i = 0; i < g->size(); ++i) + if (u.has_type_vars(g->form(i))) + return true; + return false; + } + void run(goal_ref const & g, goal_ref_buffer & result) { bool produce_proofs = g->proofs_enabled(); TRACE(goal, g->display(tout);); @@ -945,7 +961,7 @@ class elim_uncnstr_tactic : public tactic { collect_occs p; p(*g, m_vars); disable_quantified(g); - if (m_vars.empty() || recfun::util(m()).has_rec_defs() || m().has_type_vars()) { + if (m_vars.empty() || recfun::util(m()).has_rec_defs() || goal_has_type_vars(g)) { result.push_back(g.get()); // did not increase depth since it didn't do anything. return; From 165a4a42bc80f3293c943b40841cb588817557ab Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Jul 2026 13:26:44 -0700 Subject: [PATCH 45/48] Fix debug-only well-sorted traversal freeing temporary assertions (#10067) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Ubuntu `python make - MT` job was failing in unit tests because the debug-time well-sorted check could invalidate freshly constructed assertion expressions during solver entry. This surfaced as crashes in `theory_dl` and `seq_rewriter`, not as logic bugs in those tests. - **Root cause** - `is_well_sorted` traversed the input through a temporary `expr_ref`/`subterms` wrapper. - For freshly built assertions passed directly into `assert_expr`, that temporary ownership could drop the last refcount during validation and free the AST before the solver used it. - **Change** - Reworked the traversal in `src/ast/well_sorted.cpp` to walk raw `expr*` nodes explicitly. - The checker now validates subterms without taking transient ownership of the asserted expression. - **Effect** - Debug validation remains intact. - Temporary formulas survive the well-sorted check, so assertion-time validation no longer corrupts the caller’s AST. - **Representative change** ```cpp ptr_vector todo; expr_mark visited; todo.push_back(e); while (!todo.empty()) { expr* term = todo.back(); todo.pop_back(); if (visited.is_marked(term)) continue; visited.mark(term, true); if (is_app(term)) { for (expr* arg : *to_app(term)) if (!visited.is_marked(arg)) todo.push_back(arg); check_app(to_app(term)); } else if (is_var(term)) { check_var(to_var(term)); } else if (is_quantifier(term)) { check_quantifier(to_quantifier(term)); } } ``` --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- src/ast/well_sorted.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/ast/well_sorted.cpp b/src/ast/well_sorted.cpp index a498b0dae5..3fe519369d 100644 --- a/src/ast/well_sorted.cpp +++ b/src/ast/well_sorted.cpp @@ -36,13 +36,27 @@ struct well_sorted_proc { well_sorted_proc(ast_manager & m):m(m), m_error(false) {} void check(expr* e) { - for (auto term : subterms::ground(expr_ref(e, m))) { - if (is_app(term)) + ptr_vector todo; + expr_mark visited; + todo.push_back(e); + while (!todo.empty()) { + expr* term = todo.back(); + todo.pop_back(); + if (visited.is_marked(term)) + continue; + visited.mark(term, true); + if (is_app(term)) { + for (expr* arg : *to_app(term)) + if (!visited.is_marked(arg)) + todo.push_back(arg); check_app(to_app(term)); - else if (is_var(term)) + } + else if (is_var(term)) { check_var(to_var(term)); - else if (is_quantifier(term)) + } + else if (is_quantifier(term)) { check_quantifier(to_quantifier(term)); + } } } @@ -119,4 +133,3 @@ bool is_well_sorted(ast_manager const & m, expr * n) { return !p.m_error; } - From 7040a74d1a55b3472ab10930d89aa350f039d06e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 7 Jul 2026 14:59:50 -0700 Subject: [PATCH 46/48] defer ho-matching to lazy mam Signed-off-by: Nikolaj Bjorner --- src/smt/smt_quantifier.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 156f9ef80a..68358e3b02 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -867,10 +867,7 @@ namespace smt { << " compiled=" << (p1 != mp) << " p1=" << mk_pp(p1, m) << "\n"); if (p1 != mp) { - if (!unary && j >= num_eager_multi_patterns) - m_lazy_mam->add_pattern(q1, p1); - else - m_mam->add_pattern(q1, p1); + m_lazy_mam->add_pattern(q1, p1); } } if (!unary) From 965db51b5c3f42e9813d0dc1a47f2afbe4314d63 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 7 Jul 2026 09:56:37 -0700 Subject: [PATCH 47/48] use patterns --- src/smt/smt_quantifier.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 68358e3b02..455ea83c74 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -219,9 +219,7 @@ namespace smt { STRACE(triggers, tout <<", Pat: "<< expr_ref(pat, m());); STRACE(causality, tout <<", Father:";); } - for (auto n : used_enodes) { - enode *orig = std::get<0>(n); - enode *substituted = std::get<1>(n); + for (auto [orig, substituted] : used_enodes) { (void) substituted; if (orig == nullptr) { STRACE(causality, tout << " #" << substituted->get_owner_id();); @@ -260,9 +258,7 @@ namespace smt { log_justification_to_root(out, bindings[i], already_visited, m_context, m()); } - for (auto n : used_enodes) { - enode *orig = std::get<0>(n); - enode *substituted = std::get<1>(n); + for (auto [orig, substituted] : used_enodes) { if (orig != nullptr) { log_justification_to_root(out, orig, already_visited, m_context, m()); log_justification_to_root(out, substituted, already_visited, m_context, m()); From c56b2cbaa4eaa0aec9ac17c2274e34c6465bff04 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Jul 2026 15:29:05 -0700 Subject: [PATCH 48/48] fix pattern inference to deal with binders properly, pin sorts in tptp_frontend --- src/ast/pattern/pattern_inference.cpp | 49 +++++++-------------- src/cmd_context/tptp_frontend.cpp | 12 ++--- src/solver/assertions/asserted_formulas.cpp | 1 + 3 files changed, 22 insertions(+), 40 deletions(-) diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp index b02aac4eab..87f17beb87 100644 --- a/src/ast/pattern/pattern_inference.cpp +++ b/src/ast/pattern/pattern_inference.cpp @@ -121,6 +121,7 @@ void pattern_inference_cfg::collect::operator()(expr * n, unsigned num_bindings) SASSERT(m_info.empty()); SASSERT(m_todo.empty()); SASSERT(m_cache.empty()); + SASSERT(is_well_sorted(m, n)); m_num_bindings = num_bindings; m_todo.push_back(entry(n, 0)); while (!m_todo.empty()) { @@ -173,21 +174,15 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) { switch (n->get_kind()) { case AST_VAR: { unsigned idx = to_var(n)->get_idx(); - if (idx >= delta) { - idx = idx - delta; - uint_set free_vars; - if (idx < m_num_bindings) - free_vars.insert(idx); - info * i = nullptr; - if (delta == 0) - i = alloc(info, m, n, free_vars, 1); - else - i = alloc(info, m, m.mk_var(idx, to_var(n)->get_sort()), free_vars, 1); - save(n, delta, i); - } - else { + if (idx >= m_num_bindings + delta) { save(n, delta, nullptr); + return; } + uint_set free_vars; + if (delta <= idx) + free_vars.insert(idx - delta); + info * i = alloc(info, m, n, free_vars, 1); + save(n, delta, i); return; } case AST_APP: { @@ -243,7 +238,8 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) { // stating properties about these operators. family_id fid = c->get_family_id(); decl_kind k = c->get_decl_kind(); - if (!free_vars.empty() && + if (!free_vars.empty() && + delta == 0 && (fid != m_afid || (fid == m_afid && !m_owner.m_nested_arith_only && (k == OP_DIV || k == OP_IDIV || k == OP_MOD || k == OP_REM || k == OP_MUL)))) { TRACE(pattern_inference, tout << "potential candidate: \n" << mk_pp(new_node, m) << "\n";); m_owner.add_candidate(new_node, free_vars, size); @@ -254,30 +250,15 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) { quantifier * q = to_quantifier(n); unsigned num_decls = q->get_num_decls(); info * body_info = nullptr; - m_cache.find(entry(q->get_expr(), delta + num_decls), body_info); - if (body_info == nullptr) { + expr *body = q->get_expr(); + m_cache.find(entry(body, delta + num_decls), body_info); + if (!body_info) { save(n, delta, nullptr); return; } - // The lambda/quantifier itself is a valid sub-term in a pattern. - // body_info->m_node was normalized into the *outer* quantifier's de - // Bruijn space (the enclosing binders, including this lambda's own - // num_decls binders, were stripped). Re-wrapping it under the lambda - // therefore requires shifting the (outer) free variables back up by - // num_decls so they do not collide with the lambda's bound variables. - // The lambda's own bound variables never occur in body_info (any - // sub-term referring to them was rejected as a candidate), so the - // shift is always sound. - expr * body = body_info->m_node.get(); - expr_ref new_body(m); - if (num_decls > 0) { - var_shifter shift(m); - shift(body, num_decls, new_body); - } - else - new_body = body; + expr *new_body = body_info->m_node.get(); quantifier_ref new_q(m); - if (new_body.get() != q->get_expr()) + if (new_body != q->get_expr()) new_q = m.update_quantifier(q, new_body); else new_q = q; diff --git a/src/cmd_context/tptp_frontend.cpp b/src/cmd_context/tptp_frontend.cpp index ff656b7ef4..e452651571 100644 --- a/src/cmd_context/tptp_frontend.cpp +++ b/src/cmd_context/tptp_frontend.cpp @@ -553,10 +553,9 @@ class tptp_parser { // Multi-argument A * B > C is represented as Array(A, Array(B, C)) (curried). sort* get_ho_sort(ptr_vector const& domain, sort* range) { sort* s = range; - for (int i = (int)domain.size() - 1; i >= 0; --i) { - s = m_array.mk_array_sort(domain[i], s); - m_pinned_sorts.push_back(s); - } + for (unsigned i = domain.size(); i-- > 0; ) + s = m_array.mk_array_sort(domain[i], s); + m_pinned_sorts.push_back(s); return s; } @@ -1535,7 +1534,7 @@ class tptp_parser { // For function-style definitions, wrap value in lambdas if (!param_vars.empty()) { expr_ref result = value; - for (int i = (int)param_vars.size() - 1; i >= 0; --i) { + for (unsigned i = param_vars.size(); i-- > 0; ) { expr_ref abs_body(m); expr_abstract(m, 0, 1, (expr* const*)¶m_vars[i], result, abs_body); sort* s = param_vars[i]->get_sort(); @@ -1976,7 +1975,7 @@ class tptp_parser { // Create nested single-variable lambdas (curried) to match our curried array encoding. // ^[X:A, Y:B] : body becomes ^[X:A] : (^[Y:B] : body) with sort Array(A, Array(B, body_sort)) expr_ref result = body; - for (int i = (int)vars.size() - 1; i >= 0; --i) { + for (unsigned i = vars.size(); i-- > 0; ) { expr_ref abs_body(m); expr_abstract(m, 0, 1, (expr* const*)&vars[i], result, abs_body); sort* s = vars[i]->get_sort(); @@ -2877,6 +2876,7 @@ expr_ref tptp_parser::parse_term() { if (!m_array.is_array(e_sort)) { sort* arg_sort = arg->get_sort(); sort* arr_sort = m_array.mk_array_sort(arg_sort, m_univ); + m_pinned_sorts.push_back(arr_sort); e = coerce_arg(e, arr_sort); } else { sort* dom = get_array_domain(e_sort, 0); diff --git a/src/solver/assertions/asserted_formulas.cpp b/src/solver/assertions/asserted_formulas.cpp index 32b8bb9b65..6abf5dbb96 100644 --- a/src/solver/assertions/asserted_formulas.cpp +++ b/src/solver/assertions/asserted_formulas.cpp @@ -496,6 +496,7 @@ void asserted_formulas::simplify_fmls::operator()() { expr_ref result(m); proof_ref result_pr(m); simplify(j, result, result_pr); + SASSERT(is_well_sorted(m, j.fml())); if (m.proofs_enabled()) { if (!result_pr) result_pr = m.mk_rewrite(j.fml(), result); result_pr = m.mk_modus_ponens(j.pr(), result_pr);