ortools: backport from main branch
This commit is contained in:
@@ -240,6 +240,7 @@ cc_test(
|
|||||||
"//ortools/base:gmock_main",
|
"//ortools/base:gmock_main",
|
||||||
"//ortools/util:time_limit",
|
"//ortools/util:time_limit",
|
||||||
"@abseil-cpp//absl/base:core_headers",
|
"@abseil-cpp//absl/base:core_headers",
|
||||||
|
"@abseil-cpp//absl/types:span",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|||||||
@@ -11,18 +11,6 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
//
|
|
||||||
// IMPORTANT NOTE: we advise using the code in
|
|
||||||
// graph/linear_assignment.h whose complexity is
|
|
||||||
// usually much smaller.
|
|
||||||
// TODO(user): base this code on LinearSumAssignment.
|
|
||||||
//
|
|
||||||
// For each of the four functions declared in this file, in case the input
|
|
||||||
// parameter 'cost' contains NaN, the function will return without invoking the
|
|
||||||
// Hungarian algorithm, and the output parameters 'direct_assignment' and
|
|
||||||
// 'reverse_assignment' will be left unchanged.
|
|
||||||
//
|
|
||||||
|
|
||||||
// An O(n^4) implementation of the Kuhn-Munkres algorithm (a.k.a. the
|
// An O(n^4) implementation of the Kuhn-Munkres algorithm (a.k.a. the
|
||||||
// Hungarian algorithm) for solving the assignment problem.
|
// Hungarian algorithm) for solving the assignment problem.
|
||||||
// The assignment problem takes a set of agents, a set of tasks and a
|
// The assignment problem takes a set of agents, a set of tasks and a
|
||||||
@@ -30,10 +18,6 @@
|
|||||||
// an optimal (i.e., least cost) assignment of agents to tasks.
|
// an optimal (i.e., least cost) assignment of agents to tasks.
|
||||||
// The code also enables computing a maximum assignment by changing the
|
// The code also enables computing a maximum assignment by changing the
|
||||||
// input matrix.
|
// input matrix.
|
||||||
//
|
|
||||||
// This code is based on (read: translated from) the Java version
|
|
||||||
// (read: translated from) the Python version at
|
|
||||||
// http://www.clapper.org/software/python/munkres/.
|
|
||||||
|
|
||||||
#ifndef OR_TOOLS_ALGORITHMS_HUNGARIAN_H_
|
#ifndef OR_TOOLS_ALGORITHMS_HUNGARIAN_H_
|
||||||
#define OR_TOOLS_ALGORITHMS_HUNGARIAN_H_
|
#define OR_TOOLS_ALGORITHMS_HUNGARIAN_H_
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "absl/base/macros.h"
|
#include "absl/base/macros.h"
|
||||||
|
#include "absl/types/span.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "ortools/util/time_limit.h"
|
#include "ortools/util/time_limit.h"
|
||||||
|
|
||||||
@@ -26,8 +27,8 @@ namespace {
|
|||||||
|
|
||||||
const int kInvalidSolution = -1;
|
const int kInvalidSolution = -1;
|
||||||
|
|
||||||
bool IsSolutionValid(const std::vector<int64_t>& profits,
|
bool IsSolutionValid(absl::Span<const int64_t> profits,
|
||||||
const std::vector<std::vector<int64_t> >& weights,
|
absl::Span<const std::vector<int64_t>> weights,
|
||||||
const std::vector<int64_t>& capacities,
|
const std::vector<int64_t>& capacities,
|
||||||
const std::vector<bool>& best_solution,
|
const std::vector<bool>& best_solution,
|
||||||
int64_t optimal_profit) {
|
int64_t optimal_profit) {
|
||||||
@@ -59,7 +60,7 @@ int64_t SolveKnapsackProblemUsingSpecificSolverAndReduction(
|
|||||||
std::vector<int64_t> profits(profit_array, profit_array + number_of_items);
|
std::vector<int64_t> profits(profit_array, profit_array + number_of_items);
|
||||||
std::vector<int64_t> capacities(capacity_array,
|
std::vector<int64_t> capacities(capacity_array,
|
||||||
capacity_array + number_of_dimensions);
|
capacity_array + number_of_dimensions);
|
||||||
std::vector<std::vector<int64_t> > weights;
|
std::vector<std::vector<int64_t>> weights;
|
||||||
for (int i = 0; i < number_of_dimensions; ++i) {
|
for (int i = 0; i < number_of_dimensions; ++i) {
|
||||||
const int64_t* one_dimension = weight_array + number_of_items * i;
|
const int64_t* one_dimension = weight_array + number_of_items * i;
|
||||||
std::vector<int64_t> weights_one_dimension(one_dimension,
|
std::vector<int64_t> weights_one_dimension(one_dimension,
|
||||||
@@ -484,7 +485,7 @@ TEST(KnapsackSolverTest, SolveTwoDimensionsSettingPrimaryPropagator) {
|
|||||||
std::vector<int64_t> profits(kProfitArray, kProfitArray + kArraySize);
|
std::vector<int64_t> profits(kProfitArray, kProfitArray + kArraySize);
|
||||||
std::vector<int64_t> capacities(kCapacityArray,
|
std::vector<int64_t> capacities(kCapacityArray,
|
||||||
kCapacityArray + kNumberOfDimensions);
|
kCapacityArray + kNumberOfDimensions);
|
||||||
std::vector<std::vector<int64_t> > weights;
|
std::vector<std::vector<int64_t>> weights;
|
||||||
for (int i = 0; i < kNumberOfDimensions; ++i) {
|
for (int i = 0; i < kNumberOfDimensions; ++i) {
|
||||||
const int64_t* one_dimension = kWeightArray + kArraySize * i;
|
const int64_t* one_dimension = kWeightArray + kArraySize * i;
|
||||||
std::vector<int64_t> weights_one_dimension(one_dimension,
|
std::vector<int64_t> weights_one_dimension(one_dimension,
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
#include "google/protobuf/descriptor.pb.h"
|
#include "google/protobuf/descriptor.pb.h"
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ class OptimizerSelector;
|
|||||||
// - LP_FIRST_SOLUTION
|
// - LP_FIRST_SOLUTION
|
||||||
// - OBJECTIVE_FIRST_SOLUTION
|
// - OBJECTIVE_FIRST_SOLUTION
|
||||||
// - USER_GUIDED_FIRST_SOLUTION
|
// - USER_GUIDED_FIRST_SOLUTION
|
||||||
// - FEASIBILITY_PUMP_FIRST_SOLUTION
|
|
||||||
// - RANDOM_CONSTRAINT_LNS_GUIDED_BY_LP
|
// - RANDOM_CONSTRAINT_LNS_GUIDED_BY_LP
|
||||||
// - RANDOM_VARIABLE_LNS_GUIDED_BY_LP
|
// - RANDOM_VARIABLE_LNS_GUIDED_BY_LP
|
||||||
// - RELATION_GRAPH_LNS
|
// - RELATION_GRAPH_LNS
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
//
|
|
||||||
// This file contains the presolving code for a LinearProgram.
|
// This file contains the presolving code for a LinearProgram.
|
||||||
//
|
//
|
||||||
// A classical reference is:
|
// A classical reference is:
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|||||||
@@ -5,76 +5,64 @@ flow problems.
|
|||||||
|
|
||||||
It contains in particular:
|
It contains in particular:
|
||||||
|
|
||||||
* well-tuned algorithms (for example, shortest paths and
|
* well-tuned algorithms (for example, shortest paths and
|
||||||
[Hamiltonian paths](https://en.wikipedia.org/wiki/Hamiltonian_path)).
|
[Hamiltonian paths](https://en.wikipedia.org/wiki/Hamiltonian_path)).
|
||||||
* hard-to-find algorithms (Hamiltonian paths, push-relabel flow algorithms).
|
* hard-to-find algorithms (Hamiltonian paths, push-relabel flow algorithms).
|
||||||
* other, more common algorithms, that are useful to use with graphs from
|
* other, more common algorithms, that are useful to use with graphs from
|
||||||
`util/graph`.
|
`util/graph`.
|
||||||
|
|
||||||
Generic algorithms for shortest paths:
|
Generic algorithms for shortest paths:
|
||||||
|
|
||||||
* [`bounded_dijkstra.h`][bounded_dijkstra_h]: entry point for shortest paths.
|
* [`bounded_dijkstra.h`][bounded_dijkstra_h]: entry point for shortest paths.
|
||||||
This is the preferred implementation for most needs.
|
This is the preferred implementation for most needs.
|
||||||
|
* [`bidirectional_dijkstra.h`][bidirectional_dijkstra_h]: for large graphs,
|
||||||
* [`bidirectional_dijkstra.h`][bidirectional_dijkstra_h]: for large graphs,
|
this implementation might be faster than `bounded_dijkstra.h`.
|
||||||
this implementation might be faster than `bounded_dijkstra.h`.
|
* [`shortest_paths.h`][shortest_paths_h]: shortest paths that are computed in
|
||||||
|
parallel (only if there are several sources). Includes
|
||||||
* [`shortest_paths.h`][shortest_paths_h]: shortest paths that are computed in
|
[Dijkstra](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm) and
|
||||||
parallel (only if there are several sources). Includes
|
[Bellman-Ford](https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm)
|
||||||
[Dijkstra](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm) and
|
algorithms. *Although its name is very generic, only use this implementation
|
||||||
[Bellman-Ford](https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm)
|
if parallelism makes sense.*
|
||||||
algorithms. *Although its name is very generic, only use this implementation
|
|
||||||
if parallelism makes sense.*
|
|
||||||
|
|
||||||
Specific algorithms for paths:
|
Specific algorithms for paths:
|
||||||
|
|
||||||
* [`dag_shortest_path.h`][dag_shortest_path_h]: shortest paths on directed
|
* [`dag_shortest_path.h`][dag_shortest_path_h]: shortest paths on directed
|
||||||
acyclic graphs. If you have such a graph, this implementation is likely to
|
acyclic graphs. If you have such a graph, this implementation is likely to be
|
||||||
be the fastest. Unlike most implementations, these algorithms have two
|
the fastest. Unlike most implementations, these algorithms have two interfaces
|
||||||
interfaces: a "simple" one (list of edges and weights) and a standard one
|
: a "simple" one (list of edges and weights) and a standard one (taking as
|
||||||
(taking as input a graph data structure from
|
input a graph data structure from [`//ortools/graph/graph.h`][graph_h]).
|
||||||
[`//ortools/graph/graph.h`][graph_h]).
|
* [`dag_constrained_shortest_path.`][dag_constrained_shortest_path_h]: shortest
|
||||||
|
paths on directed acyclic graphs with resource constraints.
|
||||||
* [`dag_constrained_shortest_path.`][dag_constrained_shortest_path_h]:
|
* [`hamiltonian_path.h`][hamiltonian_path_h]: entry point for computing minimum
|
||||||
shortest paths on directed acyclic graphs with resource constraints.
|
[Hamiltonian paths](https://en.wikipedia.org/wiki/Hamiltonian_path) and cycles
|
||||||
|
on directed graphs with costs on arcs, using a dynamic-programming algorithm.
|
||||||
* [`hamiltonian_path.h`][hamiltonian_path_h]: entry point for computing
|
* [`eulerian_path.h`][eulerian_path_h]: entry point for computing minimum
|
||||||
minimum [Hamiltonian paths](https://en.wikipedia.org/wiki/Hamiltonian_path)
|
[Eulerian paths](https://en.wikipedia.org/wiki/Eulerian_path) and cycles on
|
||||||
and cycles on directed graphs with costs on arcs, using a
|
undirected graphs.
|
||||||
dynamic-programming algorithm.
|
|
||||||
|
|
||||||
* [`eulerian_path.h`][eulerian_path_h]: entry point for computing minimum
|
|
||||||
[Eulerian paths](https://en.wikipedia.org/wiki/Eulerian_path) and cycles on
|
|
||||||
undirected graphs.
|
|
||||||
|
|
||||||
Graph decompositions:
|
Graph decompositions:
|
||||||
|
|
||||||
* [`connected_components.h`][connected_components_h]: entry point for computing
|
* [`connected_components.h`][connected_components_h]: entry point for computing
|
||||||
connected components in an undirected graph. (It does not need an explicit
|
connected components in an undirected graph. (It does not need an explicit
|
||||||
graph class.)
|
graph class.)
|
||||||
|
|
||||||
* [`strongly_connected_components.h`][strongly_connected_components_h]: entry
|
* [`strongly_connected_components.h`][strongly_connected_components_h]: entry
|
||||||
point for computing the strongly connected components of a directed graph.
|
point for computing the strongly connected components of a directed graph.
|
||||||
|
* [`cliques.h`][cliques_h]: entry point for computing maximum cliques and clique
|
||||||
* [`cliques.h`][cliques_h]: entry point for computing maximum cliques and
|
covers in a directed graph, based on the Bron-Kerbosch algorithm.(It does not
|
||||||
clique covers in a directed graph, based on the Bron-Kerbosch algorithm.(It
|
need an explicit graph class.)
|
||||||
does not need an explicit graph class.)
|
|
||||||
|
|
||||||
Flow algorithms:
|
Flow algorithms:
|
||||||
|
|
||||||
* [`linear_assignment.h`][linear_assignment_h]: entry point for solving linear
|
* [`linear_assignment.h`][linear_assignment_h]: entry point for solving linear
|
||||||
sum assignment problems (classical assignment problems where the total cost
|
sum assignment problems (classical assignment problems where the total cost is
|
||||||
is the sum of the costs of each arc used) on directed graphs with arc costs,
|
the sum of the costs of each arc used) on directed graphs with arc costs,
|
||||||
based on the Goldberg-Kennedy push-relabel algorithm.
|
based on the Goldberg-Kennedy push-relabel algorithm.
|
||||||
|
* [`max_flow.h`][max_flow_h]: entry point for computing maximum flows on
|
||||||
* [`max_flow.h`][max_flow_h]: entry point for computing maximum flows on
|
directed graphs with arc capacities, based on the Goldberg-Tarjan push-relabel
|
||||||
directed graphs with arc capacities, based on the Goldberg-Tarjan
|
algorithm.
|
||||||
push-relabel algorithm.
|
* [`min_cost_flow.h`][min_cost_flow_h]: entry point for computing minimum-cost
|
||||||
|
flows on directed graphs with arc capacities, arc costs, and supplies/demands
|
||||||
* [`min_cost_flow.h`][min_cost_flow_h]: entry point for computing minimum-cost
|
at nodes, based on the Goldberg-Tarjan push-relabel algorithm.
|
||||||
flows on directed graphs with arc capacities, arc costs, and
|
|
||||||
supplies/demands at nodes, based on the Goldberg-Tarjan push-relabel
|
|
||||||
algorithm.
|
|
||||||
|
|
||||||
## Class design
|
## Class design
|
||||||
|
|
||||||
@@ -201,21 +189,18 @@ node.
|
|||||||
|
|
||||||
## Wrappers
|
## Wrappers
|
||||||
|
|
||||||
* [`python`](python): the SWIG code that makes the wrapper available in Python
|
* [`python`](python): This directory contains the `pybind11` bindings to make
|
||||||
and its unit tests.
|
these C++ libraries available in Python.
|
||||||
|
* [`java`](java): the SWIG code that makes the wrapper available in Java and its
|
||||||
* [`java`](java): the SWIG code that makes the wrapper available in Java and
|
unit tests.
|
||||||
its unit tests.
|
* [`csharp`](csharp): the SWIG code that makes the wrapper available in C# and
|
||||||
|
its unit tests.
|
||||||
* [`csharp`](csharp): the SWIG code that makes the wrapper available in C# and
|
|
||||||
its unit tests.
|
|
||||||
|
|
||||||
## Samples
|
## Samples
|
||||||
|
|
||||||
You can find some canonical examples in [`samples`][samples].
|
You can find some canonical examples in [`samples`][samples].
|
||||||
|
|
||||||
<!-- Links used throughout the document. -->
|
<!-- Links used throughout the document. -->
|
||||||
|
|
||||||
[graph_h]: ../graph/graph.h
|
[graph_h]: ../graph/graph.h
|
||||||
[bounded_dijkstra_h]: ../graph/bounded_dijkstra.h
|
[bounded_dijkstra_h]: ../graph/bounded_dijkstra.h
|
||||||
[bidirectional_dijkstra_h]: ../graph/bidirectional_dijkstra.h
|
[bidirectional_dijkstra_h]: ../graph/bidirectional_dijkstra.h
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
//
|
|
||||||
// Maximal clique algorithms, based on the Bron-Kerbosch algorithm.
|
// Maximal clique algorithms, based on the Bron-Kerbosch algorithm.
|
||||||
// See http://en.wikipedia.org/wiki/Bron-Kerbosch_algorithm
|
// See http://en.wikipedia.org/wiki/Bron-Kerbosch_algorithm
|
||||||
// and
|
// and
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
//
|
|
||||||
// An implementation of a cost-scaling push-relabel algorithm for the
|
// An implementation of a cost-scaling push-relabel algorithm for the
|
||||||
// assignment problem (minimum-cost perfect bipartite matching), from
|
// assignment problem (minimum-cost perfect bipartite matching), from
|
||||||
// the paper of Goldberg and Kennedy (1995).
|
// the paper of Goldberg and Kennedy (1995).
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
//
|
|
||||||
// This code loads flow-graph models (as Dimacs file or binary FlowModel proto)
|
// This code loads flow-graph models (as Dimacs file or binary FlowModel proto)
|
||||||
// and solves them with the OR-tools flow algorithms.
|
// and solves them with the OR-tools flow algorithms.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -254,17 +254,6 @@ cc_library(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
#cc_library(
|
|
||||||
# name = "lp_constraint_classifier",
|
|
||||||
# srcs = ["lp_constraint_classifier.cc"],
|
|
||||||
# hdrs = ["lp_constraint_classifier.h"],
|
|
||||||
# copts = SAFE_FP_CODE,
|
|
||||||
# deps = [
|
|
||||||
# ":lp_data",
|
|
||||||
# "//ortools/util:fp_utils",
|
|
||||||
# ],
|
|
||||||
#)
|
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "lp_print_utils",
|
name = "lp_print_utils",
|
||||||
srcs = ["lp_print_utils.cc"],
|
srcs = ["lp_print_utils.cc"],
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
# LP Data
|
||||||
|
|
||||||
|
This directory contains a rich collection of C++ libraries for handling Linear
|
||||||
|
Programming (LP) data structures.
|
||||||
|
|
||||||
|
It provides core components for representing, manipulating, and solving linear
|
||||||
|
programs, with a focus on efficient handling of sparse data and various utility
|
||||||
|
functions for pre-processing and analysis.
|
||||||
|
|
||||||
|
## Core Data Structures
|
||||||
|
|
||||||
|
This set of libraries provides the fundamental building blocks for representing
|
||||||
|
and working with linear programming problems.
|
||||||
|
|
||||||
|
* [`lp_types.h`][lp_types_h]: Defines common types and constants used throughout
|
||||||
|
the linear programming solver.
|
||||||
|
* [`lp_data.h`][lp_data_h]: Provides the main `LinearProgram` class for storing
|
||||||
|
the complete data of a linear program, including the objective function,
|
||||||
|
constraint matrix, and variable bounds.
|
||||||
|
* [`lp_utils.h`][lp_utils_h]: Contains basic utility functions for operations on
|
||||||
|
fractional numbers and row/column vectors.
|
||||||
|
|
||||||
|
## Sparse Data Representation
|
||||||
|
|
||||||
|
Given that large-scale linear programs are often sparse, this directory offers a
|
||||||
|
suite of libraries for efficient sparse data handling.
|
||||||
|
|
||||||
|
* [`sparse.h`][sparse_h]: Implements data structures for sparse matrices, based
|
||||||
|
on well-established references in the field of direct methods for sparse
|
||||||
|
matrices.
|
||||||
|
* [`sparse_vector.h`][sparse_vector_h]: Provides classes to represent sparse
|
||||||
|
vectors efficiently.
|
||||||
|
* [`sparse_column.h`][sparse_column_h] & [`sparse_row.h`][sparse_row_h]:
|
||||||
|
Specializations of sparse vectors for column-oriented and row-oriented matrix
|
||||||
|
storage schemes.
|
||||||
|
* [`scattered_vector.h`][scattered_vector_h]: Implements vectors that offer a
|
||||||
|
sparse interface to what is internally a dense storage, which can be useful
|
||||||
|
for certain computations.
|
||||||
|
|
||||||
|
## LP Solvers and Utilities
|
||||||
|
|
||||||
|
A collection of tools for preprocessing, analyzing, and manipulating linear
|
||||||
|
programs.
|
||||||
|
|
||||||
|
* [`matrix_scaler.h`][matrix_scaler_h]: Provides the `SparseMatrixScaler` class,
|
||||||
|
which scales a `SparseMatrix` to improve numerical stability during the
|
||||||
|
solving process.
|
||||||
|
* [`lp_decomposer.h`][lp_decomposer_h]: Implements a tool to decompose a large
|
||||||
|
`LinearProgram` into several smaller, independent subproblems by identifying
|
||||||
|
disconnected components in the constraint matrix.
|
||||||
|
* [`permutation.h`][permutation_h]: Contains utilities for handling row and
|
||||||
|
column permutations on LP data structures.
|
||||||
|
|
||||||
|
## Parsers and I/O Utilities
|
||||||
|
|
||||||
|
This group of libraries handles reading and writing LP data in various formats.
|
||||||
|
|
||||||
|
* [`lp_parser.h`][lp_parser_h]: A simple parser for creating a linear program
|
||||||
|
from a string representation.
|
||||||
|
* [`mps_reader.h`][mps_reader_h]: A reader for the industry-standard MPS file
|
||||||
|
format for mathematical programming problems.
|
||||||
|
* [`sol_reader.h`][sol_reader_h]: A reader for .sol files, which are used to
|
||||||
|
specify solution values for a given model.
|
||||||
|
* [`proto_utils.h`][proto_utils_h]: Provides utilities to convert
|
||||||
|
`LinearProgram` objects to and from the MPModelProto protobuf format.
|
||||||
|
* [`lp_print_utils.h`][lp_print_utils_h]: Contains utilities to display linear
|
||||||
|
expressions in a human-readable way, including rational approximations.
|
||||||
|
|
||||||
|
<!-- Links used throughout the document. -->
|
||||||
|
|
||||||
|
[lp_types_h]: ../lp_data/lp_types.h
|
||||||
|
[lp_data_h]: ../lp_data/lp_data.h
|
||||||
|
[lp_utils_h]: ../lp_data/lp_utils.h
|
||||||
|
[sparse_h]: ../lp_data/sparse.h
|
||||||
|
[sparse_vector_h]: ../lp_data/sparse_vector.h
|
||||||
|
[sparse_column_h]: ../lp_data/sparse_column.h
|
||||||
|
[sparse_row_h]: ../lp_data/sparse_row.h
|
||||||
|
[scattered_vector_h]: ../lp_data/scattered_vector.h
|
||||||
|
[matrix_scaler_h]: ../lp_data/matrix_scaler.h
|
||||||
|
[lp_decomposer_h]: ../lp_data/lp_decomposer.h
|
||||||
|
[permutation_h]: ../lp_data/permutation.h
|
||||||
|
[lp_parser_h]: ../lp_data/lp_parser.h
|
||||||
|
[mps_reader_h]: ../lp_data/mps_reader.h
|
||||||
|
[sol_reader_h]: ../lp_data/sol_reader.h
|
||||||
|
[proto_utils_h]: ../lp_data/proto_utils.h
|
||||||
|
[lp_print_utils_h]: ../lp_data/lp_print_utils.h
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
//
|
|
||||||
// Storage classes for Linear Programs.
|
// Storage classes for Linear Programs.
|
||||||
//
|
//
|
||||||
// LinearProgram stores the complete data for a Linear Program:
|
// LinearProgram stores the complete data for a Linear Program:
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
//
|
|
||||||
// The following are very good references for terminology, data structures,
|
// The following are very good references for terminology, data structures,
|
||||||
// and algorithms:
|
// and algorithms:
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ cc_library(
|
|||||||
"//ortools/lp_data:proto_utils",
|
"//ortools/lp_data:proto_utils",
|
||||||
"//ortools/util:logging",
|
"//ortools/util:logging",
|
||||||
"@abseil-cpp//absl/algorithm:container",
|
"@abseil-cpp//absl/algorithm:container",
|
||||||
|
"@abseil-cpp//absl/base:nullability",
|
||||||
"@abseil-cpp//absl/status",
|
"@abseil-cpp//absl/status",
|
||||||
"@abseil-cpp//absl/status:statusor",
|
"@abseil-cpp//absl/status:statusor",
|
||||||
"@abseil-cpp//absl/strings",
|
"@abseil-cpp//absl/strings",
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
#include "Eigen/Core"
|
#include "Eigen/Core"
|
||||||
#include "Eigen/SparseCore"
|
#include "Eigen/SparseCore"
|
||||||
#include "absl/algorithm/container.h"
|
#include "absl/algorithm/container.h"
|
||||||
|
#include "absl/base/nullability.h"
|
||||||
#include "absl/log/check.h"
|
#include "absl/log/check.h"
|
||||||
#include "absl/log/log.h"
|
#include "absl/log/log.h"
|
||||||
#include "absl/status/status.h"
|
#include "absl/status/status.h"
|
||||||
@@ -619,7 +620,8 @@ class Solver {
|
|||||||
|
|
||||||
NextSolutionAndDelta ComputeNextDualSolution(
|
NextSolutionAndDelta ComputeNextDualSolution(
|
||||||
double dual_step_size, double extrapolation_factor,
|
double dual_step_size, double extrapolation_factor,
|
||||||
const NextSolutionAndDelta& next_primal) const;
|
const NextSolutionAndDelta& next_primal_solution,
|
||||||
|
const VectorXd* absl_nullable next_primal_product = nullptr) const;
|
||||||
|
|
||||||
std::pair<double, double> ComputeMovementTerms(
|
std::pair<double, double> ComputeMovementTerms(
|
||||||
const VectorXd& delta_primal, const VectorXd& delta_dual) const;
|
const VectorXd& delta_primal, const VectorXd& delta_dual) const;
|
||||||
@@ -630,6 +632,10 @@ class Solver {
|
|||||||
double ComputeNonlinearity(const VectorXd& delta_primal,
|
double ComputeNonlinearity(const VectorXd& delta_primal,
|
||||||
const VectorXd& next_dual_product) const;
|
const VectorXd& next_dual_product) const;
|
||||||
|
|
||||||
|
// Sets current_primal_product_ and current_dual_product_ based on
|
||||||
|
// current_primal_solution_ and current_dual_solution_ respectively.
|
||||||
|
void SetCurrentPrimalAndDualProducts();
|
||||||
|
|
||||||
// Creates all the simple-to-compute statistics in stats.
|
// Creates all the simple-to-compute statistics in stats.
|
||||||
IterationStats CreateSimpleIterationStats(RestartChoice restart_used) const;
|
IterationStats CreateSimpleIterationStats(RestartChoice restart_used) const;
|
||||||
|
|
||||||
@@ -734,6 +740,9 @@ class Solver {
|
|||||||
WallTimer timer_;
|
WallTimer timer_;
|
||||||
int iterations_completed_;
|
int iterations_completed_;
|
||||||
int num_rejected_steps_;
|
int num_rejected_steps_;
|
||||||
|
// A cache of `constraint_matrix * current_primal_solution_`.
|
||||||
|
// Malitsky-Pock linesearch only.
|
||||||
|
std::optional<VectorXd> current_primal_product_;
|
||||||
// A cache of `constraint_matrix.transpose() * current_dual_solution_`.
|
// A cache of `constraint_matrix.transpose() * current_dual_solution_`.
|
||||||
VectorXd current_dual_product_;
|
VectorXd current_dual_product_;
|
||||||
// The primal point at which the algorithm was last restarted from, or
|
// The primal point at which the algorithm was last restarted from, or
|
||||||
@@ -1870,31 +1879,41 @@ Solver::NextSolutionAndDelta Solver::ComputeNextPrimalSolution(
|
|||||||
|
|
||||||
Solver::NextSolutionAndDelta Solver::ComputeNextDualSolution(
|
Solver::NextSolutionAndDelta Solver::ComputeNextDualSolution(
|
||||||
double dual_step_size, double extrapolation_factor,
|
double dual_step_size, double extrapolation_factor,
|
||||||
const NextSolutionAndDelta& next_primal_solution) const {
|
const NextSolutionAndDelta& next_primal_solution,
|
||||||
|
const VectorXd* absl_nullable next_primal_product) const {
|
||||||
const int64_t dual_size = ShardedWorkingQp().DualSize();
|
const int64_t dual_size = ShardedWorkingQp().DualSize();
|
||||||
NextSolutionAndDelta result = {
|
NextSolutionAndDelta result = {
|
||||||
.value = VectorXd(dual_size),
|
.value = VectorXd(dual_size),
|
||||||
.delta = VectorXd(dual_size),
|
.delta = VectorXd(dual_size),
|
||||||
};
|
};
|
||||||
const QuadraticProgram& qp = WorkingQp();
|
const QuadraticProgram& qp = WorkingQp();
|
||||||
VectorXd extrapolated_primal(ShardedWorkingQp().PrimalSize());
|
std::optional<VectorXd> extrapolated_primal;
|
||||||
ShardedWorkingQp().PrimalSharder().ParallelForEachShard(
|
if (!next_primal_product) {
|
||||||
[&](const Sharder::Shard& shard) {
|
extrapolated_primal.emplace(ShardedWorkingQp().PrimalSize());
|
||||||
shard(extrapolated_primal) =
|
ShardedWorkingQp().PrimalSharder().ParallelForEachShard(
|
||||||
(shard(next_primal_solution.value) +
|
[&](const Sharder::Shard& shard) {
|
||||||
extrapolation_factor * shard(next_primal_solution.delta));
|
shard(*extrapolated_primal) =
|
||||||
});
|
(shard(next_primal_solution.value) +
|
||||||
// TODO(user): Refactor this multiplication so that we only do one matrix
|
extrapolation_factor * shard(next_primal_solution.delta));
|
||||||
// vector multiply for the primal variable. This only applies to Malitsky and
|
});
|
||||||
// Pock and not to the adaptive step size rule.
|
}
|
||||||
ShardedWorkingQp().TransposedConstraintMatrixSharder().ParallelForEachShard(
|
ShardedWorkingQp().TransposedConstraintMatrixSharder().ParallelForEachShard(
|
||||||
[&](const Sharder::Shard& shard) {
|
[&](const Sharder::Shard& shard) {
|
||||||
VectorXd temp =
|
VectorXd temp;
|
||||||
shard(current_dual_solution_) -
|
if (next_primal_product) {
|
||||||
dual_step_size *
|
CHECK(current_primal_product_.has_value());
|
||||||
shard(ShardedWorkingQp().TransposedConstraintMatrix())
|
temp = shard(current_dual_solution_) -
|
||||||
.transpose() *
|
dual_step_size *
|
||||||
extrapolated_primal;
|
(-extrapolation_factor * shard(*current_primal_product_) +
|
||||||
|
(extrapolation_factor + 1) * shard(*next_primal_product));
|
||||||
|
} else {
|
||||||
|
temp = shard(current_dual_solution_) -
|
||||||
|
dual_step_size *
|
||||||
|
shard(ShardedWorkingQp().TransposedConstraintMatrix())
|
||||||
|
.transpose() *
|
||||||
|
extrapolated_primal.value();
|
||||||
|
}
|
||||||
|
|
||||||
// Each element of the argument of `.cwiseMin()` is the critical point
|
// Each element of the argument of `.cwiseMin()` is the critical point
|
||||||
// of the respective 1D minimization problem if it's negative.
|
// of the respective 1D minimization problem if it's negative.
|
||||||
// Likewise the argument to the `.cwiseMax()` is the critical point if
|
// Likewise the argument to the `.cwiseMax()` is the critical point if
|
||||||
@@ -1937,6 +1956,21 @@ double Solver::ComputeNonlinearity(const VectorXd& delta_primal,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Solver::SetCurrentPrimalAndDualProducts() {
|
||||||
|
if (params_.linesearch_rule() ==
|
||||||
|
PrimalDualHybridGradientParams::MALITSKY_POCK_LINESEARCH_RULE) {
|
||||||
|
current_primal_product_ = TransposedMatrixVectorProduct(
|
||||||
|
ShardedWorkingQp().TransposedConstraintMatrix(),
|
||||||
|
current_primal_solution_,
|
||||||
|
ShardedWorkingQp().TransposedConstraintMatrixSharder());
|
||||||
|
} else {
|
||||||
|
current_primal_product_.reset();
|
||||||
|
}
|
||||||
|
current_dual_product_ = TransposedMatrixVectorProduct(
|
||||||
|
WorkingQp().constraint_matrix, current_dual_solution_,
|
||||||
|
ShardedWorkingQp().ConstraintMatrixSharder());
|
||||||
|
}
|
||||||
|
|
||||||
IterationStats Solver::CreateSimpleIterationStats(
|
IterationStats Solver::CreateSimpleIterationStats(
|
||||||
RestartChoice restart_used) const {
|
RestartChoice restart_used) const {
|
||||||
IterationStats stats;
|
IterationStats stats;
|
||||||
@@ -1977,8 +2011,10 @@ LocalizedLagrangianBounds Solver::ComputeLocalizedBoundsAtCurrent() const {
|
|||||||
ShardedWorkingQp(), current_primal_solution_, current_dual_solution_,
|
ShardedWorkingQp(), current_primal_solution_, current_dual_solution_,
|
||||||
PrimalDualNorm::kEuclideanNorm, primal_weight_,
|
PrimalDualNorm::kEuclideanNorm, primal_weight_,
|
||||||
distance_traveled_by_current,
|
distance_traveled_by_current,
|
||||||
/*primal_product=*/nullptr, ¤t_dual_product_,
|
/*primal_product=*/current_primal_product_.has_value()
|
||||||
params_.use_diagonal_qp_trust_region_solver(),
|
? ¤t_primal_product_.value()
|
||||||
|
: nullptr,
|
||||||
|
¤t_dual_product_, params_.use_diagonal_qp_trust_region_solver(),
|
||||||
params_.diagonal_qp_trust_region_solver_tolerance());
|
params_.diagonal_qp_trust_region_solver_tolerance());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2225,9 +2261,7 @@ void Solver::ApplyRestartChoice(const RestartChoice restart_to_apply) {
|
|||||||
}
|
}
|
||||||
current_primal_solution_ = primal_average_.ComputeAverage();
|
current_primal_solution_ = primal_average_.ComputeAverage();
|
||||||
current_dual_solution_ = dual_average_.ComputeAverage();
|
current_dual_solution_ = dual_average_.ComputeAverage();
|
||||||
current_dual_product_ = TransposedMatrixVectorProduct(
|
SetCurrentPrimalAndDualProducts();
|
||||||
WorkingQp().constraint_matrix, current_dual_solution_,
|
|
||||||
ShardedWorkingQp().ConstraintMatrixSharder());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
primal_weight_ = ComputeNewPrimalWeight();
|
primal_weight_ = ComputeNewPrimalWeight();
|
||||||
@@ -2443,6 +2477,14 @@ InnerStepOutcome Solver::TakeMalitskyPockStep() {
|
|||||||
params_.malitsky_pock_parameters().linesearch_contraction_factor();
|
params_.malitsky_pock_parameters().linesearch_contraction_factor();
|
||||||
const double dual_weight = primal_weight_ * primal_weight_;
|
const double dual_weight = primal_weight_ * primal_weight_;
|
||||||
int inner_iterations = 0;
|
int inner_iterations = 0;
|
||||||
|
VectorXd next_primal_product(current_dual_solution_.size());
|
||||||
|
ShardedWorkingQp().TransposedConstraintMatrixSharder().ParallelForEachShard(
|
||||||
|
[&](const Sharder::Shard& shard) {
|
||||||
|
shard(next_primal_product) =
|
||||||
|
shard(ShardedWorkingQp().TransposedConstraintMatrix()).transpose() *
|
||||||
|
next_primal_solution.value;
|
||||||
|
});
|
||||||
|
|
||||||
for (bool accepted_step = false; !accepted_step; ++inner_iterations) {
|
for (bool accepted_step = false; !accepted_step; ++inner_iterations) {
|
||||||
if (inner_iterations >= 60) {
|
if (inner_iterations >= 60) {
|
||||||
LogInnerIterationLimitHit();
|
LogInnerIterationLimitHit();
|
||||||
@@ -2454,7 +2496,7 @@ InnerStepOutcome Solver::TakeMalitskyPockStep() {
|
|||||||
new_primal_step_size / primal_step_size;
|
new_primal_step_size / primal_step_size;
|
||||||
NextSolutionAndDelta next_dual_solution = ComputeNextDualSolution(
|
NextSolutionAndDelta next_dual_solution = ComputeNextDualSolution(
|
||||||
dual_weight * new_primal_step_size, new_last_two_step_sizes_ratio,
|
dual_weight * new_primal_step_size, new_last_two_step_sizes_ratio,
|
||||||
next_primal_solution);
|
next_primal_solution, &next_primal_product);
|
||||||
|
|
||||||
VectorXd next_dual_product = TransposedMatrixVectorProduct(
|
VectorXd next_dual_product = TransposedMatrixVectorProduct(
|
||||||
WorkingQp().constraint_matrix, next_dual_solution.value,
|
WorkingQp().constraint_matrix, next_dual_solution.value,
|
||||||
@@ -2482,6 +2524,7 @@ InnerStepOutcome Solver::TakeMalitskyPockStep() {
|
|||||||
current_primal_solution_ = std::move(next_primal_solution.value);
|
current_primal_solution_ = std::move(next_primal_solution.value);
|
||||||
current_dual_solution_ = std::move(next_dual_solution.value);
|
current_dual_solution_ = std::move(next_dual_solution.value);
|
||||||
current_dual_product_ = std::move(next_dual_product);
|
current_dual_product_ = std::move(next_dual_product);
|
||||||
|
current_primal_product_ = std::move(next_primal_product);
|
||||||
primal_average_.Add(current_primal_solution_,
|
primal_average_.Add(current_primal_solution_,
|
||||||
/*weight=*/new_primal_step_size);
|
/*weight=*/new_primal_step_size);
|
||||||
dual_average_.Add(current_dual_solution_,
|
dual_average_.Add(current_dual_solution_,
|
||||||
@@ -2555,6 +2598,7 @@ InnerStepOutcome Solver::TakeAdaptiveStep() {
|
|||||||
current_primal_solution_ = std::move(next_primal_solution.value);
|
current_primal_solution_ = std::move(next_primal_solution.value);
|
||||||
current_dual_solution_ = std::move(next_dual_solution.value);
|
current_dual_solution_ = std::move(next_dual_solution.value);
|
||||||
current_dual_product_ = std::move(next_dual_product);
|
current_dual_product_ = std::move(next_dual_product);
|
||||||
|
current_primal_product_.reset();
|
||||||
current_primal_delta_ = std::move(next_primal_solution.delta);
|
current_primal_delta_ = std::move(next_primal_solution.delta);
|
||||||
current_dual_delta_ = std::move(next_dual_solution.delta);
|
current_dual_delta_ = std::move(next_dual_solution.delta);
|
||||||
primal_average_.Add(current_primal_solution_, /*weight=*/step_size_);
|
primal_average_.Add(current_primal_solution_, /*weight=*/step_size_);
|
||||||
@@ -2620,6 +2664,7 @@ InnerStepOutcome Solver::TakeConstantSizeStep() {
|
|||||||
current_primal_solution_ = std::move(next_primal_solution.value);
|
current_primal_solution_ = std::move(next_primal_solution.value);
|
||||||
current_dual_solution_ = std::move(next_dual_solution.value);
|
current_dual_solution_ = std::move(next_dual_solution.value);
|
||||||
current_dual_product_ = std::move(next_dual_product);
|
current_dual_product_ = std::move(next_dual_product);
|
||||||
|
current_primal_product_.reset();
|
||||||
current_primal_delta_ = std::move(next_primal_solution.delta);
|
current_primal_delta_ = std::move(next_primal_solution.delta);
|
||||||
current_dual_delta_ = std::move(next_dual_solution.delta);
|
current_dual_delta_ = std::move(next_dual_solution.delta);
|
||||||
primal_average_.Add(current_primal_solution_, /*weight=*/step_size_);
|
primal_average_.Add(current_primal_solution_, /*weight=*/step_size_);
|
||||||
@@ -2980,9 +3025,7 @@ SolverResult Solver::Solve(const IterationType iteration_type,
|
|||||||
// restart.
|
// restart.
|
||||||
|
|
||||||
ratio_last_two_step_sizes_ = 1;
|
ratio_last_two_step_sizes_ = 1;
|
||||||
current_dual_product_ = TransposedMatrixVectorProduct(
|
SetCurrentPrimalAndDualProducts();
|
||||||
WorkingQp().constraint_matrix, current_dual_solution_,
|
|
||||||
ShardedWorkingQp().ConstraintMatrixSharder());
|
|
||||||
|
|
||||||
// This is set to true if we can't proceed any more because of numerical
|
// This is set to true if we can't proceed any more because of numerical
|
||||||
// issues. We may or may not have found the optimal solution.
|
// issues. We may or may not have found the optimal solution.
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ This project aim to explain how you build a Python native wheel package using
|
|||||||
|
|
||||||
## Requirement
|
## Requirement
|
||||||
|
|
||||||
You'll need "Python >= 3.6" and few python modules ("wheel" and "absl-py").
|
You'll need "Python >= 3.9" and few python modules ("wheel" and "absl-py").
|
||||||
|
|
||||||
## Directory Layout
|
## Directory Layout
|
||||||
|
|
||||||
|
|||||||
@@ -884,6 +884,9 @@ class SparseBitset {
|
|||||||
|
|
||||||
// A bit hacky for really hot loop.
|
// A bit hacky for really hot loop.
|
||||||
typename Bitset64<IntegerType>::View BitsetView() { return bitset_.view(); }
|
typename Bitset64<IntegerType>::View BitsetView() { return bitset_.view(); }
|
||||||
|
typename Bitset64<IntegerType>::ConstView BitsetConstView() {
|
||||||
|
return bitset_.const_view();
|
||||||
|
}
|
||||||
void SetUnsafe(typename Bitset64<IntegerType>::View view, IntegerType index) {
|
void SetUnsafe(typename Bitset64<IntegerType>::View view, IntegerType index) {
|
||||||
view.Set(index);
|
view.Set(index);
|
||||||
to_clear_.push_back(index);
|
to_clear_.push_back(index);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
//
|
|
||||||
// Classes for permuting indexable, ordered containers of data without
|
// Classes for permuting indexable, ordered containers of data without
|
||||||
// depending on that data to be accessible in any particular way. The
|
// depending on that data to be accessible in any particular way. The
|
||||||
// client needs to give us two things:
|
// client needs to give us two things:
|
||||||
|
|||||||
@@ -724,7 +724,9 @@ class ClosedInterval::Iterator {
|
|||||||
// arithmetic.
|
// arithmetic.
|
||||||
uint64_t current_;
|
uint64_t current_;
|
||||||
};
|
};
|
||||||
|
#if __cplusplus >= 202002L
|
||||||
|
static_assert(std::input_iterator<ClosedInterval::Iterator>);
|
||||||
|
#endif
|
||||||
// begin()/end() are required for iteration over ClosedInterval in a range for
|
// begin()/end() are required for iteration over ClosedInterval in a range for
|
||||||
// loop.
|
// loop.
|
||||||
inline ClosedInterval::Iterator begin(ClosedInterval interval) {
|
inline ClosedInterval::Iterator begin(ClosedInterval interval) {
|
||||||
|
|||||||
Reference in New Issue
Block a user