3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-05-16 15:15:35 +00:00
z3/src/math/lp/int_cube_lll.h
Lev Nachmanson ff49d60e64 lexicographical version
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
2026-05-15 19:20:02 -07:00

95 lines
3.3 KiB
C++

/*++
Copyright (c) 2025 Microsoft Corporation
Module Name:
int_cube_lll.h
Abstract:
LLL-style cube heuristic for the integer-LP solver.
Generalization of int_cube. Instead of the unit cube C = [-1/2, 1/2]^n
we use a parallelepiped K = B * C, where B is an n x n unimodular
integer matrix found by a *monotone* greedy basis-reduction that
minimizes the actual cube cost
C(B) = (1/2) * (||A * B||_1 + ||B||_1)
= sum_r delta_row(r, B) + sum_j delta_col(j, B)
over GL_n(Z). Atomic move is a single elementary column operation
col_j(B) <- col_j(B) - q * col_k(B) (q in Z, j != k)
The q candidates for a fixed pair (j, k) include the floor/ceil of the
weighted median of the breakpoints {A_row(r,j)/A_row(r,k)} and
{B(i,j)/B(i,k)} (weights are the absolute values of the denominators).
They are scored lexicographically: first minimize the number/severity
of bounded rows/columns whose later delta-tightening would collapse
their box, then minimize C(B). This keeps the greedy from accepting a
cost-improving basis move that merely sets up a bail-tighten failure.
This addresses the regression of int_cube_hnf, whose triangulation
can blow up the column-delta term ||B||_1: in 153 random instances
(3x3 to 5x5, coefficients in [-20, 20]) HNF cube lost to plain cube
on >99% of inputs, with an average cost ratio of 3x-50x worse, while
pairwise-greedy LLL won or tied on 100% (see findings.md in the
session-state).
Soundness: identical to int_cube_hnf. We work with a saved column
snapshot of x_J, tighten the LP, find a real-feasible point x*, and
round y* = B^{-1} x* to nearest integer in lattice coordinates, then
lift z = B * round(y*).
Author:
Lev Nachmanson (levnach)
Revision History:
--*/
#pragma once
#include "math/lp/lia_move.h"
#include "math/lp/numeric_pair.h"
#include "util/vector.h"
namespace lp {
class int_solver;
class lar_solver;
class lar_term;
class int_cube_lll {
class int_solver& lia;
class lar_solver& lra;
vector<unsigned> m_J;
vector<unsigned> m_col_to_J;
vector<unsigned> m_term_js;
vector<vector<mpq>> m_H; // H = A * B; m x n
vector<vector<mpq>> m_B; // n x n unimodular
vector<vector<mpq>> m_B_inv; // B^{-1} = product of inverse elementaries
vector<mpq> m_col_w; // per-column weight in the cube cost
vector<impq> m_term_delta;
vector<impq> m_col_delta;
vector<impq> m_saved_x_J;
public:
int_cube_lll(int_solver& lia);
lia_move operator()();
private:
bool collect_J_and_terms();
bool build_matrix();
void compute_col_weights();
bool compute_basis();
bool reduce_pair(unsigned j, unsigned k, bool& improved);
bool too_big(const mpq& v) const;
bool column_bounds_are_integral(unsigned j) const;
bool tighten_terms_for_lll_cube();
bool tighten_columns_for_lll_cube();
bool tighten_column_bound_by_delta(unsigned j, const impq& delta);
void compute_deltas();
void save_x_J();
void apply_rounding();
};
}