mirror of
https://github.com/Z3Prover/z3
synced 2026-08-03 20:53:30 +00:00
[coz3-deepperf-fix] Batch fixed-column bound-witness linearization per row in lar_solver (#10029)
### 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). <!-- gh-aw-workflow-id: coz3-deepperf-fix --> <!-- gh-aw-workflow-call-id: Z3Prover/bench/coz3-deepperf-fix --> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
e1f99b569d
commit
f37b435923
6 changed files with 38 additions and 11 deletions
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue