Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
variable_and_expressions.h
Go to the documentation of this file.
1// Copyright 2010-2024 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// IWYU pragma: private, include "ortools/math_opt/cpp/math_opt.h"
15// IWYU pragma: friend "ortools/math_opt/cpp/.*"
16
17// An object oriented wrapper for variables in ModelStorage (used internally by
18// Model) with support for arithmetic operations to build linear expressions and
19// express linear constraints.
20//
21// Types are:
22// - Variable: a reference to a variable of an ModelStorage.
23//
24// - LinearExpression: a weighted sum of variables with an optional offset;
25// something like `3*x + 2*y + 5`.
26//
27// - LinearTerm: a term of a linear expression, something like `2*x`. It is
28// used as an intermediate in the arithmetic operations that builds linear
29// expressions.
30//
31// - (Lower|Upper)BoundedLinearExpression: two classes representing the result
32// of the comparison of a LinearExpression with a constant. For example `3*x
33// + 2*y + 5 >= 3`.
34//
35// - BoundedLinearExpression: the result of the comparison of a linear
36// expression with two bounds, an upper bound and a lower bound. For example
37// `2 <= 3*x + 2*y + 5 <= 3`; or `4 >= 3*x + 2*y + 5 >= 1`.
38//
39// - QuadraticTermKey: a key used internally to represent a pair of Variables.
40//
41// - QuadraticTerm: a term representing the product of a scalar coefficient
42// and two Variables (possibly the same); something like `2*x*y` or `3*x*x`.
43// It is used as an intermediate in the arithmetic operations that build
44// quadratic expressions.
45//
46// - QuadraticExpression: a sum of a quadratic terms, linear terms, and a
47// scalar offset; something like `3*x*y + 2*x*x + 4x + 5`.
48//
49// - VariablesEquality: the result of comparing two Variable instances with
50// the == operator. For example `a == b`. This intermediate class support
51// implicit conversion to both bool and BoundedLinearExpression types. This
52// enables using variables as key of maps (using the conversion to bool)
53// without preventing adding constraints of variable equality.
54//
55// The basic arithmetic operators are overloaded for those types so that we can
56// write math expressions with variables to build linear expressions. The >=, <=
57// and == comparison operators are overloaded to produce BoundedLinearExpression
58// that can be used to build constraints.
59//
60// For example we can have:
61// const Variable x = ...;
62// const Variable y = ...;
63// const LinearExpression expr = 2 * x + 3 * y - 2;
64// const BoundedLinearExpression bounded_expr = 1 <= 2 * x + 3 * y - 2 <= 10;
65//
66// To making working with containers of doubles/Variables/LinearExpressions
67// easier, the template methods Sum() and InnerProduct() are provided, e.g.
68// const std::vector<int> ints = ...;
69// const std::vector<double> doubles = ...;
70// const std::vector<Variable> vars = ...;
71// const std::vector<LinearTerm> terms = ...;
72// const std::vector<LinearExpression> exprs = ...;
73// const LinearExpression s1 = Sum(ints);
74// const LinearExpression s2 = Sum(doubles);
75// const LinearExpression s3 = Sum(vars);
76// const LinearExpression s4 = Sum(terms);
77// const LinearExpression s5 = Sum(exprs);
78// const LinearExpression p1 = InnerProduct(ints, vars);
79// const LinearExpression p2 = InnerProduct(terms, doubles);
80// const LinearExpression p3 = InnerProduct(doubles, exprs);
81// These methods work on any iterable type (defining begin() and end()). For
82// InnerProduct, the inputs must be of equal size, and a compile time error will
83// be generated unless at least one input is a container of a type implicitly
84// convertible to double.
85//
86// Pre C++20, avoid the use of std::accumulate and std::inner_product with
87// LinearExpression, they cause a quadratic blowup in running time.
88//
89// While there is some complexity in the source, users typically should not need
90// to look at types other than Variable and LinearExpression too closely. Their
91// code usually will only refer to those types.
92#ifndef OR_TOOLS_MATH_OPT_CPP_VARIABLE_AND_EXPRESSIONS_H_
93#define OR_TOOLS_MATH_OPT_CPP_VARIABLE_AND_EXPRESSIONS_H_
94
95#include <stdint.h>
96
97#include <initializer_list>
98#include <iterator>
99#include <limits>
100#include <ostream>
101#include <string>
102#include <utility>
103
104#include "absl/container/flat_hash_map.h"
105#include "absl/log/check.h"
106#include "absl/strings/string_view.h"
107#include "ortools/base/logging.h"
109#include "ortools/math_opt/cpp/key_types.h" // IWYU pragma: export
112
113namespace operations_research {
114namespace math_opt {
115
116// Forward declaration needed by Variable.
117class LinearExpression;
118
119// A value type that references a variable from ModelStorage. Usually this type
120// is passed by copy.
121//
122// This type implements https://abseil.io/docs/cpp/guides/hash (see
123// VariablesEquality for details about how operator== works).
124class Variable {
125 public:
126 // The typed integer used for ids.
127 using IdType = VariableId;
128
129 // Usually users will obtain variables using Model::AddVariable(). There
130 // should be little for users to build this object from an ModelStorage.
131 inline Variable(const ModelStorage* storage, VariableId id);
132
133 // Each call to AddVariable will produce Variables id() increasing by one,
134 // starting at zero. Deleted ids are NOT reused. Thus, if no variables are
135 // deleted, the ids in the model will be consecutive.
136 inline int64_t id() const;
137
138 inline VariableId typed_id() const;
139 inline const ModelStorage* storage() const;
140
141 inline double lower_bound() const;
142 inline double upper_bound() const;
143 inline bool is_integer() const;
144 inline absl::string_view name() const;
145
146 template <typename H>
147 friend H AbslHashValue(H h, const Variable& variable);
148 friend std::ostream& operator<<(std::ostream& ostr, const Variable& variable);
149
150 inline LinearExpression operator-() const;
151
152 private:
153 const ModelStorage* storage_;
154 VariableId id_;
155};
156
157namespace internal {
158
159// The result of the equality comparison between two Variable.
160//
161// We use an object here to delay the evaluation of equality so that we can use
162// the operator== in two use-cases:
163//
164// 1. when the user want to test that two Variable values references the same
165// variable. This is supported by having this object support implicit
166// conversion to bool.
167//
168// 2. when the user want to use the equality to create a constraint of equality
169// between two variables.
171 // Users are not expected to call this constructor. Instead they should only
172 // use the overload of `operator==` that returns this when comparing two
173 // Variable. For example `x == y`.
175 inline operator bool() const; // NOLINT
178};
179
180} // namespace internal
181
183 const Variable& rhs);
184inline bool operator!=(const Variable& lhs, const Variable& rhs);
185
186template <typename V>
187using VariableMap = absl::flat_hash_map<Variable, V>;
188
189inline std::ostream& operator<<(std::ostream& ostr, const Variable& variable);
190
191// A term in an sum of variables multiplied by coefficients.
193 // Usually this constructor is never called explicitly by users. Instead it
194 // will be implicitly used when writing linear expression. For example `x +
195 // 2*y` will automatically use this constructor to build a LinearTerm from `x`
196 // and the overload of the operator* will also automatically create the one
197 // from `2*y`.
198 inline LinearTerm(Variable variable, double coefficient);
199 inline LinearTerm operator-() const;
200 inline LinearTerm& operator*=(double d);
201 inline LinearTerm& operator/=(double d);
204};
205
206inline LinearTerm operator*(double coefficient, LinearTerm term);
207inline LinearTerm operator*(LinearTerm term, double coefficient);
208inline LinearTerm operator*(double coefficient, Variable variable);
209inline LinearTerm operator*(Variable variable, double coefficient);
210inline LinearTerm operator/(LinearTerm term, double coefficient);
211inline LinearTerm operator/(Variable variable, double coefficient);
212
213// Forward declaration so that we may add it as a friend to LinearExpression
215
216// This class represents a sum of variables multiplied by coefficient and an
217// optional offset constant. For example: "3*x + 2*y + 5".
218//
219// All operations, including constructor, will raise an assertion if the
220// operands involve variables from different Model objects.
221//
222// Contrary to Variable type, expressions owns the linear expression their
223// represent. Hence they are usually passed by reference to prevent unnecessary
224// copies.
225//
226// TODO(b/169415098): add a function to remove zero terms.
227// TODO(b/169415834): study if exact zeros should be automatically removed.
228// TODO(b/169415103): add tests that some expressions don't compile.
230 public:
231 // For unit testing purpose, we define optional counters. We have to
232 // explicitly define the default constructor, copy constructor and assignment
233 // operators in that case. Else we use the defaults.
234#ifndef MATH_OPT_USE_EXPRESSION_COUNTERS
235 LinearExpression() = default;
236 LinearExpression(const LinearExpression& other) = default;
237#else // MATH_OPT_USE_EXPRESSION_COUNTERS
240#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
241 // We have to define a custom move constructor as we need to reset storage_ to
242 // nullptr.
243 inline LinearExpression(LinearExpression&& other) noexcept;
244 // Usually users should use the overloads of operators to build linear
245 // expressions. For example, assuming `x` and `y` are Variable, then `x + 2*y
246 // + 5` will build a LinearExpression automatically.
247 inline LinearExpression(std::initializer_list<LinearTerm> terms,
248 double offset);
249 inline LinearExpression(double offset); // NOLINT
250 inline LinearExpression(Variable variable); // NOLINT
251 inline LinearExpression(const LinearTerm& term); // NOLINT
253 // We have to define a custom move assignment operator as we need to reset
254 // storage_ to nullptr.
255 inline LinearExpression& operator=(LinearExpression&& other) noexcept;
256
257 inline LinearExpression& operator+=(const LinearExpression& other);
258 inline LinearExpression& operator+=(const LinearTerm& term);
259 inline LinearExpression& operator+=(Variable variable);
260 inline LinearExpression& operator+=(double value);
261 inline LinearExpression& operator-=(const LinearExpression& other);
262 inline LinearExpression& operator-=(const LinearTerm& term);
263 inline LinearExpression& operator-=(Variable variable);
264 inline LinearExpression& operator-=(double value);
265 inline LinearExpression& operator*=(double value);
266 inline LinearExpression& operator/=(double value);
267
268 // Adds each element of items to this.
269 //
270 // Specifically, letting
271 // (i_1, i_2, ..., i_n) = items
272 // adds
273 // i_1 + i_2 + ... + i_n
274 // to this.
275 //
276 // Example:
277 // const Variable a = ...;
278 // const Variable b = ...;
279 // const std::vector<Variable> vars = {a, b};
280 // LinearExpression expr(8.0);
281 // expr.AddSum(vars);
282 // Results in expr having the value a + b + 8.0.
283 //
284 // Compile time requirements:
285 // * Iterable is a sequence (an array or object with begin() and end()).
286 // * The type of an element of items is one of double, Variable, LinearTerm
287 // or LinearExpression (or is implicitly convertible to one of these types,
288 // e.g. int).
289 //
290 // Note: The implementation is equivalent to:
291 // for(const auto item : items) {
292 // *this += item;
293 // }
294 template <typename Iterable>
295 inline void AddSum(const Iterable& items);
296
297 // Creates a new LinearExpression object equal to the sum. The implementation
298 // is equivalent to:
299 // LinearExpression expr;
300 // expr.AddSum(items);
301 template <typename Iterable>
302 static inline LinearExpression Sum(const Iterable& items);
303
304 // Adds the inner product of left and right to this.
305 //
306 // Specifically, letting
307 // (l_1, l_2 ..., l_n) = left,
308 // (r_1, r_2, ..., r_n) = right,
309 // adds
310 // l_1 * r_1 + l_2 * r_2 + ... + l_n * r_n
311 // to this.
312 //
313 // Example:
314 // const Variable a = ...;
315 // const Variable b = ...;
316 // const std::vector<Variable> left = {a, b};
317 // const std::vector<double> right = {10.0, 2.0};
318 // LinearExpression expr(3.0);
319 // expr.AddInnerProduct(left, right)
320 // Results in expr having the value 10.0 * a + 2.0 * b + 3.0.
321 //
322 // Compile time requirements:
323 // * LeftIterable and RightIterable are both sequences (arrays or objects
324 // with begin() and end())
325 // * For both left and right, their elements a type of either double,
326 // Variable, LinearTerm or LinearExpression (or type implicitly convertible
327 // to one of these types, e.g. int).
328 // * At least one of left or right has elements with type double (or a type
329 // implicitly convertible, e.g. int).
330 // Runtime requirements (or CHECK fails):
331 // * left and right have an equal number of elements.
332 //
333 // Note: The implementation is equivalent to the following pseudocode:
334 // for(const auto& [l, r] : zip(left, right)) {
335 // *this += l * r;
336 // }
337 // In particular, the multiplication will be performed on the types of the
338 // elements in left and right (take care with low precision types), but the
339 // addition will always use double precision.
340 template <typename LeftIterable, typename RightIterable>
341 inline void AddInnerProduct(const LeftIterable& left,
342 const RightIterable& right);
343
344 // Creates a new LinearExpression object equal to the inner product. The
345 // implementation is equivalent to:
346 // LinearExpression expr;
347 // expr.AddInnerProduct(left, right);
348 template <typename LeftIterable, typename RightIterable>
349 static inline LinearExpression InnerProduct(const LeftIterable& left,
350 const RightIterable& right);
351
352 // Returns the terms in this expression.
353 inline const VariableMap<double>& terms() const;
354 inline double offset() const;
355
356 // Compute the numeric value of this expression when variables are substituted
357 // by their values in variable_values.
358 //
359 // Will CHECK fail if a variable in terms() is missing from variables_values.
360 double Evaluate(const VariableMap<double>& variable_values) const;
361
362 // Compute the numeric value of this expression when variables are substituted
363 // by their values in variable_values, or zero if missing from the map.
364 //
365 // This function won't check that the variables in the input map are indeed in
366 // the same model as the ones of the expression.
368 const VariableMap<double>& variable_values) const;
369
370 inline const ModelStorage* storage() const;
371
372#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
373 static thread_local int num_calls_default_constructor_;
374 static thread_local int num_calls_copy_constructor_;
375 static thread_local int num_calls_move_constructor_;
376 static thread_local int num_calls_initializer_list_constructor_;
377 // Reset all counters in the current thread to 0.
378 static void ResetCounters();
379#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
380
381 private:
383 friend std::ostream& operator<<(std::ostream& ostr,
384 const LinearExpression& expression);
385 friend QuadraticExpression;
386
387 // Sets the storage_ to the input value if nullptr, else CHECKs that it is
388 // equal. Also CHECKs that the input value is not nullptr.
389 inline void SetOrCheckStorage(const ModelStorage* storage);
390
391 // Invariants:
392 // * nullptr, if terms_ is empty
393 // * equal to Variable::storage() of each key of terms_, else
394 const ModelStorage* storage_ = nullptr;
395 VariableMap<double> terms_;
396 double offset_ = 0.0;
397};
398
399// Returns the sum of the elements of items as a LinearExpression.
400//
401// Specifically, letting
402// (i_1, i_2, ..., i_n) = items
403// returns
404// i_1 + i_2 + ... + i_n.
405//
406// Example:
407// const Variable a = ...;
408// const Variable b = ...;
409// const std::vector<Variable> vars = {a, b, a};
410// Sum(vars)
411// => 2.0 * a + b
412// Note, instead of:
413// LinearExpression expr(3.0);
414// expr += Sum(items);
415// Prefer:
416// expr.AddSum(items);
417//
418// See LinearExpression::AddSum() for a precise contract on the type Iterable.
419//
420// If the inner product cannot be represented as a LinearExpression, consider
421// instead QuadraticExpression::Sum().
422template <typename Iterable>
423inline LinearExpression Sum(const Iterable& items);
424
425// Returns the inner product of left and right as a LinearExpression.
426//
427// Specifically, letting
428// (l_1, l_2 ..., l_n) = left,
429// (r_1, r_2, ..., r_n) = right,
430// returns
431// l_1 * r_1 + l_2 * r_2 + ... + l_n * r_n.
432//
433// Example:
434// const Variable a = ...;
435// const Variable b = ...;
436// const std::vector<Variable> left = {a, b};
437// const std::vector<double> right = {10.0, 2.0};
438// InnerProduct(left, right);
439// -=> 10.0 * a + 2.0 * b
440// Note, instead of:
441// LinearExpression expr(3.0);
442// expr += InnerProduct(left, right);
443// Prefer:
444// expr.AddInnerProduct(left, right);
445//
446// Requires that left and right have equal size, see
447// LinearExpression::AddInnerProduct for a precise contract on template types.
448//
449// If the inner product cannot be represented as a LinearExpression, consider
450// instead QuadraticExpression::InnerProduct().
451template <typename LeftIterable, typename RightIterable>
452inline LinearExpression InnerProduct(const LeftIterable& left,
453 const RightIterable& right);
454
455std::ostream& operator<<(std::ostream& ostr,
456 const LinearExpression& expression);
457
458// We intentionally pass one of the LinearExpression argument by value so
459// that we don't make unnecessary copies of temporary objects by using the move
460// constructor and the returned values optimization (RVO).
462inline LinearExpression operator+(Variable lhs, double rhs);
463inline LinearExpression operator+(double lhs, Variable rhs);
465inline LinearExpression operator+(const LinearTerm& lhs, double rhs);
466inline LinearExpression operator+(double lhs, const LinearTerm& rhs);
467inline LinearExpression operator+(const LinearTerm& lhs, Variable rhs);
468inline LinearExpression operator+(Variable lhs, const LinearTerm& rhs);
469inline LinearExpression operator+(const LinearTerm& lhs, const LinearTerm& rhs);
470inline LinearExpression operator+(LinearExpression lhs, double rhs);
471inline LinearExpression operator+(double lhs, LinearExpression rhs);
477 const LinearExpression& rhs);
478inline LinearExpression operator-(Variable lhs, double rhs);
479inline LinearExpression operator-(double lhs, Variable rhs);
481inline LinearExpression operator-(const LinearTerm& lhs, double rhs);
482inline LinearExpression operator-(double lhs, const LinearTerm& rhs);
483inline LinearExpression operator-(const LinearTerm& lhs, Variable rhs);
484inline LinearExpression operator-(Variable lhs, const LinearTerm& rhs);
485inline LinearExpression operator-(const LinearTerm& lhs, const LinearTerm& rhs);
486inline LinearExpression operator-(LinearExpression lhs, double rhs);
487inline LinearExpression operator-(double lhs, LinearExpression rhs);
493 const LinearExpression& rhs);
494inline LinearExpression operator*(LinearExpression lhs, double rhs);
495inline LinearExpression operator*(double lhs, LinearExpression rhs);
496inline LinearExpression operator/(LinearExpression lhs, double rhs);
497
498// A LinearExpression with a lower bound.
500 // Users are not expected to use this constructor. Instead, they should build
501 // this object using overloads of the >= and <= operators. For example, `x + y
502 // >= 3`.
504 double lower_bound);
507};
508
509// A LinearExpression with an upper bound.
511 // Users are not expected to use this constructor. Instead they should build
512 // this object using overloads of the >= and <= operators. For example, `x + y
513 // <= 3`.
515 double upper_bound);
518};
519
520// A LinearExpression with upper and lower bounds.
522 // Users are not expected to use this constructor. Instead they should build
523 // this object using overloads of the >=, <=, and == operators. For example,
524 // `3 <= x + y <= 3`.
526 double lower_bound, double upper_bound);
527 // Users are not expected to use this constructor. This implicit conversion
528 // will be used where a BoundedLinearExpression is expected and the user uses
529 // == comparison of two variables. For example `AddLinearConstraint(x == y);`.
530 inline BoundedLinearExpression( // NOLINT
532 inline BoundedLinearExpression( // NOLINT
533 LowerBoundedLinearExpression lb_expression);
534 inline BoundedLinearExpression( // NOLINT
535 UpperBoundedLinearExpression ub_expression);
536
537 // Returns the actual lower_bound after taking into account the linear
538 // expression offset.
539 inline double lower_bound_minus_offset() const;
540 // Returns the actual upper_bound after taking into account the linear
541 // expression offset.
542 inline double upper_bound_minus_offset() const;
543
547};
548
549std::ostream& operator<<(std::ostream& ostr,
550 const BoundedLinearExpression& bounded_expression);
551
552// We intentionally pass the LinearExpression argument by value so that we don't
553// make unnecessary copies of temporary objects by using the move constructor
554// and the returned values optimization (RVO).
556 double constant);
557inline LowerBoundedLinearExpression operator<=(double constant,
558 LinearExpression expression);
560 double constant);
561inline LowerBoundedLinearExpression operator<=(double constant,
562 const LinearTerm& term);
564 double constant);
565inline LowerBoundedLinearExpression operator<=(double constant,
566 Variable variable);
568 double constant);
569inline UpperBoundedLinearExpression operator>=(double constant,
570 LinearExpression expression);
572 double constant);
573inline UpperBoundedLinearExpression operator>=(double constant,
574 const LinearTerm& term);
576 double constant);
577inline UpperBoundedLinearExpression operator>=(double constant,
578 Variable variable);
579
580// We intentionally pass the UpperBoundedLinearExpression and
581// LowerBoundedLinearExpression arguments by value so that we don't
582// make unnecessary copies of temporary objects by using the move constructor
583// and the returned values optimization (RVO).
585 double rhs);
586inline BoundedLinearExpression operator>=(double lhs,
589 double rhs);
590inline BoundedLinearExpression operator<=(double lhs,
592// We intentionally pass one LinearExpression argument by value so that we don't
593// make unnecessary copies of temporary objects by using the move constructor
594// and the returned values optimization (RVO).
596 const LinearExpression& rhs);
598 const LinearExpression& rhs);
600 const LinearTerm& rhs);
602 const LinearTerm& rhs);
604 LinearExpression rhs);
606 LinearExpression rhs);
612 const LinearTerm& rhs);
614 const LinearTerm& rhs);
622 const LinearExpression& rhs);
624 const LinearTerm& rhs);
626 LinearExpression rhs);
632 const LinearTerm& rhs);
635inline BoundedLinearExpression operator==(const LinearTerm& lhs, double rhs);
636inline BoundedLinearExpression operator==(double lhs, const LinearTerm& rhs);
637inline BoundedLinearExpression operator==(Variable lhs, double rhs);
638inline BoundedLinearExpression operator==(double lhs, Variable rhs);
639
640// Id type used for quadratic terms, i.e. products of two variables.
641using QuadraticProductId = std::pair<VariableId, VariableId>;
642
643// Couples a QuadraticProductId with a ModelStorage, for use with IdMaps.
644// Namely, this key type satisfies the requirements stated in key_types.h.
645// Invariant:
646// * variable_ids_.first <= variable_ids_.second. The constructor will
647// silently correct this if not satisfied by the inputs.
648//
649// This type can be used as a key in ABSL hash containers.
651 public:
652 // NOTE: this definition is for use by IdMap; clients should not rely upon it.
654
655 // NOTE: This constructor will silently re-order the passed id so that, upon
656 // exiting the constructor, variable_ids_.first <= variable_ids_.second.
657 inline QuadraticTermKey(const ModelStorage* storage, QuadraticProductId id);
658 // NOTE: This constructor will CHECK fail if the variable models do not agree,
659 // i.e. first_variable.storage() != second_variable.storage(). It will also
660 // silently re-order the passed id so that, upon exiting the constructor,
661 // variable_ids_.first <= variable_ids_.second.
662 inline QuadraticTermKey(Variable first_variable, Variable second_variable);
663
664 inline QuadraticProductId typed_id() const;
665 inline const ModelStorage* storage() const;
666
667 // Returns the Variable with the smallest id.
668 Variable first() const { return Variable(storage_, variable_ids_.first); }
669
670 // Returns the Variable the largest id.
671 Variable second() const { return Variable(storage_, variable_ids_.second); }
672
673 template <typename H>
674 friend H AbslHashValue(H h, const QuadraticTermKey& key);
675
676 private:
677 const ModelStorage* storage_;
678 QuadraticProductId variable_ids_;
679};
680
681inline std::ostream& operator<<(std::ostream& ostr,
682 const QuadraticTermKey& key);
683
684inline bool operator==(QuadraticTermKey lhs, QuadraticTermKey rhs);
685inline bool operator!=(QuadraticTermKey lhs, QuadraticTermKey rhs);
686
687// Represents a quadratic term in a sum: coefficient * variable_1 * variable_2.
688// Invariant:
689// * first_variable.storage() == second_variable.storage(). The constructor
690// will CHECK fail if not satisfied.
692 public:
693 QuadraticTerm() = delete;
694 // NOTE: This will CHECK fail if
695 // first_variable.storage() != second_variable.storage().
697 double coefficient);
698
699 inline double coefficient() const;
700 inline Variable first_variable() const;
701 inline Variable second_variable() const;
702
703 // This is useful for working with IdMaps
704 inline QuadraticTermKey GetKey() const;
705
706 inline QuadraticTerm& operator*=(double value);
707 inline QuadraticTerm& operator/=(double value);
708
709 private:
711 friend QuadraticTerm operator*(double lhs, QuadraticTerm rhs);
712 friend QuadraticTerm operator*(QuadraticTerm lhs, double rhs);
713 friend QuadraticTerm operator/(QuadraticTerm lhs, double rhs);
714
715 Variable first_variable_;
716 Variable second_variable_;
717 double coefficient_;
718};
719// We declare those operator overloads that result in a QuadraticTerm, stated in
720// lexicographic ordering based on lhs type, rhs type):
722inline QuadraticTerm operator*(double lhs, QuadraticTerm rhs);
727inline QuadraticTerm operator*(QuadraticTerm lhs, double rhs);
728inline QuadraticTerm operator/(QuadraticTerm lhs, double rhs);
729
730template <typename V>
731using QuadraticTermMap = absl::flat_hash_map<QuadraticTermKey, V>;
732
733// This class represents a sum of quadratic terms, linear terms, and constant
734// offset. For example: "3*x*y + 2*x + 1".
735//
736// Mixing terms involving variables from different ModelStorage objects will
737// lead to CHECK fails, including from the constructors.
738//
739// The type owns the associated data representing the terms, and so should
740// usually be passed by (const) reference to avoid unnecessary copies.
741//
742// Note for implementers: Care must be taken to ensure that
743// linear_terms_.storage() and quadratic_terms_.storage() do not disagree. That
744// is, it is forbidden that both are non-null and not equal. Use
745// CheckModelsAgree() and the initializer_list constructor to enforce this
746// invariant in any class or friend method.
748 public:
749 // For unit testing purpose, we define optional counters. We have to
750 // explicitly define the default constructor, copy constructor and assignment
751 // operators in that case. Else we use the defaults.
752#ifndef MATH_OPT_USE_EXPRESSION_COUNTERS
755#else // MATH_OPT_USE_EXPRESSION_COUNTERS
758#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
759 // We have to define a custom move constructor as we need to reset storage_ to
760 // nullptr.
761 inline QuadraticExpression(QuadraticExpression&& other) noexcept;
762 // Users should prefer the default constructor and operator overloads to build
763 // expressions.
764 inline QuadraticExpression(
765 std::initializer_list<QuadraticTerm> quadratic_terms,
766 std::initializer_list<LinearTerm> linear_terms, double offset);
767 inline QuadraticExpression(double offset); // NOLINT
768 inline QuadraticExpression(Variable variable); // NOLINT
769 inline QuadraticExpression(const LinearTerm& term); // NOLINT
770 inline QuadraticExpression(LinearExpression expr); // NOLINT
771 inline QuadraticExpression(const QuadraticTerm& term); // NOLINT
773 // We have to define a custom move assignment operator as we need to reset
774 // storage_ to nullptr.
775 inline QuadraticExpression& operator=(QuadraticExpression&& other) noexcept;
776
777 inline double offset() const;
778 inline const VariableMap<double>& linear_terms() const;
779 inline const QuadraticTermMap<double>& quadratic_terms() const;
780
781 inline QuadraticExpression& operator+=(double value);
782 inline QuadraticExpression& operator+=(Variable variable);
783 inline QuadraticExpression& operator+=(const LinearTerm& term);
785 inline QuadraticExpression& operator+=(const QuadraticTerm& term);
787 inline QuadraticExpression& operator-=(double value);
788 inline QuadraticExpression& operator-=(Variable variable);
789 inline QuadraticExpression& operator-=(const LinearTerm& term);
791 inline QuadraticExpression& operator-=(const QuadraticTerm& term);
793 inline QuadraticExpression& operator*=(double value);
794 inline QuadraticExpression& operator/=(double value);
795
796 // Adds each element of items to this.
797 //
798 // Specifically, letting
799 // (i_1, i_2, ..., i_n) = items
800 // adds
801 // i_1 + i_2 + ... + i_n
802 // to this.
803 //
804 // Example:
805 // const Variable a = ...;
806 // const Variable b = ...;
807 // const std::vector<Variable> vars = {a, b};
808 // const std::vector<QuadraticTerm> terms = {2 * a * b};
809 // QuadraticExpression expr = 8;
810 // expr.AddSum(vars);
811 // expr.AddSum(terms);
812 // Results in expr having the value 2 * a * b + a + b + 8.0.
813 //
814 // Compile time requirements:
815 // * Iterable is a sequence (an array or object with begin() and end()).
816 // * The type of an element of items is one of double, Variable, LinearTerm,
817 // LinearExpression, QuadraticTerm, or QuadraticExpression (or is
818 // implicitly convertible to one of these types, e.g. int).
819 //
820 // Note: The implementation is equivalent to:
821 // for(const auto item : items) {
822 // *this += item;
823 // }
824 template <typename Iterable>
825 inline void AddSum(const Iterable& items);
826
827 // Returns the sum of the elements of items.
828 //
829 // Specifically, letting
830 // (i_1, i_2, ..., i_n) = items
831 // returns
832 // i_1 + i_2 + ... + i_n.
833 //
834 // Example:
835 // const Variable a = ...;
836 // const Variable b = ...;
837 // const std::vector<QuadraticTerm> terms = {a * a, 2 * a * b, 3 * b * a};
838 // QuadraticExpression::Sum(vars)
839 // => a^2 + 5 a * b
840 // Note, instead of:
841 // QuadraticExpression expr(3.0);
842 // expr += QuadraticExpression::Sum(items);
843 // Prefer:
844 // expr.AddSum(items);
845 //
846 // See QuadraticExpression::AddSum() for a precise contract on the type
847 // Iterable.
848 template <typename Iterable>
849 static inline QuadraticExpression Sum(const Iterable& items);
850
851 // Adds the inner product of left and right to this.
852 //
853 // Specifically, letting
854 // (l_1, l_2 ..., l_n) = left,
855 // (r_1, r_2, ..., r_n) = right,
856 // adds
857 // l_1 * r_1 + l_2 * r_2 + ... + l_n * r_n
858 // to this.
859 //
860 // Example:
861 // const Variable a = ...;
862 // const Variable b = ...;
863 // const std::vector<Variable> vars = {a, b};
864 // const std::vector<double> coeffs = {10.0, 2.0};
865 // QuadraticExpression expr = 3.0;
866 // expr.AddInnerProduct(coeffs, vars);
867 // expr.AddInnerProduct(vars, vars);
868 // Results in expr having the value a^2 + b^2 + 10.0 * a + 2.0 * b + 3.0.
869 //
870 // Compile time requirements:
871 // * LeftIterable and RightIterable are both sequences (arrays or objects
872 // with begin() and end())
873 // * For both left and right, their elements are of type double, Variable,
874 // LinearTerm, LinearExpression, QuadraticTerm, or QuadraticExpression (or
875 // is implicitly convertible to one of these types, e.g. int).
876 // Runtime requirements (or CHECK fails):
877 // * The inner product value, and its constitutive intermediate terms, can be
878 // represented as a QuadraticExpression (potentially through an implicit
879 // conversion).
880 // * left and right have an equal number of elements.
881 //
882 // Note: The implementation is equivalent to the following pseudocode:
883 // for(const auto& [l, r] : zip(left, right)) {
884 // *this += l * r;
885 // }
886 // In particular, the multiplication will be performed on the types of the
887 // elements in left and right (take care with low precision types), but the
888 // addition will always use double precision.
889 template <typename LeftIterable, typename RightIterable>
890 inline void AddInnerProduct(const LeftIterable& left,
891 const RightIterable& right);
892
893 // Returns the inner product of left and right.
894 //
895 // Specifically, letting
896 // (l_1, l_2 ..., l_n) = left,
897 // (r_1, r_2, ..., r_n) = right,
898 // returns
899 // l_1 * r_1 + l_2 * r_2 + ... + l_n * r_n.
900 //
901 // Example:
902 // const Variable a = ...;
903 // const Variable b = ...;
904 // const std::vector<Variable> left = {a, a};
905 // const std::vector<Variable> left = {a, b};
906 // QuadraticExpression::InnerProduct(left, right);
907 // -=> a^2 + a * b
908 // Note, instead of:
909 // QuadraticExpression expr(3.0);
910 // expr += QuadraticExpression::InnerProduct(left, right);
911 // Prefer:
912 // expr.AddInnerProduct(left, right);
913 //
914 // Requires that left and right have equal size, see
915 // QuadraticExpression::AddInnerProduct() for a precise contract on template
916 // types.
917 template <typename LeftIterable, typename RightIterable>
918 static inline QuadraticExpression InnerProduct(const LeftIterable& left,
919 const RightIterable& right);
920
921 // Compute the numeric value of this expression when variables are substituted
922 // by their values in variable_values.
923 //
924 // Will CHECK fail if a variable in linear_terms() or quadratic_terms() is
925 // missing from variables_values.
926 double Evaluate(const VariableMap<double>& variable_values) const;
927
928 // Compute the numeric value of this expression when variables are substituted
929 // by their values in variable_values, or zero if missing from the map.
930 //
931 // This function won't check that the variables in the input map are indeed in
932 // the same model as the ones of the expression.
934 const VariableMap<double>& variable_values) const;
935
936 inline const ModelStorage* storage() const;
937
938#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
939 static thread_local int num_calls_default_constructor_;
940 static thread_local int num_calls_copy_constructor_;
941 static thread_local int num_calls_move_constructor_;
942 static thread_local int num_calls_initializer_list_constructor_;
943 static thread_local int num_calls_linear_expression_constructor_;
944 // Reset all counters in the current thread to 0.
945 static void ResetCounters();
946#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
947
948 private:
950 friend std::ostream& operator<<(std::ostream& ostr,
951 const QuadraticExpression& expr);
952
953 // Sets the storage_ to the input value if nullptr, else CHECKs that it is
954 // equal. Also CHECKs that the input value is not nullptr.
955 inline void SetOrCheckStorage(const ModelStorage* storage);
956
957 // Invariants:
958 // * nullptr, if both quadratic_terms_ and linear_terms_ are empty
959 // * equal to Variable::storage() of each key of linear_terms_ and
960 // QuadraticTermKey::storage() of each key of quadratic_terms_, else
961 const ModelStorage* storage_ = nullptr;
962 QuadraticTermMap<double> quadratic_terms_;
963 VariableMap<double> linear_terms_;
964 double offset_ = 0.0;
965};
966
967// We have 6 types that we must consider arithmetic among:
968// 1. double (scalar value)
969// 2. Variable (affine value)
970// 3. LinearTerm (affine value)
971// 4. LinearExpression (affine value)
972// 5. QuadraticTerm (quadratic value)
973// 6. QuadraticExpression (quadratic value)
974// We care only about those methods that result in a QuadraticExpression. For
975// example, multiplying a linear value with a linear value, or adding a scalar
976// to a quadratic value. The single unary method is:
978
979// The binary methods, listed in lexicographic order based on
980// (operator, lhs type #, rhs type #), with the type #s are listed above, are:
981inline QuadraticExpression operator+(double lhs, const QuadraticTerm& rhs);
986 const QuadraticTerm& rhs);
990 const QuadraticTerm& rhs);
993inline QuadraticExpression operator+(const QuadraticTerm& lhs, double rhs);
996 const LinearTerm& rhs);
998 LinearExpression rhs);
1000 const QuadraticTerm& rhs);
1003inline QuadraticExpression operator+(QuadraticExpression lhs, double rhs);
1006 const LinearTerm& rhs);
1008 const LinearExpression& rhs);
1010 const QuadraticTerm& rhs);
1012 const QuadraticExpression& rhs);
1013
1014inline QuadraticExpression operator-(double lhs, const QuadraticTerm& rhs);
1015inline QuadraticExpression operator-(double lhs, QuadraticExpression rhs);
1016inline QuadraticExpression operator-(Variable lhs, const QuadraticTerm& rhs);
1018inline QuadraticExpression operator-(const LinearTerm& lhs,
1019 const QuadraticTerm& rhs);
1020inline QuadraticExpression operator-(const LinearTerm& lhs,
1023 const QuadraticTerm& rhs);
1026inline QuadraticExpression operator-(const QuadraticTerm& lhs, double rhs);
1027inline QuadraticExpression operator-(const QuadraticTerm& lhs, Variable rhs);
1029 const LinearTerm& rhs);
1031 LinearExpression rhs);
1033 const QuadraticTerm& rhs);
1036inline QuadraticExpression operator-(QuadraticExpression lhs, double rhs);
1039 const LinearTerm& rhs);
1041 const LinearExpression& rhs);
1043 const QuadraticTerm& rhs);
1045 const QuadraticExpression& rhs);
1046
1047inline QuadraticExpression operator*(double lhs, QuadraticExpression rhs);
1050 const LinearExpression& rhs);
1053 LinearTerm rhs);
1055 const LinearExpression& rhs);
1056inline QuadraticExpression operator*(QuadraticExpression lhs, double rhs);
1057
1058inline QuadraticExpression operator/(QuadraticExpression lhs, double rhs);
1059
1060// A QuadraticExpression with a lower bound.
1062 // Users are not expected to use this constructor. Instead, they should build
1063 // this object using overloads of the >= and <= operators. For example, `x * y
1064 // >= 3`.
1066 double lower_bound);
1067 // Users are not expected to explicitly use the following constructor.
1068 inline LowerBoundedQuadraticExpression( // NOLINT
1069 LowerBoundedLinearExpression lb_expression);
1070
1073};
1074
1075// A QuadraticExpression with an upper bound.
1077 // Users are not expected to use this constructor. Instead, they should build
1078 // this object using overloads of the >= and <= operators. For example, `x * y
1079 // <= 3`.
1081 double upper_bound);
1082 // Users are not expected to explicitly use the following constructor.
1083 inline UpperBoundedQuadraticExpression( // NOLINT
1084 UpperBoundedLinearExpression ub_expression);
1085
1088};
1089
1090// A QuadraticExpression with upper and lower bounds.
1092 // Users are not expected to use this constructor. Instead, they should build
1093 // this object using overloads of the >=, <=, and == operators. For example,
1094 // `3 <= x * y <= 3`.
1096 double lower_bound, double upper_bound);
1097
1098 // Users are not expected to explicitly use the following constructors.
1099 inline BoundedQuadraticExpression( // NOLINT
1100 internal::VariablesEquality var_equality);
1101 inline BoundedQuadraticExpression( // NOLINT
1102 LowerBoundedLinearExpression lb_expression);
1103 inline BoundedQuadraticExpression( // NOLINT
1104 UpperBoundedLinearExpression ub_expression);
1105 inline BoundedQuadraticExpression( // NOLINT
1106 BoundedLinearExpression bounded_expression);
1107 inline BoundedQuadraticExpression( // NOLINT
1108 LowerBoundedQuadraticExpression lb_expression);
1109 inline BoundedQuadraticExpression( // NOLINT
1110 UpperBoundedQuadraticExpression ub_expression);
1111
1112 // Returns the actual lower_bound after taking into account the quadratic
1113 // expression offset.
1114 inline double lower_bound_minus_offset() const;
1115 // Returns the actual upper_bound after taking into account the quadratic
1116 // expression offset.
1117 inline double upper_bound_minus_offset() const;
1118
1122};
1123
1124std::ostream& operator<<(std::ostream& ostr,
1125 const BoundedQuadraticExpression& bounded_expression);
1126
1127// We intentionally pass the QuadraticExpression argument by value so that we
1128// don't make unnecessary copies of temporary objects by using the move
1129// constructor and the returned values optimization (RVO).
1131 double rhs);
1133 double rhs);
1137 QuadraticTerm rhs);
1138
1142 QuadraticTerm rhs);
1144 double rhs);
1146 double rhs);
1147
1148// We intentionally pass the UpperBoundedQuadraticExpression and
1149// LowerBoundedQuadraticExpression arguments by value so that we don't
1150// make unnecessary copies of temporary objects by using the move constructor
1151// and the returned values optimization (RVO).
1153 UpperBoundedQuadraticExpression lhs, double rhs);
1155 double lhs, LowerBoundedQuadraticExpression rhs);
1157 LowerBoundedQuadraticExpression lhs, double rhs);
1159 double lhs, UpperBoundedQuadraticExpression rhs);
1160// We intentionally pass one QuadraticExpression argument by value so that we
1161// don't make unnecessary copies of temporary objects by using the move
1162// constructor and the returned values optimization (RVO).
1163
1164// Comparisons with lhs = QuadraticExpression
1166 const QuadraticExpression& rhs);
1168 QuadraticTerm rhs);
1170 const LinearExpression& rhs);
1172 LinearTerm rhs);
1174 Variable rhs);
1176 const QuadraticExpression& rhs);
1178 QuadraticTerm rhs);
1180 const LinearExpression& rhs);
1182 LinearTerm rhs);
1184 Variable rhs);
1186 const QuadraticExpression& rhs);
1188 QuadraticTerm rhs);
1190 const LinearExpression& rhs);
1192 LinearTerm rhs);
1194 Variable rhs);
1196 double rhs);
1197// Comparisons with lhs = QuadraticTerm
1201 QuadraticTerm rhs);
1203 LinearExpression rhs);
1209 QuadraticTerm rhs);
1211 LinearExpression rhs);
1217 QuadraticTerm rhs);
1219 LinearExpression rhs);
1223// Comparisons with lhs = LinearExpression
1227 QuadraticTerm rhs);
1231 QuadraticTerm rhs);
1235 QuadraticTerm rhs);
1236// Comparisons with lhs = LinearTerm
1246// Comparisons with lhs = Variable
1256// Comparisons with lhs = Double
1258inline BoundedQuadraticExpression operator==(double lhs,
1260
1263// Inline function implementations /////////////////////////////////////////////
1266
1268// Variable
1270
1271Variable::Variable(const ModelStorage* const storage, const VariableId id)
1272 : storage_(storage), id_(id) {
1273 DCHECK(storage != nullptr);
1274}
1275
1276int64_t Variable::id() const { return id_.value(); }
1278VariableId Variable::typed_id() const { return id_; }
1279
1280const ModelStorage* Variable::storage() const { return storage_; }
1281
1283 return storage_->variable_lower_bound(id_);
1285
1287 return storage_->variable_upper_bound(id_);
1289
1290bool Variable::is_integer() const { return storage_->is_variable_integer(id_); }
1291
1292absl::string_view Variable::name() const {
1293 if (storage()->has_variable(id_)) {
1294 return storage_->variable_name(id_);
1295 }
1296 return "[variable deleted from model]";
1297}
1299template <typename H>
1300H AbslHashValue(H h, const Variable& variable) {
1301 return H::combine(std::move(h), variable.id_.value(), variable.storage_);
1302}
1303
1304std::ostream& operator<<(std::ostream& ostr, const Variable& variable) {
1305 // TODO(b/170992529): handle quoting of invalid characters in the name.
1306 const absl::string_view name = variable.name();
1307 if (name.empty()) {
1308 ostr << "__var#" << variable.id() << "__";
1309 } else {
1310 ostr << name;
1311 }
1312 return ostr;
1313}
1314
1315LinearExpression Variable::operator-() const {
1316 return LinearExpression({LinearTerm(*this, -1.0)}, 0.0);
1317}
1318
1320// LinearTerm
1322
1323LinearTerm::LinearTerm(Variable variable, const double coefficient)
1324 : variable(std::move(variable)), coefficient(coefficient) {}
1325
1326LinearTerm LinearTerm::operator-() const {
1328}
1329
1330LinearTerm& LinearTerm::operator*=(const double d) {
1332 return *this;
1333}
1335LinearTerm& LinearTerm::operator/=(const double d) {
1336 coefficient /= d;
1337 return *this;
1339
1340LinearTerm operator*(const double coefficient, LinearTerm term) {
1341 term *= coefficient;
1342 return term;
1344
1345LinearTerm operator*(LinearTerm term, const double coefficient) {
1346 term *= coefficient;
1347 return term;
1349
1350LinearTerm operator*(const double coefficient, Variable variable) {
1351 return LinearTerm(std::move(variable), coefficient);
1352}
1354LinearTerm operator*(Variable variable, const double coefficient) {
1355 return LinearTerm(std::move(variable), coefficient);
1356}
1357
1359 term /= coefficient;
1360 return term;
1361}
1363LinearTerm operator/(Variable variable, const double coefficient) {
1364 return LinearTerm(std::move(variable), 1 / coefficient);
1365}
1368// LinearExpression
1370
1371void LinearExpression::SetOrCheckStorage(const ModelStorage* const storage) {
1372 CHECK(storage != nullptr) << internal::kKeyHasNullModelStorage;
1373 if (storage_ == nullptr) {
1374 storage_ = storage;
1375 return;
1376 }
1377 CHECK_EQ(storage, storage_) << internal::kObjectsFromOtherModelStorage;
1378}
1379
1380LinearExpression::LinearExpression(LinearExpression&& other) noexcept
1381 : storage_(std::exchange(other.storage_, nullptr)),
1382 terms_(std::move(other.terms_)),
1383 offset_(std::exchange(other.offset_, 0.0)) {
1384 other.terms_.clear();
1385#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
1386 ++num_calls_move_constructor_;
1387#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
1388}
1389
1391 LinearExpression&& other) noexcept {
1392 storage_ = std::exchange(other.storage_, nullptr);
1393 terms_ = std::move(other.terms_);
1394 other.terms_.clear();
1395 offset_ = std::exchange(other.offset_, 0.0);
1396 return *this;
1397}
1398
1399LinearExpression::LinearExpression(std::initializer_list<LinearTerm> terms,
1400 const double offset)
1401 : offset_(offset) {
1402#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
1403 ++num_calls_initializer_list_constructor_;
1404#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
1405 for (const auto& term : terms) {
1406 SetOrCheckStorage(term.variable.storage());
1407 // The same variable may appear multiple times in the input list; we must
1408 // accumulate the coefficients.
1409 terms_[term.variable] += term.coefficient;
1410 }
1411}
1412
1414 : LinearExpression({}, offset) {}
1415
1416LinearExpression::LinearExpression(Variable variable)
1417 : LinearExpression({LinearTerm(variable, 1.0)}, 0.0) {}
1418
1419LinearExpression::LinearExpression(const LinearTerm& term)
1420 : LinearExpression({term}, 0.0) {}
1421
1422LinearExpression operator-(LinearExpression expr) {
1423 expr.offset_ = -expr.offset_;
1424 for (auto& term : expr.terms_) {
1425 term.second = -term.second;
1427 return expr;
1428}
1430LinearExpression operator+(const Variable lhs, const double rhs) {
1431 return LinearTerm(lhs, 1.0) + rhs;
1433
1434LinearExpression operator+(const double lhs, const Variable rhs) {
1435 return lhs + LinearTerm(rhs, 1.0);
1436}
1437
1438LinearExpression operator+(const Variable lhs, const Variable rhs) {
1439 return LinearTerm(lhs, 1.0) + LinearTerm(rhs, 1.0);
1441
1442LinearExpression operator+(const LinearTerm& lhs, const double rhs) {
1443 return LinearExpression({lhs}, rhs);
1445
1446LinearExpression operator+(const double lhs, const LinearTerm& rhs) {
1447 return LinearExpression({rhs}, lhs);
1449
1450LinearExpression operator+(const LinearTerm& lhs, const Variable rhs) {
1451 return lhs + LinearTerm(rhs, 1.0);
1453
1454LinearExpression operator+(const Variable lhs, const LinearTerm& rhs) {
1455 return LinearTerm(lhs, 1.0) + rhs;
1457
1458LinearExpression operator+(const LinearTerm& lhs, const LinearTerm& rhs) {
1459 return LinearExpression({lhs, rhs}, 0);
1461
1462LinearExpression operator+(LinearExpression lhs, const double rhs) {
1463 lhs += rhs;
1464 return lhs;
1465}
1466
1467LinearExpression operator+(const double lhs, LinearExpression rhs) {
1468 rhs += lhs;
1469 return rhs;
1470}
1471
1473 return std::move(lhs) + LinearTerm(rhs, 1.0);
1474}
1475
1476LinearExpression operator+(const Variable lhs, LinearExpression rhs) {
1477 return LinearTerm(lhs, 1.0) + std::move(rhs);
1478}
1479
1480LinearExpression operator+(LinearExpression lhs, const LinearTerm& rhs) {
1481 lhs += rhs;
1482 return lhs;
1483}
1484
1485LinearExpression operator+(LinearTerm lhs, LinearExpression rhs) {
1486 rhs += lhs;
1487 return rhs;
1488}
1489
1491 lhs += rhs;
1492 return lhs;
1493}
1494
1495LinearExpression operator-(const Variable lhs, const double rhs) {
1496 return LinearTerm(lhs, 1.0) - rhs;
1497}
1498
1499LinearExpression operator-(const double lhs, const Variable rhs) {
1500 return lhs - LinearTerm(rhs, 1.0);
1501}
1502
1503LinearExpression operator-(const Variable lhs, const Variable rhs) {
1504 return LinearTerm(lhs, 1.0) - LinearTerm(rhs, 1.0);
1506
1507LinearExpression operator-(const LinearTerm& lhs, const double rhs) {
1508 return LinearExpression({lhs}, -rhs);
1510
1511LinearExpression operator-(const double lhs, const LinearTerm& rhs) {
1512 return LinearExpression({-rhs}, lhs);
1514
1515LinearExpression operator-(const LinearTerm& lhs, const Variable rhs) {
1516 return lhs - LinearTerm(rhs, 1.0);
1518
1519LinearExpression operator-(const Variable lhs, const LinearTerm& rhs) {
1520 return LinearTerm(lhs, 1.0) - rhs;
1522
1523LinearExpression operator-(const LinearTerm& lhs, const LinearTerm& rhs) {
1524 return LinearExpression({lhs, -rhs}, 0);
1526
1527LinearExpression operator-(LinearExpression lhs, const double rhs) {
1528 lhs -= rhs;
1529 return lhs;
1530}
1531
1532LinearExpression operator-(const double lhs, LinearExpression rhs) {
1533 auto ret = -std::move(rhs);
1534 ret += lhs;
1535 return ret;
1536}
1539 return std::move(lhs) - LinearTerm(rhs, 1.0);
1540}
1541
1543 return LinearTerm(lhs, 1.0) - std::move(rhs);
1544}
1545
1546LinearExpression operator-(LinearExpression lhs, const LinearTerm& rhs) {
1547 lhs -= rhs;
1548 return lhs;
1549}
1550
1551LinearExpression operator-(LinearTerm lhs, LinearExpression rhs) {
1552 auto ret = -std::move(rhs);
1553 ret += lhs;
1554 return ret;
1555}
1558 lhs -= rhs;
1559 return lhs;
1560}
1562LinearExpression operator*(LinearExpression lhs, const double rhs) {
1563 lhs *= rhs;
1564 return lhs;
1565}
1566
1568 rhs *= lhs;
1569 return rhs;
1570}
1571
1573 lhs /= rhs;
1574 return lhs;
1575}
1576
1578 // Here we know that each key in other.terms_ has already been checked and
1579 // thus we don't need to compare in the loop. Of course this only applies if
1580 // the other has terms.
1581 if (!other.terms_.empty()) {
1582 SetOrCheckStorage(other.storage());
1583 for (const auto& [v, coeff] : other.terms_) {
1584 terms_[v] += coeff;
1585 }
1586 }
1587 offset_ += other.offset_;
1588 return *this;
1589}
1590
1592 SetOrCheckStorage(term.variable.storage());
1593 terms_[term.variable] += term.coefficient;
1594 return *this;
1595}
1596
1597LinearExpression& LinearExpression::operator+=(const Variable variable) {
1598 SetOrCheckStorage(variable.storage());
1599 return *this += LinearTerm(variable, 1.0);
1600}
1603 offset_ += value;
1604 return *this;
1605}
1606
1608 // See operator+=.
1609 if (!other.terms_.empty()) {
1610 SetOrCheckStorage(other.storage());
1611 for (const auto& [v, coeff] : other.terms_) {
1612 terms_[v] -= coeff;
1613 }
1614 }
1615 offset_ -= other.offset_;
1616 return *this;
1618
1620 SetOrCheckStorage(term.variable.storage());
1621 terms_[term.variable] -= term.coefficient;
1622 return *this;
1623}
1624
1625LinearExpression& LinearExpression::operator-=(const Variable variable) {
1626 SetOrCheckStorage(variable.storage());
1627 return *this -= LinearTerm(variable, 1.0);
1628}
1631 offset_ -= value;
1632 return *this;
1633}
1634
1636 offset_ *= value;
1637 for (auto& term : terms_) {
1638 term.second *= value;
1639 }
1640 return *this;
1641}
1642
1644 offset_ /= value;
1645 for (auto& term : terms_) {
1646 term.second /= value;
1647 }
1648 return *this;
1649}
1650
1651template <typename Iterable>
1652void LinearExpression::AddSum(const Iterable& items) {
1653 for (const auto& item : items) {
1654 *this += item;
1655 }
1656}
1657
1658template <typename Iterable>
1659LinearExpression LinearExpression::Sum(const Iterable& items) {
1660 LinearExpression result;
1661 result.AddSum(items);
1662 return result;
1663}
1664
1665template <typename Iterable>
1666LinearExpression Sum(const Iterable& items) {
1667 return LinearExpression::Sum(items);
1668}
1670namespace internal {
1671
1672template <typename LeftIterable, typename RightIterable, typename Expression>
1673void AddInnerProduct(const LeftIterable& left, const RightIterable& right,
1674 Expression& expr) {
1675 using std::begin;
1676 using std::end;
1677 auto l = begin(left);
1678 auto r = begin(right);
1679 const auto l_end = end(left);
1680 const auto r_end = end(right);
1681 for (; l != l_end && r != r_end; ++l, ++r) {
1682 expr += (*l) * (*r);
1684 CHECK(l == l_end)
1685 << "left had more elements than right, sizes should be equal";
1686 CHECK(r == r_end)
1687 << "right had more elements than left, sizes should be equal";
1688}
1689
1690} // namespace internal
1691
1692template <typename LeftIterable, typename RightIterable>
1693void LinearExpression::AddInnerProduct(const LeftIterable& left,
1694 const RightIterable& right) {
1695 internal::AddInnerProduct(left, right, *this);
1696}
1697
1698template <typename LeftIterable, typename RightIterable>
1699LinearExpression LinearExpression::InnerProduct(const LeftIterable& left,
1700 const RightIterable& right) {
1701 LinearExpression result;
1702 result.AddInnerProduct(left, right);
1703 return result;
1704}
1705
1706template <typename LeftIterable, typename RightIterable>
1707LinearExpression InnerProduct(const LeftIterable& left,
1708 const RightIterable& right) {
1710}
1711
1712const VariableMap<double>& LinearExpression::terms() const { return terms_; }
1713
1714double LinearExpression::offset() const { return offset_; }
1715
1716const ModelStorage* LinearExpression::storage() const { return storage_; }
1719// VariablesEquality
1721
1722namespace internal {
1723
1725 : lhs(std::move(lhs)), rhs(std::move(rhs)) {}
1727inline VariablesEquality::operator bool() const {
1728 return lhs.typed_id() == rhs.typed_id() && lhs.storage() == rhs.storage();
1729}
1730
1731} // namespace internal
1732
1733internal::VariablesEquality operator==(const Variable& lhs,
1734 const Variable& rhs) {
1735 return internal::VariablesEquality(lhs, rhs);
1737
1738bool operator!=(const Variable& lhs, const Variable& rhs) {
1739 return !(lhs == rhs);
1740}
1741
1743// LowerBoundedLinearExpression
1744// UpperBoundedLinearExpression
1745// BoundedLinearExpression
1747
1748LowerBoundedLinearExpression::LowerBoundedLinearExpression(
1749 LinearExpression expression, const double lower_bound)
1750 : expression(std::move(expression)), lower_bound(lower_bound) {}
1751
1752UpperBoundedLinearExpression::UpperBoundedLinearExpression(
1753 LinearExpression expression, const double upper_bound)
1754 : expression(std::move(expression)), upper_bound(upper_bound) {}
1755
1756BoundedLinearExpression::BoundedLinearExpression(LinearExpression expression,
1757 const double lower_bound,
1758 const double upper_bound)
1759 : expression(std::move(expression)),
1763BoundedLinearExpression::BoundedLinearExpression(
1765 : expression({{eq.lhs, 1.0}, {eq.rhs, -1.0}}, 0.0),
1767 upper_bound(0.0) {}
1768
1771 : expression(std::move(lb_expression.expression)),
1772 lower_bound(lb_expression.lower_bound),
1773 upper_bound(std::numeric_limits<double>::infinity()) {}
1774
1776 UpperBoundedLinearExpression ub_expression)
1777 : expression(std::move(ub_expression.expression)),
1778 lower_bound(-std::numeric_limits<double>::infinity()),
1779 upper_bound(ub_expression.upper_bound) {}
1780
1782 return lower_bound - expression.offset();
1784
1786 return upper_bound - expression.offset();
1787}
1788
1790 const double constant) {
1791 return LowerBoundedLinearExpression(std::move(expression), constant);
1792}
1793
1794LowerBoundedLinearExpression operator<=(const double constant,
1795 LinearExpression expression) {
1796 return LowerBoundedLinearExpression(std::move(expression), constant);
1797}
1798
1800 const double constant) {
1801 return LowerBoundedLinearExpression(LinearExpression({term}, 0.0), constant);
1802}
1804LowerBoundedLinearExpression operator<=(const double constant,
1805 const LinearTerm& term) {
1806 return LowerBoundedLinearExpression(LinearExpression({term}, 0.0), constant);
1807}
1810 const double constant) {
1811 return LinearTerm(variable, 1.0) >= constant;
1812}
1814LowerBoundedLinearExpression operator<=(const double constant,
1815 const Variable variable) {
1816 return constant <= LinearTerm(variable, 1.0);
1817}
1820 const double constant) {
1821 return UpperBoundedLinearExpression(std::move(expression), constant);
1822}
1824UpperBoundedLinearExpression operator>=(const double constant,
1825 LinearExpression expression) {
1826 return UpperBoundedLinearExpression(std::move(expression), constant);
1827}
1830 const double constant) {
1831 return UpperBoundedLinearExpression(LinearExpression({term}, 0.0), constant);
1832}
1834UpperBoundedLinearExpression operator>=(const double constant,
1835 const LinearTerm& term) {
1836 return UpperBoundedLinearExpression(LinearExpression({term}, 0.0), constant);
1837}
1840 const double constant) {
1841 return LinearTerm(variable, 1.0) <= constant;
1842}
1844UpperBoundedLinearExpression operator>=(const double constant,
1845 const Variable variable) {
1846 return constant >= LinearTerm(variable, 1.0);
1847}
1850 const double rhs) {
1851 return BoundedLinearExpression(std::move(lhs.expression),
1852 /*lower_bound=*/lhs.lower_bound,
1853 /*upper_bound=*/rhs);
1854}
1855
1856BoundedLinearExpression operator>=(const double lhs,
1857 LowerBoundedLinearExpression rhs) {
1858 return BoundedLinearExpression(std::move(rhs.expression),
1859 /*lower_bound=*/rhs.lower_bound,
1860 /*upper_bound=*/lhs);
1861}
1862
1864 const double rhs) {
1865 return BoundedLinearExpression(std::move(lhs.expression),
1866 /*lower_bound=*/rhs,
1867 /*upper_bound=*/lhs.upper_bound);
1868}
1869
1872 return BoundedLinearExpression(std::move(rhs.expression),
1873 /*lower_bound=*/lhs,
1874 /*upper_bound=*/rhs.upper_bound);
1875}
1876
1878 const LinearExpression& rhs) {
1879 lhs -= rhs;
1881 std::move(lhs), /*lower_bound=*/-std::numeric_limits<double>::infinity(),
1882 /*upper_bound=*/0.0);
1883}
1886 const LinearExpression& rhs) {
1887 lhs -= rhs;
1889 std::move(lhs), /*lower_bound=*/0.0,
1890 /*upper_bound=*/std::numeric_limits<double>::infinity());
1892
1893BoundedLinearExpression operator<=(LinearExpression lhs,
1894 const LinearTerm& rhs) {
1895 lhs -= rhs;
1896 return BoundedLinearExpression(
1897 std::move(lhs), /*lower_bound=*/-std::numeric_limits<double>::infinity(),
1898 /*upper_bound=*/0.0);
1900
1901BoundedLinearExpression operator>=(LinearExpression lhs,
1902 const LinearTerm& rhs) {
1903 lhs -= rhs;
1904 return BoundedLinearExpression(
1905 std::move(lhs), /*lower_bound=*/0.0,
1906 /*upper_bound=*/std::numeric_limits<double>::infinity());
1908
1909BoundedLinearExpression operator<=(const LinearTerm& lhs,
1910 LinearExpression rhs) {
1911 rhs -= lhs;
1912 return BoundedLinearExpression(
1913 std::move(rhs), /*lower_bound=*/0.0,
1914 /*upper_bound=*/std::numeric_limits<double>::infinity());
1916
1917BoundedLinearExpression operator>=(const LinearTerm& lhs,
1918 LinearExpression rhs) {
1919 rhs -= lhs;
1920 return BoundedLinearExpression(
1921 std::move(rhs), /*lower_bound=*/-std::numeric_limits<double>::infinity(),
1922 /*upper_bound=*/0.0);
1924
1925BoundedLinearExpression operator<=(LinearExpression lhs, const Variable rhs) {
1926 return std::move(lhs) <= LinearTerm(rhs, 1.0);
1927}
1928
1929BoundedLinearExpression operator>=(LinearExpression lhs, const Variable rhs) {
1930 return std::move(lhs) >= LinearTerm(rhs, 1.0);
1932
1933BoundedLinearExpression operator<=(const Variable lhs, LinearExpression rhs) {
1934 return LinearTerm(lhs, 1.0) <= std::move(rhs);
1935}
1936
1937BoundedLinearExpression operator>=(const Variable lhs, LinearExpression rhs) {
1938 return LinearTerm(lhs, 1.0) >= std::move(rhs);
1940
1941BoundedLinearExpression operator<=(const LinearTerm& lhs,
1942 const LinearTerm& rhs) {
1944 LinearExpression({lhs, -rhs}, 0.0),
1945 /*lower_bound=*/-std::numeric_limits<double>::infinity(),
1946 /*upper_bound=*/0.0);
1948
1949BoundedLinearExpression operator>=(const LinearTerm& lhs,
1950 const LinearTerm& rhs) {
1952 LinearExpression({lhs, -rhs}, 0.0), /*lower_bound=*/0.0,
1953 /*upper_bound=*/std::numeric_limits<double>::infinity());
1954}
1957 return lhs <= LinearTerm(rhs, 1.0);
1958}
1959
1960BoundedLinearExpression operator>=(const LinearTerm& lhs, const Variable rhs) {
1961 return lhs >= LinearTerm(rhs, 1.0);
1962}
1965 return LinearTerm(lhs, 1.0) <= rhs;
1966}
1967
1968BoundedLinearExpression operator>=(const Variable lhs, const LinearTerm& rhs) {
1969 return LinearTerm(lhs, 1.0) >= rhs;
1971
1972BoundedLinearExpression operator<=(const Variable lhs, const Variable rhs) {
1973 return LinearTerm(lhs, 1.0) <= LinearTerm(rhs, 1.0);
1975
1976BoundedLinearExpression operator>=(const Variable lhs, const Variable rhs) {
1977 return LinearTerm(lhs, 1.0) >= LinearTerm(rhs, 1.0);
1979
1980BoundedLinearExpression operator==(LinearExpression lhs,
1981 const LinearExpression& rhs) {
1982 lhs -= rhs;
1983 return BoundedLinearExpression(std::move(lhs), /*lower_bound=*/0.0,
1984 /*upper_bound=*/0.0);
1985}
1989 lhs -= rhs;
1990 return BoundedLinearExpression(std::move(lhs), /*lower_bound=*/0.0,
1991 /*upper_bound=*/0.0);
1992}
1993
1995 LinearExpression rhs) {
1996 rhs -= lhs;
1997 return BoundedLinearExpression(std::move(rhs), /*lower_bound=*/0.0,
1998 /*upper_bound=*/0.0);
1999}
2000
2002 return std::move(lhs) == LinearTerm(rhs, 1.0);
2003}
2004
2005BoundedLinearExpression operator==(const Variable lhs, LinearExpression rhs) {
2006 return LinearTerm(lhs, 1.0) == std::move(rhs);
2007}
2010 lhs -= rhs;
2011 return BoundedLinearExpression(std::move(lhs), /*lower_bound=*/0.0,
2012 /*upper_bound=*/0.0);
2013}
2014
2016 rhs -= lhs;
2017 return BoundedLinearExpression(std::move(rhs), /*lower_bound=*/0.0,
2018 /*upper_bound=*/0.0);
2020
2021BoundedLinearExpression operator==(const LinearTerm& lhs,
2022 const LinearTerm& rhs) {
2024 /*lower_bound=*/0.0,
2025 /*upper_bound=*/0.0);
2026}
2027
2028BoundedLinearExpression operator==(const LinearTerm& lhs, const Variable rhs) {
2029 return lhs == LinearTerm(rhs, 1.0);
2030}
2031
2032BoundedLinearExpression operator==(const Variable lhs, const LinearTerm& rhs) {
2033 return LinearTerm(lhs, 1.0) == rhs;
2034}
2036BoundedLinearExpression operator==(const LinearTerm& lhs, const double rhs) {
2037 return BoundedLinearExpression(LinearExpression({lhs}, -rhs),
2038 /*lower_bound=*/0.0, /*upper_bound=*/0.0);
2039}
2040
2041BoundedLinearExpression operator==(const double lhs, const LinearTerm& rhs) {
2043 /*lower_bound=*/0.0, /*upper_bound=*/0.0);
2044}
2045
2046BoundedLinearExpression operator==(const Variable lhs, const double rhs) {
2047 return LinearTerm(lhs, 1.0) == rhs;
2048}
2049
2050BoundedLinearExpression operator==(const double lhs, const Variable rhs) {
2051 return lhs == LinearTerm(rhs, 1.0);
2052}
2053
2055// QuadraticTermKey
2057
2058QuadraticTermKey::QuadraticTermKey(const ModelStorage* storage,
2059 const QuadraticProductId id)
2060 : storage_(storage), variable_ids_(id) {
2061 if (variable_ids_.first > variable_ids_.second) {
2062 // See https://en.cppreference.com/w/cpp/named_req/Swappable for details.
2063 using std::swap;
2064 swap(variable_ids_.first, variable_ids_.second);
2065 }
2066}
2067
2068QuadraticTermKey::QuadraticTermKey(const Variable first_variable,
2069 const Variable second_variable)
2070 : QuadraticTermKey(first_variable.storage(), {first_variable.typed_id(),
2071 second_variable.typed_id()}) {
2072 CHECK_EQ(first_variable.storage(), second_variable.storage())
2073 << internal::kObjectsFromOtherModelStorage;
2075
2076QuadraticProductId QuadraticTermKey::typed_id() const { return variable_ids_; }
2077
2078const ModelStorage* QuadraticTermKey::storage() const { return storage_; }
2079
2080template <typename H>
2081H AbslHashValue(H h, const QuadraticTermKey& key) {
2082 return H::combine(std::move(h), key.typed_id().first.value(),
2083 key.typed_id().second.value(), key.storage());
2085
2086std::ostream& operator<<(std::ostream& ostr, const QuadraticTermKey& key) {
2087 ostr << "(" << Variable(key.storage(), key.typed_id().first) << ", "
2088 << Variable(key.storage(), key.typed_id().second) << ")";
2089 return ostr;
2090}
2091
2093 return lhs.storage() == rhs.storage() && lhs.typed_id() == rhs.typed_id();
2095
2096bool operator!=(const QuadraticTermKey lhs, const QuadraticTermKey rhs) {
2097 return !(lhs == rhs);
2098}
2099
2101// QuadraticTerm (no arithmetic)
2103
2104QuadraticTerm::QuadraticTerm(Variable first_variable, Variable second_variable,
2105 const double coefficient)
2106 : first_variable_(std::move(first_variable)),
2107 second_variable_(std::move(second_variable)),
2108 coefficient_(coefficient) {
2109 CHECK_EQ(first_variable_.storage(), second_variable_.storage())
2110 << internal::kObjectsFromOtherModelStorage;
2111}
2113double QuadraticTerm::coefficient() const { return coefficient_; }
2114Variable QuadraticTerm::first_variable() const { return first_variable_; }
2115Variable QuadraticTerm::second_variable() const { return second_variable_; }
2116
2117QuadraticTermKey QuadraticTerm::GetKey() const {
2118 return QuadraticTermKey(
2119 first_variable_.storage(),
2120 std::make_pair(first_variable_.typed_id(), second_variable_.typed_id()));
2121}
2124// QuadraticExpression (no arithmetic)
2126
2127void QuadraticExpression::SetOrCheckStorage(const ModelStorage* const storage) {
2128 CHECK(storage != nullptr) << internal::kKeyHasNullModelStorage;
2129 if (storage_ == nullptr) {
2130 storage_ = storage;
2131 return;
2133 CHECK_EQ(storage, storage_) << internal::kObjectsFromOtherModelStorage;
2134}
2136QuadraticExpression::QuadraticExpression(QuadraticExpression&& other) noexcept
2137 : storage_(std::exchange(other.storage_, nullptr)),
2138 quadratic_terms_(std::move(other.quadratic_terms_)),
2139 linear_terms_(std::move(other.linear_terms_)),
2140 offset_(std::exchange(other.offset_, 0.0)) {
2141 other.quadratic_terms_.clear();
2142 other.linear_terms_.clear();
2143#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
2144 ++num_calls_move_constructor_;
2145#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
2146}
2147
2148QuadraticExpression& QuadraticExpression::operator=(
2149 QuadraticExpression&& other) noexcept {
2150 storage_ = std::exchange(other.storage_, nullptr);
2151 quadratic_terms_ = std::move(other.quadratic_terms_);
2152 other.quadratic_terms_.clear();
2153 linear_terms_ = std::move(other.linear_terms_);
2154 other.linear_terms_.clear();
2155 offset_ = std::exchange(other.offset_, 0.0);
2156 return *this;
2157}
2158
2159QuadraticExpression::QuadraticExpression(
2160 const std::initializer_list<QuadraticTerm> quadratic_terms,
2161 const std::initializer_list<LinearTerm> linear_terms, const double offset)
2162 : offset_(offset) {
2163#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
2164 ++num_calls_initializer_list_constructor_;
2165#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
2166 for (const LinearTerm& term : linear_terms) {
2167 SetOrCheckStorage(term.variable.storage());
2168 linear_terms_[term.variable] += term.coefficient;
2169 }
2170 for (const QuadraticTerm& term : quadratic_terms) {
2171 const QuadraticTermKey key = term.GetKey();
2172 SetOrCheckStorage(key.storage());
2173 quadratic_terms_[key] += term.coefficient();
2174 }
2175}
2176
2178 : QuadraticExpression({}, {}, offset) {}
2181 : QuadraticExpression({}, {LinearTerm(variable, 1.0)}, 0.0) {}
2182
2183QuadraticExpression::QuadraticExpression(const LinearTerm& term)
2184 : QuadraticExpression({}, {term}, 0.0) {}
2185
2186QuadraticExpression::QuadraticExpression(LinearExpression expr)
2187 : storage_(std::exchange(expr.storage_, nullptr)),
2188 linear_terms_(std::move(expr.terms_)),
2189 offset_(std::exchange(expr.offset_, 0.0)) {
2190#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
2191 ++num_calls_linear_expression_constructor_;
2192#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
2193}
2194
2195QuadraticExpression::QuadraticExpression(const QuadraticTerm& term)
2196 : QuadraticExpression({term}, {}, 0.0) {}
2198const ModelStorage* QuadraticExpression::storage() const { return storage_; }
2199
2200double QuadraticExpression::offset() const { return offset_; }
2201
2203 return linear_terms_;
2204}
2205
2207 return quadratic_terms_;
2208}
2209
2211// Arithmetic operators (non-member).
2212//
2213// These are NOT required to explicitly CHECK that the underlying model storages
2214// agree between linear_terms_ and quadratic_terms_ unless they are a friend of
2215// QuadraticExpression. As much as possible, defer to the assignment operators
2216// and the initializer list constructor for QuadraticExpression.
2219// ----------------------------- Addition (+) ----------------------------------
2221QuadraticExpression operator+(const double lhs, const QuadraticTerm& rhs) {
2222 return QuadraticExpression({rhs}, {}, lhs);
2223}
2224
2225QuadraticExpression operator+(const double lhs, QuadraticExpression rhs) {
2226 rhs += lhs;
2227 return rhs;
2228}
2229
2230QuadraticExpression operator+(const Variable lhs, const QuadraticTerm& rhs) {
2231 return QuadraticExpression({rhs}, {LinearTerm(lhs, 1.0)}, 0.0);
2232}
2233
2234QuadraticExpression operator+(const Variable lhs, QuadraticExpression rhs) {
2235 rhs += LinearTerm(lhs, 1.0);
2236 return rhs;
2237}
2238
2239QuadraticExpression operator+(const LinearTerm& lhs, const QuadraticTerm& rhs) {
2240 return QuadraticExpression({rhs}, {lhs}, 0.0);
2241}
2242
2244 rhs += lhs;
2245 return rhs;
2246}
2249 QuadraticExpression expr(std::move(lhs));
2250 expr += rhs;
2251 return expr;
2253
2254QuadraticExpression operator+(const LinearExpression& lhs,
2255 QuadraticExpression rhs) {
2256 rhs += lhs;
2257 return rhs;
2258}
2259
2260QuadraticExpression operator+(const QuadraticTerm& lhs, const double rhs) {
2261 return QuadraticExpression({lhs}, {}, rhs);
2262}
2263
2264QuadraticExpression operator+(const QuadraticTerm& lhs, const Variable rhs) {
2265 return QuadraticExpression({lhs}, {LinearTerm(rhs, 1.0)}, 0.0);
2266}
2267
2268QuadraticExpression operator+(const QuadraticTerm& lhs, const LinearTerm& rhs) {
2269 return QuadraticExpression({lhs}, {rhs}, 0.0);
2271
2272QuadraticExpression operator+(const QuadraticTerm& lhs, LinearExpression rhs) {
2273 QuadraticExpression expr(std::move(rhs));
2274 expr += lhs;
2275 return expr;
2277
2278QuadraticExpression operator+(const QuadraticTerm& lhs,
2279 const QuadraticTerm& rhs) {
2280 return QuadraticExpression({lhs, rhs}, {}, 0.0);
2281}
2285 rhs += lhs;
2286 return rhs;
2287}
2288
2289QuadraticExpression operator+(QuadraticExpression lhs, const double rhs) {
2290 lhs += rhs;
2291 return lhs;
2292}
2293
2295 lhs += LinearTerm(rhs, 1.0);
2296 return lhs;
2297}
2298
2299QuadraticExpression operator+(QuadraticExpression lhs, const LinearTerm& rhs) {
2300 lhs += rhs;
2301 return lhs;
2302}
2303
2304QuadraticExpression operator+(QuadraticExpression lhs,
2305 const LinearExpression& rhs) {
2306 lhs += rhs;
2307 return lhs;
2308}
2309
2310QuadraticExpression operator+(QuadraticExpression lhs,
2311 const QuadraticTerm& rhs) {
2312 lhs += rhs;
2313 return lhs;
2314}
2315
2317 const QuadraticExpression& rhs) {
2318 lhs += rhs;
2319 return lhs;
2320}
2322// --------------------------- Subtraction (-) ---------------------------------
2323
2324// NOTE: A friend of QuadraticTerm, but does not touch variables
2326 term.coefficient_ *= -1.0;
2327 return term;
2328}
2329
2330// NOTE: A friend of QuadraticExpression, but does not touch variables
2331QuadraticExpression operator-(QuadraticExpression expr) {
2332 expr.offset_ = -expr.offset_;
2333 for (auto& term : expr.linear_terms_) {
2334 term.second = -term.second;
2335 }
2336 for (auto& term : expr.quadratic_terms_) {
2337 term.second = -term.second;
2339 return expr;
2340}
2341
2342QuadraticExpression operator-(const double lhs, const QuadraticTerm& rhs) {
2343 return QuadraticExpression({-rhs}, {}, lhs);
2344}
2345
2346QuadraticExpression operator-(const double lhs, QuadraticExpression rhs) {
2347 auto expr = -std::move(rhs);
2348 expr += lhs;
2349 return expr;
2350}
2351
2352QuadraticExpression operator-(const Variable lhs, const QuadraticTerm& rhs) {
2353 return QuadraticExpression({-rhs}, {LinearTerm(lhs, 1.0)}, 0.0);
2354}
2355
2356QuadraticExpression operator-(const Variable lhs, QuadraticExpression rhs) {
2357 return LinearTerm(lhs, 1.0) - std::move(rhs);
2358}
2359
2360QuadraticExpression operator-(const LinearTerm& lhs, const QuadraticTerm& rhs) {
2361 return QuadraticExpression({-rhs}, {lhs}, 0.0);
2362}
2363
2365 auto expr = -std::move(rhs);
2366 expr += lhs;
2367 return expr;
2369
2370QuadraticExpression operator-(LinearExpression lhs, const QuadraticTerm& rhs) {
2371 QuadraticExpression expr(std::move(lhs));
2372 expr -= rhs;
2373 return expr;
2375
2376QuadraticExpression operator-(const LinearExpression& lhs,
2377 QuadraticExpression rhs) {
2378 auto expr = -std::move(rhs);
2379 expr += lhs;
2380 return expr;
2381}
2383QuadraticExpression operator-(const QuadraticTerm& lhs, const double rhs) {
2384 return QuadraticExpression({lhs}, {}, -rhs);
2385}
2387QuadraticExpression operator-(const QuadraticTerm& lhs, const Variable rhs) {
2388 return QuadraticExpression({lhs}, {LinearTerm(rhs, -1.0)}, 0.0);
2389}
2390
2391QuadraticExpression operator-(const QuadraticTerm& lhs, const LinearTerm& rhs) {
2392 return QuadraticExpression({lhs}, {-rhs}, 0.0);
2393}
2394
2395QuadraticExpression operator-(const QuadraticTerm& lhs, LinearExpression rhs) {
2396 QuadraticExpression expr(-std::move(rhs));
2397 expr += lhs;
2398 return expr;
2399}
2400
2401QuadraticExpression operator-(const QuadraticTerm& lhs,
2402 const QuadraticTerm& rhs) {
2403 return QuadraticExpression({lhs, -rhs}, {}, 0.0);
2404}
2408 rhs *= -1.0;
2409 rhs += lhs;
2410 return rhs;
2411}
2412
2414 lhs -= rhs;
2415 return lhs;
2416}
2418// NOTE: Out-of-order for compilation purposes
2420 lhs -= rhs;
2421 return lhs;
2422}
2425 lhs -= LinearTerm(rhs, 1.0);
2426 return lhs;
2427}
2429// NOTE: operator-(QuadraticExpression, const LinearTerm) appears above
2430
2432 const LinearExpression& rhs) {
2433 lhs -= rhs;
2434 return lhs;
2436
2437QuadraticExpression operator-(QuadraticExpression lhs,
2438 const QuadraticTerm& rhs) {
2439 lhs -= rhs;
2440 return lhs;
2442
2443QuadraticExpression operator-(QuadraticExpression lhs,
2444 const QuadraticExpression& rhs) {
2445 lhs -= rhs;
2446 return lhs;
2447}
2448
2449// ---------------------------- Multiplication (*) -----------------------------
2450
2451// NOTE: A friend of QuadraticTerm, but does not touch variables
2452QuadraticTerm operator*(const double lhs, QuadraticTerm rhs) {
2453 rhs.coefficient_ *= lhs;
2454 return rhs;
2455}
2456
2457QuadraticExpression operator*(const double lhs, QuadraticExpression rhs) {
2458 rhs *= lhs;
2459 return rhs;
2460}
2461
2462QuadraticTerm operator*(Variable lhs, Variable rhs) {
2463 return QuadraticTerm(std::move(lhs), std::move(rhs), 1.0);
2464}
2467 return QuadraticTerm(std::move(lhs), std::move(rhs.variable),
2468 rhs.coefficient);
2469}
2470
2471QuadraticExpression operator*(Variable lhs, const LinearExpression& rhs) {
2472 QuadraticExpression expr;
2473 for (const auto& [var, coeff] : rhs.terms()) {
2474 expr += QuadraticTerm(lhs, var, coeff);
2475 }
2476 if (rhs.offset() != 0) {
2477 expr += LinearTerm(std::move(lhs), rhs.offset());
2478 }
2479 return expr;
2480}
2481
2482QuadraticTerm operator*(LinearTerm lhs, Variable rhs) {
2483 return QuadraticTerm(std::move(lhs.variable), std::move(rhs),
2484 lhs.coefficient);
2485}
2486
2487QuadraticTerm operator*(LinearTerm lhs, LinearTerm rhs) {
2488 return QuadraticTerm(std::move(lhs.variable), std::move(rhs.variable),
2489 lhs.coefficient * rhs.coefficient);
2490}
2491
2492QuadraticExpression operator*(LinearTerm lhs, const LinearExpression& rhs) {
2494 for (const auto& [var, coeff] : rhs.terms()) {
2495 expr += QuadraticTerm(lhs.variable, var, lhs.coefficient * coeff);
2496 }
2497 if (rhs.offset() != 0) {
2498 expr += LinearTerm(std::move(lhs.variable), lhs.coefficient * rhs.offset());
2499 }
2500 return expr;
2501}
2502
2503QuadraticExpression operator*(const LinearExpression& lhs, Variable rhs) {
2505 for (const auto& [var, coeff] : lhs.terms()) {
2506 expr += QuadraticTerm(var, rhs, coeff);
2507 }
2508 if (lhs.offset() != 0) {
2509 expr += LinearTerm(std::move(rhs), lhs.offset());
2510 }
2511 return expr;
2512}
2513
2516 for (const auto& [var, coeff] : lhs.terms()) {
2517 expr += QuadraticTerm(var, rhs.variable, coeff * rhs.coefficient);
2518 }
2519 if (lhs.offset() != 0) {
2520 expr += LinearTerm(std::move(rhs.variable), lhs.offset() * rhs.coefficient);
2521 }
2522 return expr;
2523}
2524
2526 const LinearExpression& rhs) {
2527 QuadraticExpression expr = lhs.offset() * rhs.offset();
2528 if (rhs.offset() != 0) {
2529 for (const auto& [var, coeff] : lhs.terms()) {
2530 expr += LinearTerm(var, coeff * rhs.offset());
2531 }
2532 }
2533 if (lhs.offset() != 0) {
2534 for (const auto& [var, coeff] : rhs.terms()) {
2535 expr += LinearTerm(var, lhs.offset() * coeff);
2537 }
2538 for (const auto& [lhs_var, lhs_coeff] : lhs.terms()) {
2539 for (const auto& [rhs_var, rhs_coeff] : rhs.terms()) {
2540 expr += QuadraticTerm(lhs_var, rhs_var, lhs_coeff * rhs_coeff);
2541 }
2542 }
2543 return expr;
2544}
2545
2546// NOTE: A friend of QuadraticTerm, but does not touch variables
2547QuadraticTerm operator*(QuadraticTerm lhs, const double rhs) {
2548 lhs.coefficient_ *= rhs;
2549 return lhs;
2550}
2551
2552QuadraticExpression operator*(QuadraticExpression lhs, const double rhs) {
2553 lhs *= rhs;
2554 return lhs;
2555}
2556
2557// ------------------------------- Division (/) --------------------------------
2558
2559// NOTE: A friend of QuadraticTerm, but does not touch variables
2560QuadraticTerm operator/(QuadraticTerm lhs, const double rhs) {
2561 lhs.coefficient_ /= rhs;
2562 return lhs;
2563}
2564
2565QuadraticExpression operator/(QuadraticExpression lhs, const double rhs) {
2566 lhs /= rhs;
2567 return lhs;
2568}
2571// In-place arithmetic operators.
2572//
2573// These must guarantee that the underlying model storages for linear_terms_ and
2574// quadratic_terms_ agree upon exit of the function, using CheckModelsAgree(),
2575// the list initializer constructor for QuadraticExpression, or similar logic.
2577
2579 offset_ += value;
2580 // NOTE: Not touching terms, no need to check models
2581 return *this;
2583
2585 SetOrCheckStorage(variable.storage());
2586 linear_terms_[variable] += 1;
2587 return *this;
2588}
2589
2590QuadraticExpression& QuadraticExpression::operator+=(const LinearTerm& term) {
2591 SetOrCheckStorage(term.variable.storage());
2592 linear_terms_[term.variable] += term.coefficient;
2593 return *this;
2594}
2595
2596QuadraticExpression& QuadraticExpression::operator+=(
2597 const LinearExpression& expr) {
2598 offset_ += expr.offset();
2599 // See comment in LinearExpression::operator+=.
2600 if (!expr.terms().empty()) {
2601 SetOrCheckStorage(expr.storage());
2602 for (const auto& [v, coeff] : expr.terms()) {
2603 linear_terms_[v] += coeff;
2604 }
2605 }
2606 return *this;
2607}
2610 const QuadraticTerm& term) {
2611 const QuadraticTermKey key = term.GetKey();
2612 SetOrCheckStorage(key.storage());
2613 quadratic_terms_[key] += term.coefficient();
2614 return *this;
2615}
2616
2618 const QuadraticExpression& expr) {
2619 offset_ += expr.offset();
2620 // See comment in LinearExpression::operator+=.
2621 if (!expr.linear_terms().empty() || !expr.quadratic_terms().empty()) {
2622 SetOrCheckStorage(expr.storage());
2623 for (const auto& [v, coeff] : expr.linear_terms()) {
2624 linear_terms_[v] += coeff;
2625 }
2626 for (const auto& [k, coeff] : expr.quadratic_terms()) {
2627 quadratic_terms_[k] += coeff;
2628 }
2629 }
2630 return *this;
2631}
2632
2634 offset_ -= value;
2635 // NOTE: Not touching terms, no need to check models
2636 return *this;
2637}
2638
2640 SetOrCheckStorage(variable.storage());
2641 linear_terms_[variable] -= 1;
2642 return *this;
2643}
2644
2646 SetOrCheckStorage(term.variable.storage());
2647 linear_terms_[term.variable] -= term.coefficient;
2648 return *this;
2649}
2650
2651QuadraticExpression& QuadraticExpression::operator-=(
2652 const LinearExpression& expr) {
2653 offset_ -= expr.offset();
2654 // See comment in LinearExpression::operator+=.
2655 if (!expr.terms().empty()) {
2656 SetOrCheckStorage(expr.storage());
2657 for (const auto& [v, coeff] : expr.terms()) {
2658 linear_terms_[v] -= coeff;
2659 }
2660 }
2661 return *this;
2662}
2665 const QuadraticTerm& term) {
2666 const QuadraticTermKey key = term.GetKey();
2667 SetOrCheckStorage(key.storage());
2668 quadratic_terms_[key] -= term.coefficient();
2669 return *this;
2670}
2671
2673 const QuadraticExpression& expr) {
2674 offset_ -= expr.offset();
2675 // See comment in LinearExpression::operator+=.
2676 if (!expr.linear_terms().empty() || !expr.quadratic_terms().empty()) {
2677 SetOrCheckStorage(expr.storage());
2678 for (const auto& [v, coeff] : expr.linear_terms()) {
2679 linear_terms_[v] -= coeff;
2680 }
2681 for (const auto& [k, coeff] : expr.quadratic_terms()) {
2682 quadratic_terms_[k] -= coeff;
2683 }
2684 }
2685 return *this;
2686}
2687
2689 coefficient_ *= value;
2690 // NOTE: Not touching variables in term, just modifying coefficient, so no
2691 // need to check that models agree.
2692 return *this;
2693}
2694
2696 offset_ *= value;
2697 for (auto& term : linear_terms_) {
2698 term.second *= value;
2699 }
2700 for (auto& term : quadratic_terms_) {
2701 term.second *= value;
2702 }
2703 // NOTE: Not adding/removing/altering variables in expression, just modifying
2704 // coefficients, so no need to check that models agree.
2705 return *this;
2706}
2707
2708QuadraticTerm& QuadraticTerm::operator/=(const double value) {
2709 coefficient_ /= value;
2710 // NOTE: Not touching variables in term, just modifying coefficient, so no
2711 // need to check that models agree.
2712 return *this;
2713}
2714
2716 offset_ /= value;
2717 for (auto& term : linear_terms_) {
2718 term.second /= value;
2720 for (auto& term : quadratic_terms_) {
2721 term.second /= value;
2722 }
2723 // NOTE: Not adding/removing/altering variables in expression, just modifying
2724 // coefficients, so no need to check that models agree.
2725 return *this;
2726}
2727
2728template <typename Iterable>
2729void QuadraticExpression::AddSum(const Iterable& items) {
2730 for (const auto& item : items) {
2731 *this += item;
2733}
2734
2735template <typename Iterable>
2736QuadraticExpression QuadraticExpression::Sum(const Iterable& items) {
2737 QuadraticExpression result;
2738 result.AddSum(items);
2739 return result;
2740}
2741
2742template <typename LeftIterable, typename RightIterable>
2743void QuadraticExpression::AddInnerProduct(const LeftIterable& left,
2744 const RightIterable& right) {
2745 internal::AddInnerProduct(left, right, *this);
2746}
2747
2748template <typename LeftIterable, typename RightIterable>
2749QuadraticExpression QuadraticExpression::InnerProduct(
2750 const LeftIterable& left, const RightIterable& right) {
2751 QuadraticExpression result;
2752 result.AddInnerProduct(left, right);
2753 return result;
2754}
2755
2757// LowerBoundedQuadraticExpression
2758// UpperBoundedQuadraticExpression
2759// BoundedQuadraticExpression
2761
2763 QuadraticExpression expression, const double lower_bound)
2764 : expression(std::move(expression)), lower_bound(lower_bound) {}
2766 LowerBoundedLinearExpression lb_expression)
2767 : expression(std::move(lb_expression.expression)),
2768 lower_bound(lb_expression.lower_bound) {}
2769
2771 QuadraticExpression expression, const double upper_bound)
2772 : expression(std::move(expression)), upper_bound(upper_bound) {}
2779 QuadraticExpression expression, const double lower_bound,
2780 const double upper_bound)
2781 : expression(std::move(expression)),
2785 internal::VariablesEquality var_equality)
2786 : lower_bound(0), upper_bound(0) {
2787 expression += var_equality.lhs;
2788 expression -= var_equality.rhs;
2789}
2792 : expression(std::move(lb_expression.expression)),
2793 lower_bound(lb_expression.lower_bound),
2794 upper_bound(std::numeric_limits<double>::infinity()) {}
2797 : expression(std::move(ub_expression.expression)),
2798 lower_bound(-std::numeric_limits<double>::infinity()),
2799 upper_bound(ub_expression.upper_bound) {}
2801 BoundedLinearExpression bounded_expression)
2802 : expression(std::move(bounded_expression.expression)),
2803 lower_bound(bounded_expression.lower_bound),
2804 upper_bound(bounded_expression.upper_bound) {}
2806 LowerBoundedQuadraticExpression lb_expression)
2807 : expression(std::move(lb_expression.expression)),
2808 lower_bound(lb_expression.lower_bound),
2809 upper_bound(std::numeric_limits<double>::infinity()) {}
2811 UpperBoundedQuadraticExpression ub_expression)
2812 : expression(std::move(ub_expression.expression)),
2813 lower_bound(-std::numeric_limits<double>::infinity()),
2814 upper_bound(ub_expression.upper_bound) {}
2815
2822}
2823
2825 const double rhs) {
2826 return LowerBoundedQuadraticExpression(std::move(lhs), rhs);
2827}
2829 const double rhs) {
2830 return LowerBoundedQuadraticExpression(lhs, rhs);
2833 QuadraticExpression rhs) {
2834 return LowerBoundedQuadraticExpression(std::move(rhs), lhs);
2835}
2837 const QuadraticTerm rhs) {
2838 return LowerBoundedQuadraticExpression(rhs, lhs);
2839}
2840
2843 return UpperBoundedQuadraticExpression(std::move(rhs), lhs);
2844}
2846 const QuadraticTerm rhs) {
2847 return UpperBoundedQuadraticExpression(rhs, lhs);
2848}
2850 const double rhs) {
2851 return UpperBoundedQuadraticExpression(std::move(lhs), rhs);
2852}
2853UpperBoundedQuadraticExpression operator<=(const QuadraticTerm lhs,
2854 const double rhs) {
2855 return UpperBoundedQuadraticExpression(lhs, rhs);
2856}
2857
2859 const double rhs) {
2860 return BoundedQuadraticExpression(std::move(lhs.expression), rhs,
2861 lhs.upper_bound);
2863BoundedQuadraticExpression operator>=(const double lhs,
2864 LowerBoundedQuadraticExpression rhs) {
2865 return BoundedQuadraticExpression(std::move(rhs.expression), rhs.lower_bound,
2866 lhs);
2868BoundedQuadraticExpression operator<=(LowerBoundedQuadraticExpression lhs,
2869 const double rhs) {
2870 return BoundedQuadraticExpression(std::move(lhs.expression), lhs.lower_bound,
2871 rhs);
2872}
2873BoundedQuadraticExpression operator<=(const double lhs,
2874 UpperBoundedQuadraticExpression rhs) {
2875 return BoundedQuadraticExpression(std::move(rhs.expression), lhs,
2876 rhs.upper_bound);
2877}
2878
2880 const QuadraticExpression& rhs) {
2881 lhs -= rhs;
2882 return BoundedQuadraticExpression(std::move(lhs), 0,
2883 std::numeric_limits<double>::infinity());
2885BoundedQuadraticExpression operator>=(QuadraticExpression lhs,
2886 const QuadraticTerm rhs) {
2887 lhs -= rhs;
2888 return BoundedQuadraticExpression(std::move(lhs), 0,
2889 std::numeric_limits<double>::infinity());
2890}
2891BoundedQuadraticExpression operator>=(QuadraticExpression lhs,
2892 const LinearExpression& rhs) {
2893 lhs -= rhs;
2894 return BoundedQuadraticExpression(std::move(lhs), 0,
2895 std::numeric_limits<double>::infinity());
2896}
2897BoundedQuadraticExpression operator>=(QuadraticExpression lhs,
2898 const LinearTerm rhs) {
2899 lhs -= rhs;
2900 return BoundedQuadraticExpression(std::move(lhs), 0,
2901 std::numeric_limits<double>::infinity());
2902}
2903BoundedQuadraticExpression operator>=(QuadraticExpression lhs,
2904 const Variable rhs) {
2905 lhs -= rhs;
2906 return BoundedQuadraticExpression(std::move(lhs), 0,
2907 std::numeric_limits<double>::infinity());
2908}
2909BoundedQuadraticExpression operator<=(QuadraticExpression lhs,
2910 const QuadraticExpression& rhs) {
2911 lhs -= rhs;
2913 std::move(lhs), -std::numeric_limits<double>::infinity(), 0);
2914}
2915BoundedQuadraticExpression operator<=(QuadraticExpression lhs,
2916 const QuadraticTerm rhs) {
2917 lhs -= rhs;
2919 std::move(lhs), -std::numeric_limits<double>::infinity(), 0);
2920}
2921BoundedQuadraticExpression operator<=(QuadraticExpression lhs,
2922 const LinearExpression& rhs) {
2923 lhs -= rhs;
2925 std::move(lhs), -std::numeric_limits<double>::infinity(), 0);
2926}
2927BoundedQuadraticExpression operator<=(QuadraticExpression lhs,
2928 const LinearTerm rhs) {
2929 lhs -= rhs;
2931 std::move(lhs), -std::numeric_limits<double>::infinity(), 0);
2932}
2933BoundedQuadraticExpression operator<=(QuadraticExpression lhs,
2934 const Variable rhs) {
2935 lhs -= rhs;
2937 std::move(lhs), -std::numeric_limits<double>::infinity(), 0);
2938}
2939BoundedQuadraticExpression operator==(QuadraticExpression lhs,
2940 const QuadraticExpression& rhs) {
2941 lhs -= rhs;
2942 return BoundedQuadraticExpression(std::move(lhs), 0, 0);
2943}
2944BoundedQuadraticExpression operator==(QuadraticExpression lhs,
2945 const QuadraticTerm rhs) {
2946 lhs -= rhs;
2947 return BoundedQuadraticExpression(std::move(lhs), 0, 0);
2948}
2949BoundedQuadraticExpression operator==(QuadraticExpression lhs,
2950 const LinearExpression& rhs) {
2951 lhs -= rhs;
2952 return BoundedQuadraticExpression(std::move(lhs), 0, 0);
2954BoundedQuadraticExpression operator==(QuadraticExpression lhs,
2955 const LinearTerm rhs) {
2956 lhs -= rhs;
2957 return BoundedQuadraticExpression(std::move(lhs), 0, 0);
2958}
2960 const Variable rhs) {
2961 lhs -= rhs;
2962 return BoundedQuadraticExpression(std::move(lhs), 0, 0);
2963}
2964BoundedQuadraticExpression operator==(QuadraticExpression lhs,
2965 const double rhs) {
2966 lhs -= rhs;
2967 return BoundedQuadraticExpression(std::move(lhs), 0, 0);
2968}
2969
2971 QuadraticExpression rhs) {
2972 rhs -= lhs;
2974 std::move(rhs), -std::numeric_limits<double>::infinity(), 0);
2976BoundedQuadraticExpression operator>=(const QuadraticTerm lhs,
2977 const QuadraticTerm rhs) {
2978 return BoundedQuadraticExpression(
2979 rhs - lhs, -std::numeric_limits<double>::infinity(), 0);
2981BoundedQuadraticExpression operator>=(const QuadraticTerm lhs,
2982 LinearExpression rhs) {
2983 return BoundedQuadraticExpression(
2984 std::move(rhs) - lhs, -std::numeric_limits<double>::infinity(), 0);
2986BoundedQuadraticExpression operator>=(const QuadraticTerm lhs,
2987 const LinearTerm rhs) {
2988 return BoundedQuadraticExpression(
2989 rhs - lhs, -std::numeric_limits<double>::infinity(), 0);
2991BoundedQuadraticExpression operator>=(const QuadraticTerm lhs,
2992 const Variable rhs) {
2993 return BoundedQuadraticExpression(
2994 rhs - lhs, -std::numeric_limits<double>::infinity(), 0);
2995}
2997 QuadraticExpression rhs) {
2998 rhs -= lhs;
2999 return BoundedQuadraticExpression(std::move(rhs), 0,
3000 std::numeric_limits<double>::infinity());
3001}
3003 const QuadraticTerm rhs) {
3004 return BoundedQuadraticExpression(rhs - lhs, 0,
3005 std::numeric_limits<double>::infinity());
3006}
3008 LinearExpression rhs) {
3009 return BoundedQuadraticExpression(std::move(rhs) - lhs, 0,
3010 std::numeric_limits<double>::infinity());
3011}
3013 const LinearTerm rhs) {
3014 return BoundedQuadraticExpression(rhs - lhs, 0,
3015 std::numeric_limits<double>::infinity());
3016}
3018 const Variable rhs) {
3019 return BoundedQuadraticExpression(rhs - lhs, 0,
3020 std::numeric_limits<double>::infinity());
3021}
3023 QuadraticExpression rhs) {
3024 rhs -= lhs;
3025 return BoundedQuadraticExpression(std::move(rhs), 0, 0);
3026}
3027BoundedQuadraticExpression operator==(const QuadraticTerm lhs,
3028 const QuadraticTerm rhs) {
3029 return BoundedQuadraticExpression(rhs - lhs, 0, 0);
3030}
3031BoundedQuadraticExpression operator==(const QuadraticTerm lhs,
3032 LinearExpression rhs) {
3033 return BoundedQuadraticExpression(std::move(rhs) - lhs, 0, 0);
3034}
3035BoundedQuadraticExpression operator==(const QuadraticTerm lhs,
3036 const LinearTerm rhs) {
3037 return BoundedQuadraticExpression(rhs - lhs, 0, 0);
3039BoundedQuadraticExpression operator==(const QuadraticTerm lhs,
3040 const Variable rhs) {
3041 return BoundedQuadraticExpression(rhs - lhs, 0, 0);
3042}
3044 const double rhs) {
3045 return BoundedQuadraticExpression(rhs - lhs, 0, 0);
3046}
3047
3049 QuadraticExpression rhs) {
3050 rhs -= lhs;
3052 std::move(rhs), -std::numeric_limits<double>::infinity(), 0);
3054BoundedQuadraticExpression operator>=(LinearExpression lhs,
3055 const QuadraticTerm rhs) {
3056 return BoundedQuadraticExpression(
3057 rhs - std::move(lhs), -std::numeric_limits<double>::infinity(), 0);
3058}
3059BoundedQuadraticExpression operator<=(const LinearExpression& lhs,
3060 QuadraticExpression rhs) {
3061 rhs -= lhs;
3062 return BoundedQuadraticExpression(std::move(rhs), 0,
3063 std::numeric_limits<double>::infinity());
3064}
3066 const QuadraticTerm rhs) {
3067 return BoundedQuadraticExpression(rhs - std::move(lhs), 0,
3068 std::numeric_limits<double>::infinity());
3070BoundedQuadraticExpression operator==(const LinearExpression& lhs,
3071 QuadraticExpression rhs) {
3072 rhs -= lhs;
3073 return BoundedQuadraticExpression(std::move(rhs), 0, 0);
3075BoundedQuadraticExpression operator==(LinearExpression lhs,
3076 const QuadraticTerm rhs) {
3077 return BoundedQuadraticExpression(rhs - std::move(lhs), 0, 0);
3078}
3079// LinearTerm --
3081 QuadraticExpression rhs) {
3082 rhs -= lhs;
3084 std::move(rhs), -std::numeric_limits<double>::infinity(), 0);
3086BoundedQuadraticExpression operator>=(const LinearTerm lhs,
3087 const QuadraticTerm rhs) {
3088 return BoundedQuadraticExpression(
3089 rhs - lhs, -std::numeric_limits<double>::infinity(), 0);
3090}
3092 QuadraticExpression rhs) {
3093 rhs -= lhs;
3094 return BoundedQuadraticExpression(std::move(rhs), 0,
3095 std::numeric_limits<double>::infinity());
3097BoundedQuadraticExpression operator<=(const LinearTerm lhs,
3098 const QuadraticTerm rhs) {
3099 return BoundedQuadraticExpression(rhs - lhs, 0,
3100 std::numeric_limits<double>::infinity());
3102BoundedQuadraticExpression operator==(const LinearTerm lhs,
3103 QuadraticExpression rhs) {
3104 rhs -= lhs;
3105 return BoundedQuadraticExpression(std::move(rhs), 0, 0);
3107BoundedQuadraticExpression operator==(const LinearTerm lhs,
3108 const QuadraticTerm rhs) {
3109 return BoundedQuadraticExpression(rhs - lhs, 0, 0);
3110}
3111// Variable --
3113 QuadraticExpression rhs) {
3114 rhs -= lhs;
3116 std::move(rhs), -std::numeric_limits<double>::infinity(), 0);
3118BoundedQuadraticExpression operator>=(const Variable lhs,
3119 const QuadraticTerm rhs) {
3120 return BoundedQuadraticExpression(
3121 rhs - lhs, -std::numeric_limits<double>::infinity(), 0);
3122}
3124 QuadraticExpression rhs) {
3125 rhs -= lhs;
3126 return BoundedQuadraticExpression(std::move(rhs), 0,
3127 std::numeric_limits<double>::infinity());
3129BoundedQuadraticExpression operator<=(const Variable lhs,
3130 const QuadraticTerm rhs) {
3131 return BoundedQuadraticExpression(rhs - lhs, 0,
3132 std::numeric_limits<double>::infinity());
3134BoundedQuadraticExpression operator==(const Variable lhs,
3135 QuadraticExpression rhs) {
3136 rhs -= lhs;
3137 return BoundedQuadraticExpression(std::move(rhs), 0, 0);
3139BoundedQuadraticExpression operator==(const Variable lhs,
3140 const QuadraticTerm rhs) {
3141 return BoundedQuadraticExpression(rhs - lhs, 0, 0);
3142}
3143
3144// Double --
3145BoundedQuadraticExpression operator==(const double lhs,
3146 QuadraticExpression rhs) {
3147 rhs -= lhs;
3148 return BoundedQuadraticExpression(std::move(rhs), 0, 0);
3150BoundedQuadraticExpression operator==(const double lhs,
3151 const QuadraticTerm rhs) {
3152 return BoundedQuadraticExpression(rhs - lhs, 0, 0);
3153}
3154
3155} // namespace math_opt
3156} // namespace operations_research
3157
3158#endif // OR_TOOLS_MATH_OPT_CPP_VARIABLE_AND_EXPRESSIONS_H_
double EvaluateWithDefaultZero(const VariableMap< double > &variable_values) const
static LinearExpression InnerProduct(const LeftIterable &left, const RightIterable &right)
friend LinearExpression operator-(LinearExpression expr)
double Evaluate(const VariableMap< double > &variable_values) const
const VariableMap< double > & terms() const
Returns the terms in this expression.
LinearExpression & operator-=(const LinearExpression &other)
friend std::ostream & operator<<(std::ostream &ostr, const LinearExpression &expression)
LinearExpression & operator+=(const LinearExpression &other)
void AddInnerProduct(const LeftIterable &left, const RightIterable &right)
LinearExpression & operator=(const LinearExpression &other)=default
LinearExpression(const LinearExpression &other)=default
static LinearExpression Sum(const Iterable &items)
void AddInnerProduct(const LeftIterable &left, const RightIterable &right)
const QuadraticTermMap< double > & quadratic_terms() const
static RightIterable QuadraticExpression InnerProduct(const LeftIterable &left, const RightIterable &right)
friend std::ostream & operator<<(std::ostream &ostr, const QuadraticExpression &expr)
double EvaluateWithDefaultZero(const VariableMap< double > &variable_values) const
QuadraticExpression(const QuadraticExpression &other)=default
static QuadraticExpression Sum(const Iterable &items)
double Evaluate(const VariableMap< double > &variable_values) const
friend QuadraticExpression operator-(QuadraticExpression expr)
QuadraticExpression & operator=(const QuadraticExpression &other)=default
QuadraticTermKey(const ModelStorage *storage, QuadraticProductId id)
Variable first() const
Returns the Variable with the smallest id.
Variable second() const
Returns the Variable the largest id.
friend H AbslHashValue(H h, const QuadraticTermKey &key)
friend QuadraticTerm operator*(double lhs, QuadraticTerm rhs)
-------------------------— Multiplication (*) --------------------------—
friend QuadraticTerm operator-(QuadraticTerm term)
------------------------— Subtraction (-) ------------------------------—
QuadraticTermKey GetKey() const
This is useful for working with IdMaps.
friend QuadraticTerm operator/(QuadraticTerm lhs, double rhs)
----------------------------— Division (/) -----------------------------—
friend std::ostream & operator<<(std::ostream &ostr, const Variable &variable)
VariableId IdType
The typed integer used for ids.
friend H AbslHashValue(H h, const Variable &variable)
Variable(const ModelStorage *storage, VariableId id)
const std::string name
A name for logging purposes.
int64_t value
IntVar * var
double upper_bound
double lower_bound
constexpr absl::string_view kKeyHasNullModelStorage
The CHECK message to use when a KeyType::storage() is nullptr.
Definition key_types.h:151
constexpr absl::string_view kObjectsFromOtherModelStorage
Definition key_types.h:156
void AddInnerProduct(const LeftIterable &left, const RightIterable &right, Expression &expr)
absl::flat_hash_map< Variable, V > VariableMap
LinearExpression Sum(const Iterable &items)
LinearExpression operator+(Variable lhs, double rhs)
absl::flat_hash_map< QuadraticTermKey, V > QuadraticTermMap
LinearTerm operator*(double coefficient, LinearTerm term)
std::ostream & operator<<(std::ostream &ostr, const IndicatorConstraint &constraint)
bool operator==(const IndicatorConstraint &lhs, const IndicatorConstraint &rhs)
bool operator!=(const IndicatorConstraint &lhs, const IndicatorConstraint &rhs)
LowerBoundedLinearExpression operator>=(LinearExpression expression, double constant)
RightIterable LinearExpression InnerProduct(const LeftIterable &left, const RightIterable &right)
LowerBoundedLinearExpression operator<=(double constant, LinearExpression expression)
LinearTerm operator/(LinearTerm term, double coefficient)
LinearExpression operator-(LinearExpression expr)
std::pair< VariableId, VariableId > QuadraticProductId
Id type used for quadratic terms, i.e. products of two variables.
H AbslHashValue(H h, const IndicatorConstraint &constraint)
In SWIG mode, we don't want anything besides these top-level includes.
LinearRange operator==(const LinearExpr &lhs, const LinearExpr &rhs)
H AbslHashValue(H h, const StrongIndex< StrongIndexName > &i)
– ABSL HASHING SUPPORT --------------------------------------------------—
std::ostream & operator<<(std::ostream &out, const Assignment &assignment)
STL namespace.
int64_t coefficient
std::optional< int64_t > end
A LinearExpression with upper and lower bounds.
BoundedLinearExpression(LinearExpression expression, double lower_bound, double upper_bound)
A QuadraticExpression with upper and lower bounds.
BoundedQuadraticExpression(QuadraticExpression expression, double lower_bound, double upper_bound)
A term in an sum of variables multiplied by coefficients.
LinearTerm(Variable variable, double coefficient)
LowerBoundedLinearExpression(LinearExpression expression, double lower_bound)
LowerBoundedQuadraticExpression(QuadraticExpression expression, double lower_bound)
UpperBoundedLinearExpression(LinearExpression expression, double upper_bound)
UpperBoundedQuadraticExpression(QuadraticExpression expression, double upper_bound)