OR-Tools  9.6
diophantine.h
Go to the documentation of this file.
1 // Copyright 2010-2022 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #ifndef OR_TOOLS_SAT_DIOPHANTINE_H_
15 #define OR_TOOLS_SAT_DIOPHANTINE_H_
16 
17 #include <cstdint>
18 #include <vector>
19 
20 #include "absl/numeric/int128.h"
21 #include "absl/types/span.h"
22 
23 namespace operations_research::sat {
24 
25 // Reduces v modulo the elements_to_consider first elements of the (normal
26 // form) basis. The leading coeff of a basis element is the last one. In other
27 // terms, basis has the form:
28 // * A 0 0 0 0 0
29 // * * B 0 0 0 0
30 // * * * C 0 0 0
31 // .............
32 // with non-zero pivots elements A, B, C, ... and the reduction is performed in
33 // such a way that for a pivot P of the basis and the correspond entry x of v at
34 // the end of the reduction, we have
35 // -floor(|P|/2) <= v < ceil(|P|/2).
36 void ReduceModuloBasis(const std::vector<std::vector<absl::int128>>& basis,
37  const int elements_to_consider,
38  std::vector<absl::int128>& v);
39 
40 // Returns an ordering of the indices of coefficients such that the GCD of its
41 // initial segments decreases fast. As the product of the 15 smallest prime
42 // numbers is the biggest fitting in an int64_t, it is guaranteed that the GCD
43 // becomes stationary after at most 15 steps. Returns an empty vector if the GCD
44 // is equal to the absolute value of one of the coefficients.
45 std::vector<int> GreedyFastDecreasingGcd(absl::Span<const int64_t> coeffs);
46 
47 // The comments here describe basic feature of the fields. See more details in
48 // the description of the function below SolveDiophantine.
50  // One of the coefficients is equal to the GCD of all coefficients.
52 
53  // false if the equation is proven infeasible.
55 
56  // Order of indices of the next fields.
57  // This is a permutation of [0, num_vars_of_initial_equation). It starts by
58  // the chosen pivots.
59  std::vector<int> index_permutation;
60 
61  // Special (reduced) solution of the constraint. Only coefficients of pivots
62  // are specified. Further coefficients are 0.
63  // All coefficients except the first one are guaranteed to be int64_t (see
64  // ReductionModuloBasis).
65  std::vector<absl::int128> special_solution;
66 
67  // Reduced basis of the kernel.
68  // All coefficients except the first one are guaranteed to be int64_t (see
69  // ReductionModuloBasis).
70  // Size is index_order.size() - 1.
71  std::vector<std::vector<absl::int128>> kernel_basis;
72 
73  // Bounds of kernel multiples.
74  // Same size as kernel_basis.
75  std::vector<absl::int128> kernel_vars_lbs;
76  std::vector<absl::int128> kernel_vars_ubs;
77 };
78 
79 // Gives a parametric description of the solutions of the Diophantine equation
80 // with n variables:
81 // sum(coeffs[i] * x[i]) = rhs.
82 // var_lbs and var_ubs are bounds on desired values for variables x_i's.
83 //
84 // It is known that, ignoring variable bounds, the set of solutions of such an
85 // equation is
86 // 1. either empty if the gcd(coeffs[i]) does not divide rhs;
87 // 2. or the sum of a special solution and an element of the kernel of the
88 // equation.
89 // In case 1, the function return .has_solution = false;
90 // In case 2, if one coefficient is equal to the GCD of all (in absolute value),
91 // returns .no_reformulation_needed = true. Otherwise, it behaves as follows:
92 //
93 // The kernel of the equation as dimension n-1.
94 //
95 // We assume we permute the variable by index_permutation, such that the first k
96 // k terms have a gcd equal to the gcd of all coefficient (it is possible to do
97 // this with k <= 15).
98 // Under this assumption, we can find:
99 // * a special solution that is entirely supported by the k first variables;
100 // * a basis {b[0], b[1], ..., b[n-2]} of the kernel such that:
101 // - for i = 0 ... k-2, b[i][j] = 0 if j > i+1;
102 // - for i >= k-1, b[i][j] = 0 if j >= k except b[i][i+1] = 1.
103 // The function returns the k first coefficients of the special solution and the
104 // at most k first non-zero coefficients of each elements of the basis.
105 //
106 // In other terms, solutions have the form, for i in [0, k):
107 // x[i] = special_solution[i] + sum(sum linear_basis[j][i] * y[j])
108 // where:
109 // * y[j] is a newly created variable for 0 <= j < k - 1;
110 // * y[j] = x[index_permutation[j + 1]] otherwise.
111 //
112 // The function reduces the basis and the special solution in such a way that
113 // the only coefficients that could get outside the range of input coefficients
114 // are the first coefficient of the special solution and the first coefficient
115 // of each element of the basis (see ReduceModuloBasis for more specific
116 // conditions).
117 //
118 // Moreover, the function compute bounds for the newly created variables using
119 // bounds of the variables passed as input. Note that:
120 // * It can happen that a computed upper bound is lower than the corresponding
121 // lower bound. It happens when a newly created variable can be bounded on an
122 // interval containing no integer. In such a case, the function returns
123 // .has_solution = false.
124 // * The returned bounds describe a necessary condition for
125 // x[i] in [var_lbs[i], var_ubs[i]]
126 // but not a sufficient one.
127 DiophantineSolution SolveDiophantine(absl::Span<const int64_t> coeffs,
128  int64_t rhs,
129  absl::Span<const int64_t> var_lbs,
130  absl::Span<const int64_t> var_ubs);
131 
132 } // namespace operations_research::sat
133 
134 #endif // OR_TOOLS_SAT_DIOPHANTINE_H_
DiophantineSolution SolveDiophantine(absl::Span< const int64_t > coeffs, int64_t rhs, absl::Span< const int64_t > var_lbs, absl::Span< const int64_t > var_ubs)
Definition: diophantine.cc:117
std::vector< int > GreedyFastDecreasingGcd(const absl::Span< const int64_t > coeffs)
Definition: diophantine.cc:64
void ReduceModuloBasis(const std::vector< std::vector< absl::int128 >> &basis, const int elements_to_consider, std::vector< absl::int128 > &v)
Definition: diophantine.cc:43
std::vector< absl::int128 > special_solution
Definition: diophantine.h:65
std::vector< absl::int128 > kernel_vars_ubs
Definition: diophantine.h:76
std::vector< absl::int128 > kernel_vars_lbs
Definition: diophantine.h:75
std::vector< std::vector< absl::int128 > > kernel_basis
Definition: diophantine.h:71