70 const absl::Span<const int64_t> coeffs) {
71 std::vector<int> result;
72 DCHECK(coeffs[0] != std::numeric_limits<int64_t>::min());
73 int64_t min_abs_coeff = std::abs(coeffs[0]);
75 int64_t global_gcd = min_abs_coeff;
76 for (
int i = 1;
i < coeffs.size(); ++
i) {
77 DCHECK(coeffs[
i] != std::numeric_limits<int64_t>::min());
78 const int64_t abs_coeff = std::abs(coeffs[
i]);
79 global_gcd = std::gcd(global_gcd, abs_coeff);
80 if (abs_coeff < min_abs_coeff) {
81 min_abs_coeff = abs_coeff;
85 if (min_abs_coeff == global_gcd)
return result;
86 int64_t current_gcd = min_abs_coeff;
87 result.reserve(coeffs.size());
88 result.push_back(min_term);
89 while (current_gcd > global_gcd) {
93 int64_t new_gcd = std::gcd(current_gcd, std::abs(coeffs[0]));
95 for (
int i = 1;
i < coeffs.size(); ++
i) {
96 const int64_t gcd = std::gcd(current_gcd, std::abs(coeffs[
i]));
102 result.push_back(term);
103 current_gcd = new_gcd;
105 const int initial_count =
static_cast<int>(result.size());
106 for (
int i = 0;
i < coeffs.size(); ++
i) {
109 for (
int j = 0; j < initial_count; ++j) {
110 if (result[j] ==
i) {
124 absl::Span<const int64_t> var_lbs,
125 absl::Span<const int64_t> var_ubs) {
126 const int64_t global_gcd = Gcd(coeffs);
128 if (rhs % global_gcd != 0)
return {.has_solutions =
false};
131 if (pivots.empty()) {
132 return {.no_reformulation_needed =
true, .has_solutions =
true};
134 int64_t current_gcd = std::abs(coeffs[pivots[0]]);
137 std::vector<absl::int128> special_solution = {current_gcd /
140 std::vector<std::vector<absl::int128>> kernel_basis;
141 kernel_basis.reserve(coeffs.size() - 1);
143 for (;
i < pivots.size() && current_gcd > global_gcd; ++
i) {
144 const int64_t coeff = coeffs[pivots[
i]];
145 const int64_t new_gcd = std::gcd(current_gcd, std::abs(coeff));
146 kernel_basis.emplace_back(
i + 1);
147 kernel_basis.back().back() = current_gcd / new_gcd;
148 for (
int i = 0;
i < special_solution.size(); ++
i) {
149 kernel_basis.back()[
i] = -special_solution[
i] * coeff / new_gcd;
152 kernel_basis.back());
155 int64_t a = current_gcd;
160 for (
int i = 0;
i < special_solution.size(); ++
i) {
161 special_solution[
i] *= u;
163 special_solution.push_back(v);
166 current_gcd = new_gcd;
168 const int replaced_variables_count =
i;
169 for (;
i < pivots.size(); ++
i) {
170 const int64_t coeff = coeffs[pivots[
i]];
171 kernel_basis.emplace_back(replaced_variables_count);
172 for (
int i = 0;
i < special_solution.size(); ++
i) {
173 kernel_basis.back()[
i] = -special_solution[
i] * coeff / global_gcd;
176 kernel_basis.back());
179 for (
int i = 0;
i < special_solution.size(); ++
i) {
180 special_solution[
i] *= rhs / global_gcd;
196 std::vector<absl::int128> kernel_vars_lbs(replaced_variables_count - 1);
197 std::vector<absl::int128> kernel_vars_ubs(replaced_variables_count - 1);
198 for (
int i = replaced_variables_count - 1;
i >= 0; --
i) {
199 absl::int128 lb = var_lbs[pivots[
i]] - special_solution[
i];
200 absl::int128 ub = var_ubs[pivots[
i]] - special_solution[
i];
202 const int bounds_to_update =
i > 0 ?
i - 1 : 0;
203 for (
int j = bounds_to_update + 1; j < replaced_variables_count - 1; ++j) {
204 const absl::int128 coeff = kernel_basis[j][
i];
205 lb -= coeff * (coeff < 0 ? kernel_vars_lbs[j] : kernel_vars_ubs[j]);
206 ub -= coeff * (coeff < 0 ? kernel_vars_ubs[j] : kernel_vars_lbs[j]);
208 for (
int j = replaced_variables_count - 1; j < pivots.size() - 1; ++j) {
209 const absl::int128 coeff = kernel_basis[j][
i];
210 const int64_t lb_var = var_lbs[pivots[j + 1]];
211 const int64_t ub_var = var_ubs[pivots[j + 1]];
212 lb -= coeff * (coeff < 0 ? lb_var : ub_var);
213 ub -= coeff * (coeff < 0 ? ub_var : lb_var);
215 const absl::int128 coeff = kernel_basis[bounds_to_update][
i];
216 const absl::int128 deduced_lb =
218 const absl::int128 deduced_ub =
221 kernel_vars_lbs[
i - 1] = deduced_lb;
222 kernel_vars_ubs[
i - 1] = deduced_ub;
224 kernel_vars_lbs[0] = std::max(kernel_vars_lbs[0], deduced_lb);
225 kernel_vars_ubs[0] = std::min(kernel_vars_ubs[0], deduced_ub);
228 for (
int i = 0;
i < replaced_variables_count - 1; ++
i) {
229 if (kernel_vars_lbs[
i] > kernel_vars_ubs[
i])
230 return {.has_solutions =
false};
232 return {.no_reformulation_needed =
false,
233 .has_solutions =
true,
234 .index_permutation = pivots,
235 .special_solution = special_solution,
236 .kernel_basis = kernel_basis,
237 .kernel_vars_lbs = kernel_vars_lbs,
238 .kernel_vars_ubs = kernel_vars_ubs};