67 const absl::Span<const int64_t> coeffs) {
68 std::vector<int> result;
69 DCHECK(coeffs[0] != std::numeric_limits<int64_t>::min());
70 int64_t min_abs_coeff = std::abs(coeffs[0]);
72 int64_t global_gcd = min_abs_coeff;
73 for (
int i = 1;
i < coeffs.size(); ++
i) {
74 DCHECK(coeffs[
i] != std::numeric_limits<int64_t>::min());
75 const int64_t abs_coeff = std::abs(coeffs[
i]);
76 global_gcd = std::gcd(global_gcd, abs_coeff);
77 if (abs_coeff < min_abs_coeff) {
78 min_abs_coeff = abs_coeff;
82 if (min_abs_coeff == global_gcd)
return result;
83 int64_t current_gcd = min_abs_coeff;
84 result.reserve(coeffs.size());
85 result.push_back(min_term);
86 while (current_gcd > global_gcd) {
90 int64_t new_gcd = std::gcd(current_gcd, std::abs(coeffs[0]));
92 for (
int i = 1;
i < coeffs.size(); ++
i) {
93 const int64_t gcd = std::gcd(current_gcd, std::abs(coeffs[
i]));
99 result.push_back(term);
100 current_gcd = new_gcd;
102 const int initial_count =
static_cast<int>(result.size());
103 for (
int i = 0;
i < coeffs.size(); ++
i) {
106 for (
int j = 0; j < initial_count; ++j) {
107 if (result[j] ==
i) {
121 absl::Span<const int64_t> var_lbs,
122 absl::Span<const int64_t> var_ubs) {
123 const int64_t global_gcd = Gcd(coeffs);
125 if (rhs % global_gcd != 0)
return {.has_solutions =
false};
128 if (pivots.empty()) {
129 return {.no_reformulation_needed =
true, .has_solutions =
true};
131 int64_t current_gcd = std::abs(coeffs[pivots[0]]);
134 std::vector<absl::int128> special_solution = {current_gcd /
137 std::vector<std::vector<absl::int128>> kernel_basis;
138 kernel_basis.reserve(coeffs.size() - 1);
140 for (;
i < pivots.size() && current_gcd > global_gcd; ++
i) {
141 const int64_t coeff = coeffs[pivots[
i]];
142 const int64_t new_gcd = std::gcd(current_gcd, std::abs(coeff));
143 kernel_basis.emplace_back(
i + 1);
144 kernel_basis.back().back() = current_gcd / new_gcd;
145 for (
int i = 0;
i < special_solution.size(); ++
i) {
146 kernel_basis.back()[
i] = -special_solution[
i] * coeff / new_gcd;
149 kernel_basis.back());
152 int64_t
a = current_gcd;
157 for (
int i = 0;
i < special_solution.size(); ++
i) {
158 special_solution[
i] *= u;
160 special_solution.push_back(v);
163 current_gcd = new_gcd;
165 const int replaced_variables_count =
i;
166 for (;
i < pivots.size(); ++
i) {
167 const int64_t coeff = coeffs[pivots[
i]];
168 kernel_basis.emplace_back(replaced_variables_count);
169 for (
int i = 0;
i < special_solution.size(); ++
i) {
170 kernel_basis.back()[
i] = -special_solution[
i] * coeff / global_gcd;
173 kernel_basis.back());
176 for (
int i = 0;
i < special_solution.size(); ++
i) {
177 special_solution[
i] *= rhs / global_gcd;
193 std::vector<absl::int128> kernel_vars_lbs(replaced_variables_count - 1);
194 std::vector<absl::int128> kernel_vars_ubs(replaced_variables_count - 1);
195 for (
int i = replaced_variables_count - 1;
i >= 0; --
i) {
196 absl::int128 lb = var_lbs[pivots[
i]] - special_solution[
i];
197 absl::int128 ub = var_ubs[pivots[
i]] - special_solution[
i];
199 const int bounds_to_update =
i > 0 ?
i - 1 : 0;
200 for (
int j = bounds_to_update + 1; j < replaced_variables_count - 1; ++j) {
201 const absl::int128 coeff = kernel_basis[j][
i];
202 lb -= coeff * (coeff < 0 ? kernel_vars_lbs[j] : kernel_vars_ubs[j]);
203 ub -= coeff * (coeff < 0 ? kernel_vars_ubs[j] : kernel_vars_lbs[j]);
205 for (
int j = replaced_variables_count - 1; j < pivots.size() - 1; ++j) {
206 const absl::int128 coeff = kernel_basis[j][
i];
207 const int64_t lb_var = var_lbs[pivots[j + 1]];
208 const int64_t ub_var = var_ubs[pivots[j + 1]];
209 lb -= coeff * (coeff < 0 ? lb_var : ub_var);
210 ub -= coeff * (coeff < 0 ? ub_var : lb_var);
212 const absl::int128 coeff = kernel_basis[bounds_to_update][
i];
213 const absl::int128 deduced_lb =
CeilOfRatio(coeff > 0 ? lb : ub, coeff);
214 const absl::int128 deduced_ub =
FloorOfRatio(coeff > 0 ? ub : lb, coeff);
216 kernel_vars_lbs[
i - 1] = deduced_lb;
217 kernel_vars_ubs[
i - 1] = deduced_ub;
219 kernel_vars_lbs[0] = std::max(kernel_vars_lbs[0], deduced_lb);
220 kernel_vars_ubs[0] = std::min(kernel_vars_ubs[0], deduced_ub);
223 for (
int i = 0;
i < replaced_variables_count - 1; ++
i) {
224 if (kernel_vars_lbs[
i] > kernel_vars_ubs[
i])
225 return {.has_solutions =
false};
227 return {.no_reformulation_needed =
false,
228 .has_solutions =
true,
229 .index_permutation = pivots,
230 .special_solution = special_solution,
231 .kernel_basis = kernel_basis,
232 .kernel_vars_lbs = kernel_vars_lbs,
233 .kernel_vars_ubs = kernel_vars_ubs};