OR-Tools  9.3
variable_and_expressions.h
Go to the documentation of this file.
1// Copyright 2010-2021 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// An object oriented wrapper for variables in ModelStorage (used internally by
15// Model) with support for arithmetic operations to build linear expressions and
16// express linear constraints.
17//
18// Types are:
19// - Variable: a reference to a variable of an ModelStorage.
20//
21// - LinearExpression: a weighted sum of variables with an optional offset;
22// something like `3*x + 2*y + 5`.
23//
24// - LinearTerm: a term of a linear expression, something like `2*x`. It is
25// used as an intermediate in the arithmetic operations that builds linear
26// expressions.
27//
28// - (Lower|Upper)BoundedLinearExpression: two classes representing the result
29// of the comparison of a LinearExpression with a constant. For example `3*x
30// + 2*y + 5 >= 3`.
31//
32// - BoundedLinearExpression: the result of the comparison of a linear
33// expression with two bounds, an upper bound and a lower bound. For example
34// `2 <= 3*x + 2*y + 5 <= 3`; or `4 >= 3*x + 2*y + 5 >= 1`.
35//
36// - QuadraticTermKey: a key used internally to represent a pair of Variables.
37//
38// - QuadraticTerm: a term representing the product of a scalar coefficient
39// and two Variables (possibly the same); something like `2*x*y` or `3*x*x`.
40// It is used as an intermediate in the arithmetic operations that build
41// quadratic expressions.
42//
43// - QuadraticExpression: a sum of a quadratic terms, linear terms, and a
44// scalar offset; something like `3*x*y + 2*x*x + 4x + 5`.
45//
46// - VariablesEquality: the result of comparing two Variable instances with
47// the == operator. For example `a == b`. This intermediate class support
48// implicit conversion to both bool and BoundedLinearExpression types. This
49// enables using variables as key of maps (using the conversion to bool)
50// without preventing adding constraints of variable equality.
51//
52// The basic arithmetic operators are overloaded for those types so that we can
53// write math expressions with variables to build linear expressions. The >=, <=
54// and == comparison operators are overloaded to produce BoundedLinearExpression
55// that can be used to build constraints.
56//
57// For example we can have:
58// const Variable x = ...;
59// const Variable y = ...;
60// const LinearExpression expr = 2 * x + 3 * y - 2;
61// const BoundedLinearExpression bounded_expr = 1 <= 2 * x + 3 * y - 2 <= 10;
62//
63// To making working with containers of doubles/Variables/LinearExpressions
64// easier, the template methods Sum() and InnerProduct() are provided, e.g.
65// const std::vector<int> ints = ...;
66// const std::vector<double> doubles = ...;
67// const std::vector<Variable> vars = ...;
68// const std::vector<LinearTerm> terms = ...;
69// const std::vector<LinearExpression> exprs = ...;
70// const LinearExpression s1 = Sum(ints);
71// const LinearExpression s2 = Sum(doubles);
72// const LinearExpression s3 = Sum(vars);
73// const LinearExpression s4 = Sum(terms);
74// const LinearExpression s5 = Sum(exprs);
75// const LinearExpression p1 = InnerProduct(ints, vars);
76// const LinearExpression p2 = InnerProduct(terms, doubles);
77// const LinearExpression p3 = InnerProduct(doubles, exprs);
78// These methods work on any iterable type (defining begin() and end()). For
79// InnerProduct, the inputs must be of equal size, and a compile time error will
80// be generated unless at least one input is a container of a type implicitly
81// convertible to double.
82//
83// Pre C++20, avoid the use of std::accumulate and std::inner_product with
84// LinearExpression, they cause a quadratic blowup in running time.
85//
86// While there is some complexity in the source, users typically should not need
87// to look at types other than Variable and LinearExpression too closely. Their
88// code usually will only refer to those types.
89#ifndef OR_TOOLS_MATH_OPT_CPP_VARIABLE_AND_EXPRESSIONS_H_
90#define OR_TOOLS_MATH_OPT_CPP_VARIABLE_AND_EXPRESSIONS_H_
91
92#include <stdint.h>
93
94#include <initializer_list>
95#include <iterator>
96#include <limits>
97#include <string>
98#include <utility>
99
100#include "absl/container/flat_hash_map.h"
101#include "ortools/base/logging.h"
104#include "ortools/math_opt/cpp/id_map.h" // IWYU pragma: export
105#include "ortools/math_opt/cpp/key_types.h" // IWYU pragma: export
106
107namespace operations_research {
108namespace math_opt {
109
110// Forward declaration needed by Variable.
111class LinearExpression;
112
113// A value type that references a variable from ModelStorage. Usually this type
114// is passed by copy.
115class Variable {
116 public:
117 // The typed integer used for ids.
118 using IdType = VariableId;
119
120 // Usually users will obtain variables using Model::AddVariable(). There
121 // should be little for users to build this object from an ModelStorage.
122 inline Variable(const ModelStorage* storage, VariableId id);
123
124 // Each call to AddVariable will produce Variables id() increasing by one,
125 // starting at zero. Deleted ids are NOT reused. Thus, if no variables are
126 // deleted, the ids in the model will be consecutive.
127 inline int64_t id() const;
128
129 inline VariableId typed_id() const;
130 inline const ModelStorage* storage() const;
131
132 inline double lower_bound() const;
133 inline double upper_bound() const;
134 inline bool is_integer() const;
135 inline const std::string& name() const;
136
137 template <typename H>
138 friend H AbslHashValue(H h, const Variable& variable);
139 friend std::ostream& operator<<(std::ostream& ostr, const Variable& variable);
140
141 inline LinearExpression operator-() const;
142
143 private:
144 const ModelStorage* storage_;
145 VariableId id_;
146};
147
148// Implements the API of std::unordered_map<Variable, V>, but forbids Variables
149// from different models in the same map.
150template <typename V>
152
153inline std::ostream& operator<<(std::ostream& ostr, const Variable& variable);
154
155// A term in an sum of variables multiplied by coefficients.
157 // Usually this constructor is never called explicitly by users. Instead it
158 // will be implicitly used when writing linear expression. For example `x +
159 // 2*y` will automatically use this constructor to build a LinearTerm from `x`
160 // and the overload of the operator* will also automatically create the one
161 // from `2*y`.
162 inline LinearTerm(Variable variable, double coefficient);
163 inline LinearTerm operator-() const;
164 inline LinearTerm& operator*=(double d);
165 inline LinearTerm& operator/=(double d);
168};
169
170inline LinearTerm operator*(double coefficient, LinearTerm term);
171inline LinearTerm operator*(LinearTerm term, double coefficient);
172inline LinearTerm operator*(double coefficient, Variable variable);
173inline LinearTerm operator*(Variable variable, double coefficient);
174inline LinearTerm operator/(LinearTerm term, double coefficient);
175inline LinearTerm operator/(Variable variable, double coefficient);
176
177// Forward declaration so that we may add it as a friend to LinearExpression
179
180// This class represents a sum of variables multiplied by coefficient and an
181// optional offset constant. For example: "3*x + 2*y + 5".
182//
183// All operations, including constructor, will raise an assertion if the
184// operands involve variables from different Model objects.
185//
186// Contrary to Variable type, expressions owns the linear expression their
187// represent. Hence they are usually passed by reference to prevent unnecessary
188// copies.
189//
190// TODO(b/169415098): add a function to remove zero terms.
191// TODO(b/169415834): study if exact zeros should be automatically removed.
192// TODO(b/169415103): add tests that some expressions don't compile.
194 public:
195 // For unit testing purpose, we define optional counters. We have to
196 // explicitly define default constructors in that case.
197#ifndef MATH_OPT_USE_EXPRESSION_COUNTERS
198 LinearExpression() = default;
199#else // MATH_OPT_USE_EXPRESSION_COUNTERS
203 LinearExpression& operator=(const LinearExpression& other);
204#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
205 // Usually users should use the overloads of operators to build linear
206 // expressions. For example, assuming `x` and `y` are Variable, then `x + 2*y
207 // + 5` will build a LinearExpression automatically.
208 inline LinearExpression(std::initializer_list<LinearTerm> terms,
209 double offset);
210 inline LinearExpression(double offset); // NOLINT
211 inline LinearExpression(Variable variable); // NOLINT
212 inline LinearExpression(const LinearTerm& term); // NOLINT
213
214 inline LinearExpression& operator+=(const LinearExpression& other);
215 inline LinearExpression& operator+=(const LinearTerm& term);
216 inline LinearExpression& operator+=(Variable variable);
217 inline LinearExpression& operator+=(double value);
218 inline LinearExpression& operator-=(const LinearExpression& other);
219 inline LinearExpression& operator-=(const LinearTerm& term);
220 inline LinearExpression& operator-=(Variable variable);
221 inline LinearExpression& operator-=(double value);
222 inline LinearExpression& operator*=(double value);
223 inline LinearExpression& operator/=(double value);
224
225 // Adds each element of items to this.
226 //
227 // Specifically, letting
228 // (i_1, i_2, ..., i_n) = items
229 // adds
230 // i_1 + i_2 + ... + i_n
231 // to this.
232 //
233 // Example:
234 // Variable a = ...;
235 // Variable b = ...;
236 // const std::vector<Variable> vars = {a, b};
237 // LinearExpression expr(8.0);
238 // expr.AddSum(vars);
239 // Results in expr having the value a + b + 8.0.
240 //
241 // Compile time requirements:
242 // * Iterable is a sequence (an array or object with begin() and end()).
243 // * The type of an element of items is one of double, Variable, LinearTerm
244 // or LinearExpression (or is implicitly convertible to one of these types,
245 // e.g. int).
246 //
247 // Note: The implementation is equivalent to:
248 // for(const auto item : items) {
249 // *this += item;
250 // }
251 template <typename Iterable>
252 inline void AddSum(const Iterable& items);
253
254 // Adds the inner product of left and right to this.
255 //
256 // Specifically, letting
257 // (l_1, l_2 ..., l_n) = left,
258 // (r_1, r_2, ..., r_n) = right,
259 // adds
260 // l_1 * r_1 + l_2 * r_2 + ... + l_n * r_n
261 // to this.
262 //
263 // Example:
264 // Variable a = ...;
265 // Variable b = ...;
266 // const std::vector<Variable> left = {a, b};
267 // const std::vector<double> right = {10.0, 2.0};
268 // LinearExpression expr(3.0);
269 // expr.AddInnerProduct(left, right)
270 // Results in expr having the value 10.0 * a + 2.0 * b + 3.0.
271 //
272 // Compile time requirements:
273 // * LeftIterable and RightIterable are both sequences (arrays or objects
274 // with begin() and end())
275 // * For both left and right, their elements a type of either double,
276 // Variable, LinearTerm or LinearExpression (or type implicitly convertible
277 // to one of these types, e.g. int).
278 // * At least one of left or right has elements with type double (or a type
279 // implicitly convertible, e.g. int).
280 // Runtime requirements (or CHECK fails):
281 // * left and right have an equal number of elements.
282 //
283 // Note: The implementation is equivalent to:
284 // for(const auto& [l, r] : zip(left, right)) {
285 // *this += l * r;
286 // }
287 // In particular, the multiplication will be performed on the types of the
288 // elements in left and right (take care with low precision types), but the
289 // addition will always use double precision.
290 template <typename LeftIterable, typename RightIterable>
291 inline void AddInnerProduct(const LeftIterable& left,
292 const RightIterable& right);
293
294 // Returns the terms in this expression.
295 inline const VariableMap<double>& terms() const;
296 inline double offset() const;
297
298 // Compute the numeric value of this expression when variables are substituted
299 // by their values in variable_values.
300 //
301 // Will CHECK fail the underlying model storage is different or if a variable
302 // in terms() is missing from variables_values.
303 double Evaluate(const VariableMap<double>& variable_values) const;
304
305 // Compute the numeric value of this expression when variables are substituted
306 // by their values in variable_values, or zero if missing from the map.
307 //
308 // Will CHECK fail the underlying model storage is different.
310 const VariableMap<double>& variable_values) const;
311
312 inline const ModelStorage* storage() const;
313 inline const absl::flat_hash_map<VariableId, double>& raw_terms() const;
314
315#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
316 static thread_local int num_calls_default_constructor_;
317 static thread_local int num_calls_copy_constructor_;
318 static thread_local int num_calls_move_constructor_;
319 static thread_local int num_calls_initializer_list_constructor_;
320 // Reset all counters in the current thread to 0.
321 static void ResetCounters();
322#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
323
324 private:
326 friend std::ostream& operator<<(std::ostream& ostr,
327 const LinearExpression& expression);
328 friend QuadraticExpression;
329
330 VariableMap<double> terms_;
331 double offset_ = 0.0;
332};
333
334// Returns the sum of the elements of items.
335//
336// Specifically, letting
337// (i_1, i_2, ..., i_n) = items
338// returns
339// i_1 + i_2 + ... + i_n.
340//
341// Example:
342// Variable a = ...;
343// Variable b = ...;
344// const std::vector<Variable> vars = {a, b, a};
345// Sum(vars)
346// => 2.0 * a + b
347// Note, instead of:
348// LinearExpression expr(3.0);
349// expr += Sum(items);
350// Prefer:
351// expr.AddSum(items);
352//
353// See LinearExpression::AddSum() for a precise contract on the type Iterable.
354template <typename Iterable>
355inline LinearExpression Sum(const Iterable& items);
356
357// Returns the inner product of left and right.
358//
359// Specifically, letting
360// (l_1, l_2 ..., l_n) = left,
361// (r_1, r_2, ..., r_n) = right,
362// returns
363// l_1 * r_1 + l_2 * r_2 + ... + l_n * r_n.
364//
365// Example:
366// Variable a = ...;
367// Variable b = ...;
368// const std::vector<Variable> left = {a, b};
369// const std::vector<double> right = {10.0, 2.0};
370// InnerProduct(left, right);
371// -=> 10.0 * a + 2.0 * b
372// Note, instead of:
373// LinearExpression expr(3.0);
374// expr += InnerProduct(left, right);
375// Prefer:
376// expr.AddInnerProduct(left, right);
377//
378// Requires that left and right have equal size, see
379// LinearExpression::AddInnerProduct for a precise contract on template types.
380template <typename LeftIterable, typename RightIterable>
381inline LinearExpression InnerProduct(const LeftIterable& left,
382 const RightIterable& right);
383
384std::ostream& operator<<(std::ostream& ostr,
385 const LinearExpression& expression);
386
387// We intentionally pass one of the LinearExpression argument by value so
388// that we don't make unnecessary copies of temporary objects by using the move
389// constructor and the returned values optimization (RVO).
391inline LinearExpression operator+(Variable lhs, double rhs);
392inline LinearExpression operator+(double lhs, Variable rhs);
394inline LinearExpression operator+(const LinearTerm& lhs, double rhs);
395inline LinearExpression operator+(double lhs, const LinearTerm& rhs);
396inline LinearExpression operator+(const LinearTerm& lhs, Variable rhs);
397inline LinearExpression operator+(Variable lhs, const LinearTerm& rhs);
398inline LinearExpression operator+(const LinearTerm& lhs, const LinearTerm& rhs);
399inline LinearExpression operator+(LinearExpression lhs, double rhs);
400inline LinearExpression operator+(double lhs, LinearExpression rhs);
406 const LinearExpression& rhs);
407inline LinearExpression operator-(Variable lhs, double rhs);
408inline LinearExpression operator-(double lhs, Variable rhs);
410inline LinearExpression operator-(const LinearTerm& lhs, double rhs);
411inline LinearExpression operator-(double lhs, const LinearTerm& rhs);
412inline LinearExpression operator-(const LinearTerm& lhs, Variable rhs);
413inline LinearExpression operator-(Variable lhs, const LinearTerm& rhs);
414inline LinearExpression operator-(const LinearTerm& lhs, const LinearTerm& rhs);
415inline LinearExpression operator-(LinearExpression lhs, double rhs);
416inline LinearExpression operator-(double lhs, LinearExpression rhs);
422 const LinearExpression& rhs);
423inline LinearExpression operator*(LinearExpression lhs, double rhs);
424inline LinearExpression operator*(double lhs, LinearExpression rhs);
425inline LinearExpression operator/(LinearExpression lhs, double rhs);
426
427namespace internal {
428
429// The result of the equality comparison between two Variable.
430//
431// We use an object here to delay the evaluation of equality so that we can use
432// the operator== in two use-cases:
433//
434// 1. when the user want to test that two Variable values references the same
435// variable. This is supported by having this object support implicit
436// conversion to bool.
437//
438// 2. when the user want to use the equality to create a constraint of equality
439// between two variables.
441 // Users are not expected to call this constructor. Instead they should only
442 // use the overload of `operator==` that returns this when comparing two
443 // Variable. For example `x == y`.
445 inline operator bool() const; // NOLINT
448};
449
450} // namespace internal
451
453 const Variable& rhs);
454inline bool operator!=(const Variable& lhs, const Variable& rhs);
455
456// A LinearExpression with a lower bound.
458 // Users are not expected to use this constructor. Instead they should build
459 // this object using the overloads of >= and <= operators. For example `x + y
460 // >= 3`.
462 double lower_bound);
465};
466
467// A LinearExpression with an upper bound.
469 // Users are not expected to use this constructor. Instead they should build
470 // this object using the overloads of >= and <= operators. For example `x + y
471 // <= 3`.
473 double upper_bound);
476};
477
478// A LinearExpression with upper and lower bounds.
480 // Users are not expected to use this constructor. Instead they should build
481 // this object using the overloads of >= and <= operators. For example `3 <= x
482 // + y <= 3`.
484 double lower_bound, double upper_bound);
485 // Users are not expected to use this constructor. This implicit conversion
486 // will be used where a BoundedLinearExpression is expected and the user uses
487 // == comparison of two variables. For example `AddLinearConstraint(x == y);`.
488 inline BoundedLinearExpression( // NOLINT
490 inline BoundedLinearExpression( // NOLINT
491 LowerBoundedLinearExpression lb_expression);
492 inline BoundedLinearExpression( // NOLINT
493 UpperBoundedLinearExpression ub_expression);
494
495 // Returns the actual lower_bound after taking into account the linear
496 // expression offset.
497 inline double lower_bound_minus_offset() const;
498 // Returns the actual upper_bound after taking into account the linear
499 // expression offset.
500 inline double upper_bound_minus_offset() const;
501
505};
506
507std::ostream& operator<<(std::ostream& ostr,
508 const BoundedLinearExpression& bounded_expression);
509
510// We intentionally pass the LinearExpression argument by value so that we don't
511// make unnecessary copies of temporary objects by using the move constructor
512// and the returned values optimization (RVO).
514 double constant);
516 LinearExpression expression);
518 double constant);
520 const LinearTerm& term);
522 double constant);
524 Variable variable);
526 double constant);
528 LinearExpression expression);
530 double constant);
532 const LinearTerm& term);
534 double constant);
536 Variable variable);
537
538// We intentionally pass the UpperBoundedLinearExpression and
539// LowerBoundedLinearExpression arguments by value so that we don't
540// make unnecessary copies of temporary objects by using the move constructor
541// and the returned values optimization (RVO).
543 double rhs);
544inline BoundedLinearExpression operator>=(double lhs,
547 double rhs);
548inline BoundedLinearExpression operator<=(double lhs,
550// We intentionally pass one LinearExpression argument by value so that we don't
551// make unnecessary copies of temporary objects by using the move constructor
552// and the returned values optimization (RVO).
554 const LinearExpression& rhs);
556 const LinearExpression& rhs);
558 const LinearTerm& rhs);
560 const LinearTerm& rhs);
562 LinearExpression rhs);
564 LinearExpression rhs);
570 const LinearTerm& rhs);
572 const LinearTerm& rhs);
580 const LinearExpression& rhs);
582 const LinearTerm& rhs);
584 LinearExpression rhs);
590 const LinearTerm& rhs);
593inline BoundedLinearExpression operator==(const LinearTerm& lhs, double rhs);
594inline BoundedLinearExpression operator==(double lhs, const LinearTerm& rhs);
595inline BoundedLinearExpression operator==(Variable lhs, double rhs);
596inline BoundedLinearExpression operator==(double lhs, Variable rhs);
597
598// Id type used for quadratic terms, i.e. products of two variables.
599using QuadraticProductId = std::pair<VariableId, VariableId>;
600
601// Couples a QuadraticProductId with a ModelStorage, for use with IdMaps.
602// Namely, this key type satisfies the requirements stated in key_types.h.
603// Invariant:
604// * variable_ids_.first <= variable_ids_.second. The constructor will
605// silently correct this if not satisfied by the inputs.
607 public:
608 // NOTE: this definition is for use by IdMap; clients should not rely upon it.
610
611 // NOTE: This constructor will silently re-order the passed id so that, upon
612 // exiting the constructor, variable_ids_.first <= variable_ids_.second.
614 // NOTE: This constructor will CHECK fail if the variable models do not agree,
615 // i.e. first_variable.storage() != second_variable.storage(). It will also
616 // silently re-order the passed id so that, upon exiting the constructor,
617 // variable_ids_.first <= variable_ids_.second.
618 inline QuadraticTermKey(Variable first_variable, Variable second_variable);
619
620 inline QuadraticProductId typed_id() const;
621 inline const ModelStorage* storage() const;
622
623 template <typename H>
624 friend H AbslHashValue(H h, const QuadraticTermKey& key);
625
626 private:
627 const ModelStorage* storage_;
628 QuadraticProductId variable_ids_;
629};
630
631inline bool operator==(const QuadraticTermKey lhs, const QuadraticTermKey rhs);
632inline bool operator!=(const QuadraticTermKey lhs, const QuadraticTermKey rhs);
633
634// Represents a quadratic term in a sum: coefficient * variable_1 * variable_2.
635// Invariant:
636// * first_variable.storage() == second_variable.storage(). The constructor
637// will CHECK fail if not satisfied.
639 public:
640 QuadraticTerm() = delete;
641 // NOTE: This will CHECK fail if
642 // first_variable.storage() != second_variable.storage().
644 double coefficient);
645
646 inline double coefficient() const;
647 inline Variable first_variable() const;
648 inline Variable second_variable() const;
649
650 // This is useful for working with IdMaps
651 inline QuadraticTermKey GetKey() const;
652
653 inline QuadraticTerm& operator*=(double value);
654 inline QuadraticTerm& operator/=(double value);
655
656 private:
658 friend QuadraticTerm operator*(double lhs, QuadraticTerm rhs);
659 friend QuadraticTerm operator*(QuadraticTerm lhs, double rhs);
660 friend QuadraticTerm operator/(QuadraticTerm lhs, double rhs);
661
662 Variable first_variable_;
663 Variable second_variable_;
664 double coefficient_;
665};
666// We declare those operator overloads that result in a QuadraticTerm, stated in
667// lexicographic ordering based on lhs type, rhs type):
669inline QuadraticTerm operator*(double lhs, QuadraticTerm rhs);
674inline QuadraticTerm operator*(QuadraticTerm lhs, double rhs);
675inline QuadraticTerm operator/(QuadraticTerm lhs, double rhs);
676
677// Implements the API of std::unordered_map<QuadraticTermKey, V>, but forbids
678// QuadraticTermKeys from different models in the same map.
679template <typename V>
681
682// This class represents a sum of quadratic terms, linear terms, and constant
683// offset. For example: "3*x*y + 2*x + 1".
684//
685// Mixing terms involving variables from different ModelStorage objects will
686// lead to CHECK fails, including from the constructors.
687//
688// The type owns the associated data representing the terms, and so should
689// usually be passed by (const) reference to avoid unnecessary copies.
690//
691// Note for implementers: Care must be taken to ensure that
692// linear_terms_.storage() and quadratic_terms_.storage() do not disagree. That
693// is, it is forbidden that both are non-null and not equal. Use
694// CheckModelsAgree() and the initializer_list constructor to enforce this
695// invariant in any class or friend method.
697 public:
698#ifndef MATH_OPT_USE_EXPRESSION_COUNTERS
700#else // MATH_OPT_USE_EXPRESSION_COUNTERS
704 QuadraticExpression& operator=(const QuadraticExpression& other);
705#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
706 // Users should prefer the default constructor and operator overloads to build
707 // expressions.
708 inline QuadraticExpression(
709 std::initializer_list<QuadraticTerm> quadratic_terms,
710 std::initializer_list<LinearTerm> linear_terms, double offset);
711 inline QuadraticExpression(double offset); // NOLINT
712 inline QuadraticExpression(Variable variable); // NOLINT
713 inline QuadraticExpression(const LinearTerm& term); // NOLINT
714 inline QuadraticExpression(LinearExpression expr); // NOLINT
715 inline QuadraticExpression(const QuadraticTerm& term); // NOLINT
716
717 inline double offset() const;
718 inline const VariableMap<double>& linear_terms() const;
719 inline const QuadraticTermMap<double>& quadratic_terms() const;
720
721 inline const absl::flat_hash_map<VariableId, double>& raw_linear_terms()
722 const;
723 inline const absl::flat_hash_map<QuadraticProductId, double>&
724 raw_quadratic_terms() const;
725
726 inline QuadraticExpression& operator+=(double value);
727 inline QuadraticExpression& operator+=(Variable variable);
728 inline QuadraticExpression& operator+=(const LinearTerm& term);
730 inline QuadraticExpression& operator+=(const QuadraticTerm& term);
732 inline QuadraticExpression& operator-=(double value);
733 inline QuadraticExpression& operator-=(Variable variable);
734 inline QuadraticExpression& operator-=(const LinearTerm& term);
736 inline QuadraticExpression& operator-=(const QuadraticTerm& term);
738 inline QuadraticExpression& operator*=(double value);
739 inline QuadraticExpression& operator/=(double value);
740
741 // Compute the numeric value of this expression when variables are substituted
742 // by their values in variable_values.
743 //
744 // Will CHECK fail if the underlying model storage is different, or if a
745 // variable in linear_terms() or quadratic_terms() is missing from
746 // variables_values.
747 double Evaluate(const VariableMap<double>& variable_values) const;
748
749 // Compute the numeric value of this expression when variables are substituted
750 // by their values in variable_values, or zero if missing from the map.
751 //
752 // Will CHECK fail the underlying model storage is different.
754 const VariableMap<double>& variable_values) const;
755
756 inline const ModelStorage* storage() const;
757
758#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
759 static thread_local int num_calls_default_constructor_;
760 static thread_local int num_calls_copy_constructor_;
761 static thread_local int num_calls_move_constructor_;
762 static thread_local int num_calls_initializer_list_constructor_;
763 static thread_local int num_calls_linear_expression_constructor_;
764 // Reset all counters in the current thread to 0.
765 static void ResetCounters();
766#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
767
768 private:
770 friend std::ostream& operator<<(std::ostream& ostr,
771 const QuadraticExpression& expr);
772 inline void CheckModelsAgree();
773
774 QuadraticTermMap<double> quadratic_terms_;
775 VariableMap<double> linear_terms_;
776 double offset_ = 0.0;
777};
778
779// We have 6 types that we must consider arithmetic among:
780// 1. double (scalar value)
781// 2. Variable (affine value)
782// 3. LinearTerm (affine value)
783// 4. LinearExpression (affine value)
784// 5. QuadraticTerm (quadratic value)
785// 6. QuadraticExpression (quadratic value)
786// We care only about those methods that result in a QuadraticExpression. For
787// example, multiplying a linear value with a linear value, or adding a scalar
788// to a quadratic value. The single unary method is:
790
791// The binary methods, listed in lexicographic order based on
792// (operator, lhs type #, rhs type #), with the type #s are listed above, are:
793inline QuadraticExpression operator+(double lhs, const QuadraticTerm& rhs);
798 const QuadraticTerm& rhs);
802 const QuadraticTerm& rhs);
805inline QuadraticExpression operator+(const QuadraticTerm& lhs, double rhs);
808 const LinearTerm& rhs);
810 LinearExpression rhs);
812 const QuadraticTerm& rhs);
818 const LinearTerm& rhs);
820 const LinearExpression& rhs);
822 const QuadraticTerm& rhs);
824 const QuadraticExpression& rhs);
825
826inline QuadraticExpression operator-(double lhs, const QuadraticTerm& rhs);
831 const QuadraticTerm& rhs);
835 const QuadraticTerm& rhs);
838inline QuadraticExpression operator-(const QuadraticTerm& lhs, double rhs);
841 const LinearTerm& rhs);
843 LinearExpression rhs);
845 const QuadraticTerm& rhs);
851 const LinearTerm& rhs);
853 const LinearExpression& rhs);
855 const QuadraticTerm& rhs);
857 const QuadraticExpression& rhs);
858
862 const LinearExpression& rhs);
865 LinearTerm rhs);
867 const LinearExpression& rhs);
869
871
874// Inline function implementations /////////////////////////////////////////////
877
879// Variable
881
882Variable::Variable(const ModelStorage* const storage, const VariableId id)
883 : storage_(storage), id_(id) {
884 DCHECK(storage != nullptr);
885}
886
887int64_t Variable::id() const { return id_.value(); }
888
889VariableId Variable::typed_id() const { return id_; }
890
891const ModelStorage* Variable::storage() const { return storage_; }
892
893double Variable::lower_bound() const {
894 return storage_->variable_lower_bound(id_);
895}
896
897double Variable::upper_bound() const {
898 return storage_->variable_upper_bound(id_);
899}
900
901bool Variable::is_integer() const { return storage_->is_variable_integer(id_); }
902
903const std::string& Variable::name() const {
904 return storage_->variable_name(id_);
905}
906
907template <typename H>
908H AbslHashValue(H h, const Variable& variable) {
909 return H::combine(std::move(h), variable.id_.value(), variable.storage_);
910}
911
912std::ostream& operator<<(std::ostream& ostr, const Variable& variable) {
913 // TODO(b/170992529): handle quoting of invalid characters in the name.
914 const std::string& name = variable.name();
915 if (name.empty()) {
916 ostr << "__var#" << variable.id() << "__";
917 } else {
918 ostr << name;
919 }
920 return ostr;
921}
922
924 return LinearExpression({LinearTerm(*this, -1.0)}, 0.0);
925}
926
928// LinearTerm
930
932 : variable(std::move(variable)), coefficient(coefficient) {}
933
936}
937
939 coefficient *= d;
940 return *this;
941}
942
944 coefficient /= d;
945 return *this;
946}
947
949 term *= coefficient;
950 return term;
951}
952
954 term *= coefficient;
955 return term;
956}
957
958LinearTerm operator*(const double coefficient, Variable variable) {
959 return LinearTerm(std::move(variable), coefficient);
960}
961
962LinearTerm operator*(Variable variable, const double coefficient) {
963 return LinearTerm(std::move(variable), coefficient);
964}
965
967 term /= coefficient;
968 return term;
969}
970
971LinearTerm operator/(Variable variable, const double coefficient) {
972 return LinearTerm(std::move(variable), 1 / coefficient);
973}
974
976// LinearExpression
978
979LinearExpression::LinearExpression(std::initializer_list<LinearTerm> terms,
980 const double offset)
981 : offset_(offset) {
982#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
983 ++num_calls_initializer_list_constructor_;
984#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
985 for (const auto& term : terms) {
986 // The same variable may appear multiple times in the input list; we must
987 // accumulate the coefficients.
988 terms_[term.variable] += term.coefficient;
989 }
990}
991
993 : LinearExpression({}, offset) {}
994
996 : LinearExpression({LinearTerm(variable, 1.0)}, 0.0) {}
997
999 : LinearExpression({term}, 0.0) {}
1000
1002 expr.offset_ = -expr.offset_;
1003 for (auto term : expr.terms_) {
1004 term.second = -term.second;
1005 }
1006 return expr;
1007}
1008
1009LinearExpression operator+(const Variable lhs, const double rhs) {
1010 return LinearTerm(lhs, 1.0) + rhs;
1011}
1012
1013LinearExpression operator+(const double lhs, const Variable rhs) {
1014 return lhs + LinearTerm(rhs, 1.0);
1015}
1016
1018 return LinearTerm(lhs, 1.0) + LinearTerm(rhs, 1.0);
1019}
1020
1021LinearExpression operator+(const LinearTerm& lhs, const double rhs) {
1022 return LinearExpression({lhs}, rhs);
1023}
1024
1025LinearExpression operator+(const double lhs, const LinearTerm& rhs) {
1026 return LinearExpression({rhs}, lhs);
1027}
1028
1030 return lhs + LinearTerm(rhs, 1.0);
1031}
1032
1034 return LinearTerm(lhs, 1.0) + rhs;
1035}
1036
1038 return LinearExpression({lhs, rhs}, 0);
1039}
1040
1042 lhs += rhs;
1043 return lhs;
1044}
1045
1047 rhs += lhs;
1048 return rhs;
1049}
1050
1052 return std::move(lhs) + LinearTerm(rhs, 1.0);
1053}
1054
1056 return LinearTerm(lhs, 1.0) + std::move(rhs);
1057}
1058
1060 lhs += rhs;
1061 return lhs;
1062}
1063
1065 rhs += lhs;
1066 return rhs;
1067}
1068
1070 lhs += rhs;
1071 return lhs;
1072}
1073
1074LinearExpression operator-(const Variable lhs, const double rhs) {
1075 return LinearTerm(lhs, 1.0) - rhs;
1076}
1077
1078LinearExpression operator-(const double lhs, const Variable rhs) {
1079 return lhs - LinearTerm(rhs, 1.0);
1080}
1081
1083 return LinearTerm(lhs, 1.0) - LinearTerm(rhs, 1.0);
1084}
1085
1086LinearExpression operator-(const LinearTerm& lhs, const double rhs) {
1087 return LinearExpression({lhs}, -rhs);
1088}
1089
1090LinearExpression operator-(const double lhs, const LinearTerm& rhs) {
1091 return LinearExpression({-rhs}, lhs);
1092}
1093
1095 return lhs - LinearTerm(rhs, 1.0);
1096}
1097
1099 return LinearTerm(lhs, 1.0) - rhs;
1100}
1101
1103 return LinearExpression({lhs, -rhs}, 0);
1104}
1105
1107 lhs -= rhs;
1108 return lhs;
1109}
1110
1112 auto ret = -std::move(rhs);
1113 ret += lhs;
1114 return ret;
1115}
1116
1118 return std::move(lhs) - LinearTerm(rhs, 1.0);
1119}
1120
1122 return LinearTerm(lhs, 1.0) - std::move(rhs);
1123}
1124
1126 lhs -= rhs;
1127 return lhs;
1128}
1129
1131 auto ret = -std::move(rhs);
1132 ret += lhs;
1133 return ret;
1134}
1135
1137 lhs -= rhs;
1138 return lhs;
1139}
1140
1142 lhs *= rhs;
1143 return lhs;
1144}
1145
1147 rhs *= lhs;
1148 return rhs;
1149}
1150
1152 lhs /= rhs;
1153 return lhs;
1154}
1155
1157 terms_.Add(other.terms_);
1158 offset_ += other.offset_;
1159 return *this;
1160}
1161
1163 terms_[term.variable] += term.coefficient;
1164 return *this;
1165}
1166
1168 return *this += LinearTerm(variable, 1.0);
1169}
1170
1172 offset_ += value;
1173 return *this;
1174}
1175
1177 terms_.Subtract(other.terms_);
1178 offset_ -= other.offset_;
1179 return *this;
1180}
1181
1183 terms_[term.variable] -= term.coefficient;
1184 return *this;
1185}
1186
1188 return *this -= LinearTerm(variable, 1.0);
1189}
1190
1192 offset_ -= value;
1193 return *this;
1194}
1195
1197 offset_ *= value;
1198 for (auto term : terms_) {
1199 term.second *= value;
1200 }
1201 return *this;
1202}
1203
1205 offset_ /= value;
1206 for (auto term : terms_) {
1207 term.second /= value;
1208 }
1209 return *this;
1210}
1211
1212template <typename Iterable>
1213void LinearExpression::AddSum(const Iterable& items) {
1214 for (const auto& item : items) {
1215 *this += item;
1216 }
1217}
1218
1219template <typename Iterable>
1220LinearExpression Sum(const Iterable& items) {
1221 LinearExpression result;
1222 result.AddSum(items);
1223 return result;
1224}
1225
1226template <typename LeftIterable, typename RightIterable>
1227void LinearExpression::AddInnerProduct(const LeftIterable& left,
1228 const RightIterable& right) {
1229 using std::begin;
1230 using std::end;
1231 auto l = begin(left);
1232 auto r = begin(right);
1233 auto l_end = end(left);
1234 auto r_end = end(right);
1235 for (; l != l_end && r != r_end; ++l, ++r) {
1236 *this += (*l) * (*r);
1237 }
1238 CHECK(l == l_end)
1239 << "left had more elements than right, sizes should be equal";
1240 CHECK(r == r_end)
1241 << "right had more elements than left, sizes should be equal";
1242}
1243
1244template <typename LeftIterable, typename RightIterable>
1245LinearExpression InnerProduct(const LeftIterable& left,
1246 const RightIterable& right) {
1247 LinearExpression result;
1248 result.AddInnerProduct(left, right);
1249 return result;
1250}
1251
1252const VariableMap<double>& LinearExpression::terms() const { return terms_; }
1253
1254double LinearExpression::offset() const { return offset_; }
1255
1257 return terms_.storage();
1258}
1259
1260const absl::flat_hash_map<VariableId, double>& LinearExpression::raw_terms()
1261 const {
1262 return terms_.raw_map();
1263}
1264
1266// VariablesEquality
1268
1269namespace internal {
1270
1272 : lhs(std::move(lhs)), rhs(std::move(rhs)) {}
1273
1274inline VariablesEquality::operator bool() const {
1275 return lhs.typed_id() == rhs.typed_id() && lhs.storage() == rhs.storage();
1276}
1277
1278} // namespace internal
1279
1281 const Variable& rhs) {
1282 return internal::VariablesEquality(lhs, rhs);
1283}
1284
1285bool operator!=(const Variable& lhs, const Variable& rhs) {
1286 return !(lhs == rhs);
1287}
1288
1290// LowerBoundedLinearExpression
1291// UpperBoundedLinearExpression
1292// BoundedLinearExpression
1294
1296 LinearExpression expression, const double lower_bound)
1297 : expression(std::move(expression)), lower_bound(lower_bound) {}
1298
1300 LinearExpression expression, const double upper_bound)
1301 : expression(std::move(expression)), upper_bound(upper_bound) {}
1302
1304 const double lower_bound,
1305 const double upper_bound)
1306 : expression(std::move(expression)),
1309
1312 : expression({{eq.lhs, 1.0}, {eq.rhs, -1.0}}, 0.0),
1313 lower_bound(0.0),
1314 upper_bound(0.0) {}
1315
1317 LowerBoundedLinearExpression lb_expression)
1318 : expression(std::move(lb_expression.expression)),
1319 lower_bound(lb_expression.lower_bound),
1320 upper_bound(std::numeric_limits<double>::infinity()) {}
1321
1323 UpperBoundedLinearExpression ub_expression)
1324 : expression(std::move(ub_expression.expression)),
1325 lower_bound(-std::numeric_limits<double>::infinity()),
1326 upper_bound(ub_expression.upper_bound) {}
1327
1329 return lower_bound - expression.offset();
1330}
1331
1333 return upper_bound - expression.offset();
1334}
1335
1337 const double constant) {
1338 return LowerBoundedLinearExpression(std::move(expression), constant);
1339}
1340
1342 LinearExpression expression) {
1343 return LowerBoundedLinearExpression(std::move(expression), constant);
1344}
1345
1347 const double constant) {
1349}
1350
1352 const LinearTerm& term) {
1354}
1355
1357 const double constant) {
1358 return LinearTerm(variable, 1.0) >= constant;
1359}
1360
1362 const Variable variable) {
1363 return constant <= LinearTerm(variable, 1.0);
1364}
1365
1367 const double constant) {
1368 return UpperBoundedLinearExpression(std::move(expression), constant);
1369}
1370
1372 LinearExpression expression) {
1373 return UpperBoundedLinearExpression(std::move(expression), constant);
1374}
1375
1377 const double constant) {
1379}
1380
1382 const LinearTerm& term) {
1384}
1385
1387 const double constant) {
1388 return LinearTerm(variable, 1.0) <= constant;
1389}
1390
1392 const Variable variable) {
1393 return constant >= LinearTerm(variable, 1.0);
1394}
1395
1397 const double rhs) {
1398 return BoundedLinearExpression(std::move(lhs.expression),
1399 /*lower_bound=*/lhs.lower_bound,
1400 /*upper_bound=*/rhs);
1401}
1402
1405 return BoundedLinearExpression(std::move(rhs.expression),
1406 /*lower_bound=*/rhs.lower_bound,
1407 /*upper_bound=*/lhs);
1408}
1409
1411 const double rhs) {
1412 return BoundedLinearExpression(std::move(lhs.expression),
1413 /*lower_bound=*/rhs,
1414 /*upper_bound=*/lhs.upper_bound);
1415}
1416
1419 return BoundedLinearExpression(std::move(rhs.expression),
1420 /*lower_bound=*/lhs,
1421 /*upper_bound=*/rhs.upper_bound);
1422}
1423
1425 const LinearExpression& rhs) {
1426 lhs -= rhs;
1428 std::move(lhs), /*lower_bound=*/-std::numeric_limits<double>::infinity(),
1429 /*upper_bound=*/0.0);
1430}
1431
1433 const LinearExpression& rhs) {
1434 lhs -= rhs;
1436 std::move(lhs), /*lower_bound=*/0.0,
1437 /*upper_bound=*/std::numeric_limits<double>::infinity());
1438}
1439
1441 const LinearTerm& rhs) {
1442 lhs -= rhs;
1444 std::move(lhs), /*lower_bound=*/-std::numeric_limits<double>::infinity(),
1445 /*upper_bound=*/0.0);
1446}
1447
1449 const LinearTerm& rhs) {
1450 lhs -= rhs;
1452 std::move(lhs), /*lower_bound=*/0.0,
1453 /*upper_bound=*/std::numeric_limits<double>::infinity());
1454}
1455
1457 LinearExpression rhs) {
1458 rhs -= lhs;
1460 std::move(rhs), /*lower_bound=*/0.0,
1461 /*upper_bound=*/std::numeric_limits<double>::infinity());
1462}
1463
1465 LinearExpression rhs) {
1466 rhs -= lhs;
1468 std::move(rhs), /*lower_bound=*/-std::numeric_limits<double>::infinity(),
1469 /*upper_bound=*/0.0);
1470}
1471
1473 return std::move(lhs) <= LinearTerm(rhs, 1.0);
1474}
1475
1477 return std::move(lhs) >= LinearTerm(rhs, 1.0);
1478}
1479
1481 return LinearTerm(lhs, 1.0) <= std::move(rhs);
1482}
1483
1485 return LinearTerm(lhs, 1.0) >= std::move(rhs);
1486}
1487
1489 const LinearTerm& rhs) {
1491 LinearExpression({lhs, -rhs}, 0.0),
1492 /*lower_bound=*/-std::numeric_limits<double>::infinity(),
1493 /*upper_bound=*/0.0);
1494}
1495
1497 const LinearTerm& rhs) {
1499 LinearExpression({lhs, -rhs}, 0.0), /*lower_bound=*/0.0,
1500 /*upper_bound=*/std::numeric_limits<double>::infinity());
1501}
1502
1504 return lhs <= LinearTerm(rhs, 1.0);
1505}
1506
1508 return lhs >= LinearTerm(rhs, 1.0);
1509}
1510
1512 return LinearTerm(lhs, 1.0) <= rhs;
1513}
1514
1516 return LinearTerm(lhs, 1.0) >= rhs;
1517}
1518
1520 return LinearTerm(lhs, 1.0) <= LinearTerm(rhs, 1.0);
1521}
1522
1524 return LinearTerm(lhs, 1.0) >= LinearTerm(rhs, 1.0);
1525}
1526
1528 const LinearExpression& rhs) {
1529 lhs -= rhs;
1530 return BoundedLinearExpression(std::move(lhs), /*lower_bound=*/0.0,
1531 /*upper_bound=*/0.0);
1532}
1533
1535 const LinearTerm& rhs) {
1536 lhs -= rhs;
1537 return BoundedLinearExpression(std::move(lhs), /*lower_bound=*/0.0,
1538 /*upper_bound=*/0.0);
1539}
1540
1542 LinearExpression rhs) {
1543 rhs -= lhs;
1544 return BoundedLinearExpression(std::move(rhs), /*lower_bound=*/0.0,
1545 /*upper_bound=*/0.0);
1546}
1547
1549 return std::move(lhs) == LinearTerm(rhs, 1.0);
1550}
1551
1553 return LinearTerm(lhs, 1.0) == std::move(rhs);
1554}
1555
1557 lhs -= rhs;
1558 return BoundedLinearExpression(std::move(lhs), /*lower_bound=*/0.0,
1559 /*upper_bound=*/0.0);
1560}
1561
1563 rhs -= lhs;
1564 return BoundedLinearExpression(std::move(rhs), /*lower_bound=*/0.0,
1565 /*upper_bound=*/0.0);
1566}
1567
1569 const LinearTerm& rhs) {
1570 return BoundedLinearExpression(LinearExpression({lhs, -rhs}, 0.0),
1571 /*lower_bound=*/0.0,
1572 /*upper_bound=*/0.0);
1573}
1574
1576 return lhs == LinearTerm(rhs, 1.0);
1577}
1578
1580 return LinearTerm(lhs, 1.0) == rhs;
1581}
1582
1583BoundedLinearExpression operator==(const LinearTerm& lhs, const double rhs) {
1584 return BoundedLinearExpression(LinearExpression({lhs}, -rhs),
1585 /*lower_bound=*/0.0, /*upper_bound=*/0.0);
1586}
1587
1588BoundedLinearExpression operator==(const double lhs, const LinearTerm& rhs) {
1589 return BoundedLinearExpression(LinearExpression({rhs}, -lhs),
1590 /*lower_bound=*/0.0, /*upper_bound=*/0.0);
1591}
1592
1593BoundedLinearExpression operator==(const Variable lhs, const double rhs) {
1594 return LinearTerm(lhs, 1.0) == rhs;
1595}
1596
1597BoundedLinearExpression operator==(const double lhs, const Variable rhs) {
1598 return lhs == LinearTerm(rhs, 1.0);
1599}
1600
1602// QuadraticTermKey
1604
1606 const QuadraticProductId id)
1607 : storage_(storage), variable_ids_(id) {
1608 if (variable_ids_.first > variable_ids_.second) {
1609 using std::swap; // go/using-std-swap
1610 swap(variable_ids_.first, variable_ids_.second);
1611 }
1612}
1613
1615 const Variable second_variable)
1616 : QuadraticTermKey(first_variable.storage(), {first_variable.typed_id(),
1617 second_variable.typed_id()}) {
1618 CHECK_EQ(first_variable.storage(), second_variable.storage())
1620}
1621
1622QuadraticProductId QuadraticTermKey::typed_id() const { return variable_ids_; }
1623
1624const ModelStorage* QuadraticTermKey::storage() const { return storage_; }
1625
1626template <typename H>
1628 return H::combine(std::move(h), key.typed_id().first.value(),
1629 key.typed_id().second.value(), key.storage());
1630}
1631
1633 return lhs.storage() == rhs.storage() && lhs.typed_id() == rhs.typed_id();
1634}
1635
1637 return !(lhs == rhs);
1638}
1639
1641// QuadraticTerm (no arithmetic)
1643
1644QuadraticTerm::QuadraticTerm(Variable first_variable, Variable second_variable,
1645 const double coefficient)
1646 : first_variable_(std::move(first_variable)),
1647 second_variable_(std::move(second_variable)),
1648 coefficient_(coefficient) {
1649 CHECK_EQ(first_variable_.storage(), second_variable_.storage())
1651}
1652
1653double QuadraticTerm::coefficient() const { return coefficient_; }
1654Variable QuadraticTerm::first_variable() const { return first_variable_; }
1655Variable QuadraticTerm::second_variable() const { return second_variable_; }
1656
1658 return QuadraticTermKey(
1659 first_variable_.storage(),
1660 std::make_pair(first_variable_.typed_id(), second_variable_.typed_id()));
1661}
1662
1664// QuadraticExpression (no arithmetic)
1666
1668 const std::initializer_list<QuadraticTerm> quadratic_terms,
1669 const std::initializer_list<LinearTerm> linear_terms, const double offset)
1670 : offset_(offset) {
1671#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
1672 ++num_calls_initializer_list_constructor_;
1673#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
1674 for (const LinearTerm& term : linear_terms) {
1675 linear_terms_[term.variable] += term.coefficient;
1676 }
1677 for (const QuadraticTerm& term : quadratic_terms) {
1678 quadratic_terms_[term.GetKey()] += term.coefficient();
1679 }
1680 CheckModelsAgree();
1681}
1682
1684 : QuadraticExpression({}, {}, offset) {}
1685
1687 : QuadraticExpression({}, {LinearTerm(variable, 1.0)}, 0.0) {}
1688
1690 : QuadraticExpression({}, {term}, 0.0) {}
1691
1693 : linear_terms_(std::move(expr.terms_)),
1694 offset_(std::exchange(expr.offset_, 0.0)) {
1695#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
1696 ++num_calls_linear_expression_constructor_;
1697#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
1698}
1699
1701 : QuadraticExpression({term}, {}, 0.0) {}
1702
1703void QuadraticExpression::CheckModelsAgree() {
1704 const ModelStorage* const quadratic_model = quadratic_terms_.storage();
1705 const ModelStorage* const linear_model = linear_terms_.storage();
1706 if ((linear_model != nullptr) && (quadratic_model != nullptr) &&
1707 (quadratic_model != linear_model)) {
1709 }
1710}
1711
1713 if (quadratic_terms().storage()) {
1714 return quadratic_terms().storage();
1715 } else {
1716 return linear_terms().storage();
1717 }
1718}
1719
1720double QuadraticExpression::offset() const { return offset_; }
1721
1723 return linear_terms_;
1724}
1725
1727 return quadratic_terms_;
1728}
1729
1730const absl::flat_hash_map<VariableId, double>&
1732 return linear_terms_.raw_map();
1733}
1734
1735const absl::flat_hash_map<QuadraticProductId, double>&
1737 return quadratic_terms_.raw_map();
1738}
1739
1741// Arithmetic operators (non-member).
1742//
1743// These are NOT required to explicitly CHECK that the underlying model storages
1744// agree between linear_terms_ and quadratic_terms_ unless they are a friend of
1745// QuadraticExpression. As much as possible, defer to the assignment operators
1746// and the initializer list constructor for QuadraticExpression.
1748
1749// ----------------------------- Addition (+) ----------------------------------
1750
1751QuadraticExpression operator+(const double lhs, const QuadraticTerm& rhs) {
1752 return QuadraticExpression({rhs}, {}, lhs);
1753}
1754
1756 rhs += lhs;
1757 return rhs;
1758}
1759
1761 return QuadraticExpression({rhs}, {LinearTerm(lhs, 1.0)}, 0.0);
1762}
1763
1765 rhs += LinearTerm(lhs, 1.0);
1766 return rhs;
1767}
1768
1770 return QuadraticExpression({rhs}, {lhs}, 0.0);
1771}
1772
1774 rhs += lhs;
1775 return rhs;
1776}
1777
1779 QuadraticExpression expr(std::move(lhs));
1780 expr += rhs;
1781 return expr;
1782}
1783
1785 QuadraticExpression rhs) {
1786 rhs += lhs;
1787 return rhs;
1788}
1789
1790QuadraticExpression operator+(const QuadraticTerm& lhs, const double rhs) {
1791 return QuadraticExpression({lhs}, {}, rhs);
1792}
1793
1795 return QuadraticExpression({lhs}, {LinearTerm(rhs, 1.0)}, 0.0);
1796}
1797
1799 return QuadraticExpression({lhs}, {rhs}, 0.0);
1800}
1801
1803 QuadraticExpression expr(std::move(rhs));
1804 expr += lhs;
1805 return expr;
1806}
1807
1809 const QuadraticTerm& rhs) {
1810 return QuadraticExpression({lhs, rhs}, {}, 0.0);
1811}
1812
1814 QuadraticExpression rhs) {
1815 rhs += lhs;
1816 return rhs;
1817}
1818
1820 lhs += rhs;
1821 return lhs;
1822}
1823
1825 lhs += LinearTerm(rhs, 1.0);
1826 return lhs;
1827}
1828
1830 lhs += rhs;
1831 return lhs;
1832}
1833
1835 const LinearExpression& rhs) {
1836 lhs += rhs;
1837 return lhs;
1838}
1839
1841 const QuadraticTerm& rhs) {
1842 lhs += rhs;
1843 return lhs;
1844}
1845
1847 const QuadraticExpression& rhs) {
1848 lhs += rhs;
1849 return lhs;
1850}
1851
1852// --------------------------- Subtraction (-) ---------------------------------
1853
1854// NOTE: A friend of QuadraticTerm, but does not touch variables
1856 term.coefficient_ *= -1.0;
1857 return term;
1858}
1859
1860// NOTE: A friend of QuadraticExpression, but does not touch variables
1862 expr.offset_ = -expr.offset_;
1863 for (auto term : expr.linear_terms_) {
1864 term.second = -term.second;
1865 }
1866 for (auto term : expr.quadratic_terms_) {
1867 term.second = -term.second;
1868 }
1869 return expr;
1870}
1871
1872QuadraticExpression operator-(const double lhs, const QuadraticTerm& rhs) {
1873 return QuadraticExpression({-rhs}, {}, lhs);
1874}
1875
1877 auto expr = -std::move(rhs);
1878 expr += lhs;
1879 return expr;
1880}
1881
1883 return QuadraticExpression({-rhs}, {LinearTerm(lhs, 1.0)}, 0.0);
1884}
1885
1887 return LinearTerm(lhs, 1.0) - std::move(rhs);
1888}
1889
1891 return QuadraticExpression({-rhs}, {lhs}, 0.0);
1892}
1893
1895 auto expr = -std::move(rhs);
1896 expr += lhs;
1897 return expr;
1898}
1899
1901 QuadraticExpression expr(std::move(lhs));
1902 expr -= rhs;
1903 return expr;
1904}
1905
1907 QuadraticExpression rhs) {
1908 auto expr = -std::move(rhs);
1909 expr += lhs;
1910 return expr;
1911}
1912
1913QuadraticExpression operator-(const QuadraticTerm& lhs, const double rhs) {
1914 return QuadraticExpression({lhs}, {}, -rhs);
1915}
1916
1918 return QuadraticExpression({lhs}, {LinearTerm(rhs, -1.0)}, 0.0);
1919}
1920
1922 return QuadraticExpression({lhs}, {-rhs}, 0.0);
1923}
1924
1926 QuadraticExpression expr(-std::move(rhs));
1927 expr += lhs;
1928 return expr;
1929}
1930
1932 const QuadraticTerm& rhs) {
1933 return QuadraticExpression({lhs, -rhs}, {}, 0.0);
1934}
1935
1937 QuadraticExpression rhs) {
1938 rhs *= -1.0;
1939 rhs += lhs;
1940 return rhs;
1941}
1942
1944 lhs -= rhs;
1945 return lhs;
1946}
1947
1948// NOTE: Out-of-order for compilation purposes
1950 lhs -= rhs;
1951 return lhs;
1952}
1953
1955 lhs -= LinearTerm(rhs, 1.0);
1956 return lhs;
1957}
1958
1959// NOTE: operator-(QuadraticExpression, const LinearTerm) appears above
1960
1962 const LinearExpression& rhs) {
1963 lhs -= rhs;
1964 return lhs;
1965}
1966
1968 const QuadraticTerm& rhs) {
1969 lhs -= rhs;
1970 return lhs;
1971}
1972
1974 const QuadraticExpression& rhs) {
1975 lhs -= rhs;
1976 return lhs;
1977}
1978
1979// ---------------------------- Multiplication (*) -----------------------------
1980
1981// NOTE: A friend of QuadraticTerm, but does not touch variables
1982QuadraticTerm operator*(const double lhs, QuadraticTerm rhs) {
1983 rhs.coefficient_ *= lhs;
1984 return rhs;
1985}
1986
1988 rhs *= lhs;
1989 return rhs;
1990}
1991
1993 return QuadraticTerm(std::move(lhs), std::move(rhs), 1.0);
1994}
1995
1997 return QuadraticTerm(std::move(lhs), std::move(rhs.variable),
1998 rhs.coefficient);
1999}
2000
2003 for (const auto& [var, coeff] : rhs.terms()) {
2004 expr += QuadraticTerm(lhs, var, coeff);
2005 }
2006 if (rhs.offset() != 0) {
2007 expr += LinearTerm(std::move(lhs), rhs.offset());
2008 }
2009 return expr;
2010}
2011
2013 return QuadraticTerm(std::move(lhs.variable), std::move(rhs),
2014 lhs.coefficient);
2015}
2016
2018 return QuadraticTerm(std::move(lhs.variable), std::move(rhs.variable),
2019 lhs.coefficient * rhs.coefficient);
2020}
2021
2024 for (const auto& [var, coeff] : rhs.terms()) {
2025 expr += QuadraticTerm(lhs.variable, var, lhs.coefficient * coeff);
2026 }
2027 if (rhs.offset() != 0) {
2028 expr += LinearTerm(std::move(lhs.variable), lhs.coefficient * rhs.offset());
2029 }
2030 return expr;
2031}
2032
2035 for (const auto& [var, coeff] : lhs.terms()) {
2036 expr += QuadraticTerm(var, rhs, coeff);
2037 }
2038 if (lhs.offset() != 0) {
2039 expr += LinearTerm(std::move(rhs), lhs.offset());
2040 }
2041 return expr;
2042}
2043
2046 for (const auto& [var, coeff] : lhs.terms()) {
2047 expr += QuadraticTerm(var, rhs.variable, coeff * rhs.coefficient);
2048 }
2049 if (lhs.offset() != 0) {
2050 expr += LinearTerm(std::move(rhs.variable), lhs.offset() * rhs.coefficient);
2051 }
2052 return expr;
2053}
2054
2056 const LinearExpression& rhs) {
2057 QuadraticExpression expr = lhs.offset() * rhs.offset();
2058 if (rhs.offset() != 0) {
2059 for (const auto& [var, coeff] : lhs.terms()) {
2060 expr += LinearTerm(var, coeff * rhs.offset());
2061 }
2062 }
2063 if (lhs.offset() != 0) {
2064 for (const auto& [var, coeff] : rhs.terms()) {
2065 expr += LinearTerm(var, lhs.offset() * coeff);
2066 }
2067 }
2068 for (const auto& [lhs_var, lhs_coeff] : lhs.terms()) {
2069 for (const auto& [rhs_var, rhs_coeff] : rhs.terms()) {
2070 expr += QuadraticTerm(lhs_var, rhs_var, lhs_coeff * rhs_coeff);
2071 }
2072 }
2073 return expr;
2074}
2075
2076// NOTE: A friend of QuadraticTerm, but does not touch variables
2077QuadraticTerm operator*(QuadraticTerm lhs, const double rhs) {
2078 lhs.coefficient_ *= rhs;
2079 return lhs;
2080}
2081
2083 lhs *= rhs;
2084 return lhs;
2085}
2086
2087// ------------------------------- Division (/) --------------------------------
2088
2089// NOTE: A friend of QuadraticTerm, but does not touch variables
2090QuadraticTerm operator/(QuadraticTerm lhs, const double rhs) {
2091 lhs.coefficient_ /= rhs;
2092 return lhs;
2093}
2094
2096 lhs /= rhs;
2097 return lhs;
2098}
2099
2101// In-place arithmetic operators.
2102//
2103// These must guarantee that the underlying model storages for linear_terms_ and
2104// quadratic_terms_ agree upon exit of the function, using CheckModelsAgree(),
2105// the list initializer constructor for QuadraticExpression, or similar logic.
2107
2109 offset_ += value;
2110 // NOTE: Not touching terms, no need to check models
2111 return *this;
2112}
2113
2115 linear_terms_[variable] += 1;
2116 CheckModelsAgree();
2117 return *this;
2118}
2119
2121 linear_terms_[term.variable] += term.coefficient;
2122 CheckModelsAgree();
2123 return *this;
2124}
2125
2127 const LinearExpression& expr) {
2128 offset_ += expr.offset();
2129 linear_terms_.Add(expr.terms());
2130 CheckModelsAgree();
2131 return *this;
2132}
2133
2135 const QuadraticTerm& term) {
2136 quadratic_terms_[term.GetKey()] += term.coefficient();
2137 CheckModelsAgree();
2138 return *this;
2139}
2140
2142 const QuadraticExpression& expr) {
2143 offset_ += expr.offset();
2144 linear_terms_.Add(expr.linear_terms());
2145 quadratic_terms_.Add(expr.quadratic_terms());
2146 CheckModelsAgree();
2147 return *this;
2148}
2149
2151 offset_ -= value;
2152 // NOTE: Not touching terms, no need to check models
2153 return *this;
2154}
2155
2157 linear_terms_[variable] -= 1;
2158 CheckModelsAgree();
2159 return *this;
2160}
2161
2163 linear_terms_[term.variable] -= term.coefficient;
2164 CheckModelsAgree();
2165 return *this;
2166}
2167
2169 const LinearExpression& expr) {
2170 offset_ -= expr.offset();
2171 linear_terms_.Subtract(expr.terms());
2172 CheckModelsAgree();
2173 return *this;
2174}
2175
2177 const QuadraticTerm& term) {
2178 quadratic_terms_[term.GetKey()] -= term.coefficient();
2179 CheckModelsAgree();
2180 return *this;
2181}
2182
2184 const QuadraticExpression& expr) {
2185 offset_ -= expr.offset();
2186 linear_terms_.Subtract(expr.linear_terms());
2187 quadratic_terms_.Subtract(expr.quadratic_terms());
2188 CheckModelsAgree();
2189 return *this;
2190}
2191
2193 coefficient_ *= value;
2194 // NOTE: Not touching variables in term, just modifying coefficient, so no
2195 // need to check that models agree.
2196 return *this;
2197}
2198
2200 offset_ *= value;
2201 for (auto term : linear_terms_) {
2202 term.second *= value;
2203 }
2204 for (auto term : quadratic_terms_) {
2205 term.second *= value;
2206 }
2207 // NOTE: Not adding/removing/altering variables in expression, just modifying
2208 // coefficients, so no need to check that models agree.
2209 return *this;
2210}
2211
2213 coefficient_ /= value;
2214 // NOTE: Not touching variables in term, just modifying coefficient, so no
2215 // need to check that models agree.
2216 return *this;
2217}
2218
2220 offset_ /= value;
2221 for (auto term : linear_terms_) {
2222 term.second /= value;
2223 }
2224 for (auto term : quadratic_terms_) {
2225 term.second /= value;
2226 }
2227 // NOTE: Not adding/removing/altering variables in expression, just modifying
2228 // coefficients, so no need to check that models agree.
2229 return *this;
2230}
2231
2232} // namespace math_opt
2233} // namespace operations_research
2234
2235#endif // OR_TOOLS_MATH_OPT_CPP_VARIABLE_AND_EXPRESSIONS_H_
#define CHECK(condition)
Definition: base/logging.h:495
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:703
#define LOG(severity)
Definition: base/logging.h:420
#define DCHECK(condition)
Definition: base/logging.h:890
LinearExpression & operator+=(const LinearExpression &other)
double Evaluate(const VariableMap< double > &variable_values) const
double EvaluateWithDefaultZero(const VariableMap< double > &variable_values) const
friend LinearExpression operator-(LinearExpression expr)
LinearExpression & operator-=(const LinearExpression &other)
void AddInnerProduct(const LeftIterable &left, const RightIterable &right)
const absl::flat_hash_map< VariableId, double > & raw_terms() const
friend std::ostream & operator<<(std::ostream &ostr, const LinearExpression &expression)
const std::string & variable_name(VariableId id) const
double variable_lower_bound(VariableId id) const
bool is_variable_integer(VariableId id) const
double variable_upper_bound(VariableId id) const
double Evaluate(const VariableMap< double > &variable_values) const
friend std::ostream & operator<<(std::ostream &ostr, const QuadraticExpression &expr)
double EvaluateWithDefaultZero(const VariableMap< double > &variable_values) const
const QuadraticTermMap< double > & quadratic_terms() const
const absl::flat_hash_map< QuadraticProductId, double > & raw_quadratic_terms() const
const absl::flat_hash_map< VariableId, double > & raw_linear_terms() const
friend QuadraticExpression operator-(QuadraticExpression expr)
friend QuadraticTerm operator*(double lhs, QuadraticTerm rhs)
friend QuadraticTerm operator-(QuadraticTerm term)
friend QuadraticTerm operator/(QuadraticTerm lhs, double rhs)
QuadraticTermKey(const ModelStorage *storage, QuadraticProductId id)
friend H AbslHashValue(H h, const QuadraticTermKey &key)
friend std::ostream & operator<<(std::ostream &ostr, const Variable &variable)
friend H AbslHashValue(H h, const Variable &variable)
Variable(const ModelStorage *storage, VariableId id)
const std::string name
int64_t value
IntVar * var
Definition: expr_array.cc:1874
double upper_bound
double lower_bound
const int64_t offset_
Definition: interval.cc:2108
const int FATAL
Definition: log_severity.h:32
constexpr absl::string_view kObjectsFromOtherModelStorage
Definition: key_types.h:56
LowerBoundedLinearExpression operator>=(LinearExpression expression, double constant)
std::pair< VariableId, VariableId > QuadraticProductId
LinearExpression Sum(const Iterable &items)
std::ostream & operator<<(std::ostream &out, const E value)
Definition: enums.h:231
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
Definition: id_map.h:262
LinearExpression operator-(LinearExpression expr)
LinearExpression InnerProduct(const LeftIterable &left, const RightIterable &right)
LowerBoundedLinearExpression operator<=(double constant, LinearExpression expression)
bool operator==(const LinearConstraint &lhs, const LinearConstraint &rhs)
bool operator!=(const LinearConstraint &lhs, const LinearConstraint &rhs)
H AbslHashValue(H h, const LinearConstraint &linear_constraint)
LinearExpression operator+(Variable lhs, double rhs)
LinearTerm operator*(double coefficient, LinearTerm term)
LinearTerm operator/(LinearTerm term, double coefficient)
Collection of objects used to extend the Constraint Solver library.
STL namespace.
int64_t coefficient
std::optional< int64_t > end
BoundedLinearExpression(LinearExpression expression, double lower_bound, double upper_bound)
LinearTerm(Variable variable, double coefficient)
LowerBoundedLinearExpression(LinearExpression expression, double lower_bound)
UpperBoundedLinearExpression(LinearExpression expression, double upper_bound)
const double coeff
const double constant