mirror of
https://github.com/Z3Prover/z3
synced 2026-07-26 17:02:38 +00:00
[coz3-deepperf-fix] Avoid full-column rescan on each delta halving in lar_solver::init_model (#10217)
## Summary `lp::lar_solver::init_model()` (`src/math/lp/lar_solver.cpp`) picks an infinitesimal `delta` that maps every distinct rational-pair column value `(x, y)` to a *distinct* scalar `x + delta*y`, halving `delta` whenever a collision is detected. The previous implementation rebuilt **both** the set of distinct pairs and the set of scalars from a full O(n) pass over all columns on *every* halving, and the pair set is entirely independent of `delta`. ## Change - Build the delta-invariant set of distinct column pairs (`m_set_of_different_pairs`) **once**, before the halving loop. - On each halving, only rebuild the scalar set by iterating over the **distinct pairs** rather than rescanning all `n` columns (including duplicates). The collision test and the selected `delta` are unchanged: the loop still halves `delta` whenever the number of distinct scalars is less than the number of distinct pairs, and terminates when the scalar map is injective. The early-`break` versus end-of-pass check produce the same `delta` sequence because a size discrepancy on a full pass is exactly the injectivity-failure condition. ## Cost argument Let `n` = column count and `D` = number of *distinct* column pairs (`D ≤ n`), and `H` = number of halvings. - Before: `O(H · n · log D)` — every halving re-inserts all `n` columns into both sets. - After: `O(n · log D + H · D · log D)` — the pair set is built once; each halving touches only the `D` distinct pairs. This removes the repeated full rescan from the halving loop and skips redundant work for duplicate columns, turning a per-halving O(n) rebuild into a one-time cost plus O(D) per halving. ## Evidence Profiled under callgrind (deterministic instruction counts), differential correctness preserved, static-analysis hygiene clean: - Target function self-instructions: **2,695,433,533 → 2,084,074,808** (−22.7%). - Total program instructions ratio: **0.904** (−9.6%). - Wall-time speedup: **~6.1%**. - Differential correctness: identical results (no mismatches). Logic class exercised: **QF_LRA / linear real arithmetic** model construction. <!-- gh-aw-workflow-id: coz3-deepperf-fix --> <!-- gh-aw-workflow-call-id: Z3Prover/bench/coz3-deepperf-fix --> --------- Co-authored-by: z3prover-ci-bot[bot] <305651407+z3prover-ci-bot[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
parent
c15ef957eb
commit
19781df2bc
1 changed files with 13 additions and 12 deletions
|
|
@ -1571,22 +1571,23 @@ namespace lp {
|
|||
return false;
|
||||
|
||||
m_imp->m_delta = get_core_solver().find_delta_for_strict_bounds(m_imp->m_settings.m_epsilon);
|
||||
unsigned j;
|
||||
unsigned n = get_core_solver().r_x().size();
|
||||
// the set of distinct column values does not depend on m_delta, so collect it once
|
||||
// and only rescan the distinct pairs when m_delta is halved
|
||||
m_imp->m_set_of_different_pairs.clear();
|
||||
for (unsigned j = 0; j < n; ++j)
|
||||
m_imp->m_set_of_different_pairs.insert(get_core_solver().r_x(j));
|
||||
bool collision;
|
||||
do {
|
||||
m_imp->m_set_of_different_pairs.clear();
|
||||
collision = false;
|
||||
m_imp->m_set_of_different_singles.clear();
|
||||
for (j = 0; j < n; ++j) {
|
||||
const numeric_pair<mpq>& rp = get_core_solver().r_x(j);
|
||||
mpq x = rp.x + m_imp->m_delta * rp.y;
|
||||
m_imp->m_set_of_different_pairs.insert(rp);
|
||||
m_imp->m_set_of_different_singles.insert(x);
|
||||
if (m_imp->m_set_of_different_pairs.size() != m_imp->m_set_of_different_singles.size()) {
|
||||
m_imp->m_delta /= mpq(2);
|
||||
break;
|
||||
}
|
||||
for (const numeric_pair<mpq>& rp : m_imp->m_set_of_different_pairs)
|
||||
m_imp->m_set_of_different_singles.insert(rp.x + m_imp->m_delta * rp.y);
|
||||
if (m_imp->m_set_of_different_singles.size() != m_imp->m_set_of_different_pairs.size()) {
|
||||
m_imp->m_delta /= mpq(2);
|
||||
collision = true;
|
||||
}
|
||||
} while (j != n);
|
||||
} while (collision);
|
||||
TRACE(lar_solver_model, tout << "delta = " << m_imp->m_delta << "\nmodel:\n";);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue