diff --git a/ortools/base/logging.cc b/ortools/base/logging.cc index a10b6bd405..673c0a5f4e 100644 --- a/ortools/base/logging.cc +++ b/ortools/base/logging.cc @@ -36,8 +36,6 @@ void FixFlagsAndEnvironmentForSwig() { absl::EnableLogPrefix(false); } -void KeepAbslSymbols() { - absl::SetFlag(&FLAGS_stderrthreshold, 0); -} +void KeepAbslSymbols() { absl::SetFlag(&FLAGS_stderrthreshold, 0); } } // namespace operations_research diff --git a/ortools/bop/bop_base.cc b/ortools/bop/bop_base.cc index 3dfffddb5b..b31ad3d19a 100644 --- a/ortools/bop/bop_base.cc +++ b/ortools/bop/bop_base.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include #include diff --git a/ortools/bop/bop_ls.cc b/ortools/bop/bop_ls.cc index 33ae64b5c8..39f08c89e2 100644 --- a/ortools/bop/bop_ls.cc +++ b/ortools/bop/bop_ls.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/ortools/bop/bop_solver.cc b/ortools/bop/bop_solver.cc index a96a2d7fee..ab0d6d6435 100644 --- a/ortools/bop/bop_solver.cc +++ b/ortools/bop/bop_solver.cc @@ -13,6 +13,7 @@ #include "ortools/bop/bop_solver.h" +#include #include #include #include diff --git a/ortools/bop/integral_solver.cc b/ortools/bop/integral_solver.cc index 5ef009338e..8813a4d2fd 100644 --- a/ortools/bop/integral_solver.cc +++ b/ortools/bop/integral_solver.cc @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/ortools/constraint_solver/samples/tsp.cc b/ortools/constraint_solver/samples/tsp.cc index 0b2a36419d..e2df3990dc 100644 --- a/ortools/constraint_solver/samples/tsp.cc +++ b/ortools/constraint_solver/samples/tsp.cc @@ -18,6 +18,7 @@ #include #include +#include "ortools/base/init_google.h" #include "ortools/constraint_solver/routing.h" #include "ortools/constraint_solver/routing_enums.pb.h" #include "ortools/constraint_solver/routing_index_manager.h" @@ -146,7 +147,8 @@ void Tsp() { } // namespace operations_research -int main(int /*argc*/, char* /*argv*/[]) { +int main(int argc, char* argv[]) { + InitGoogle(argv[0], &argc, &argv, true); operations_research::Tsp(); return EXIT_SUCCESS; } diff --git a/ortools/flatzinc/checker.cc b/ortools/flatzinc/checker.cc index ccec7b85a0..765add9fa0 100644 --- a/ortools/flatzinc/checker.cc +++ b/ortools/flatzinc/checker.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include #include diff --git a/ortools/glop/basis_representation.cc b/ortools/glop/basis_representation.cc index bd0017a0c3..e8450d7612 100644 --- a/ortools/glop/basis_representation.cc +++ b/ortools/glop/basis_representation.cc @@ -14,6 +14,7 @@ #include "ortools/glop/basis_representation.h" #include +#include #include #include "ortools/base/stl_util.h" diff --git a/ortools/glop/dual_edge_norms.cc b/ortools/glop/dual_edge_norms.cc index 48e3b67c22..d97e31f579 100644 --- a/ortools/glop/dual_edge_norms.cc +++ b/ortools/glop/dual_edge_norms.cc @@ -13,6 +13,8 @@ #include "ortools/glop/dual_edge_norms.h" +#include + #include "ortools/lp_data/lp_utils.h" namespace operations_research { diff --git a/ortools/glop/entering_variable.cc b/ortools/glop/entering_variable.cc index 4f90c2fa2e..549f35fdd9 100644 --- a/ortools/glop/entering_variable.cc +++ b/ortools/glop/entering_variable.cc @@ -14,6 +14,7 @@ #include "ortools/glop/entering_variable.h" #include +#include #include #include #include diff --git a/ortools/glop/initial_basis.cc b/ortools/glop/initial_basis.cc index ed4d5a65d8..5763946705 100644 --- a/ortools/glop/initial_basis.cc +++ b/ortools/glop/initial_basis.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include #include diff --git a/ortools/glop/lp_solver.cc b/ortools/glop/lp_solver.cc index 4586663ffe..8c325f9dc4 100644 --- a/ortools/glop/lp_solver.cc +++ b/ortools/glop/lp_solver.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include #include diff --git a/ortools/glop/lu_factorization.cc b/ortools/glop/lu_factorization.cc index 70a7b9c116..4eb7bae45a 100644 --- a/ortools/glop/lu_factorization.cc +++ b/ortools/glop/lu_factorization.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include "ortools/lp_data/lp_types.h" diff --git a/ortools/glop/markowitz.cc b/ortools/glop/markowitz.cc index b42051f28a..16ef140a30 100644 --- a/ortools/glop/markowitz.cc +++ b/ortools/glop/markowitz.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include #include diff --git a/ortools/glop/preprocessor.cc b/ortools/glop/preprocessor.cc index 8e44a87cf8..71ef14022c 100644 --- a/ortools/glop/preprocessor.cc +++ b/ortools/glop/preprocessor.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/ortools/glop/primal_edge_norms.cc b/ortools/glop/primal_edge_norms.cc index 0c54245faf..27319044ab 100644 --- a/ortools/glop/primal_edge_norms.cc +++ b/ortools/glop/primal_edge_norms.cc @@ -14,6 +14,7 @@ #include "ortools/glop/primal_edge_norms.h" #include +#include #include "ortools/base/timer.h" #include "ortools/lp_data/lp_utils.h" diff --git a/ortools/glop/reduced_costs.cc b/ortools/glop/reduced_costs.cc index a1dfb3606e..1fff57de37 100644 --- a/ortools/glop/reduced_costs.cc +++ b/ortools/glop/reduced_costs.cc @@ -14,6 +14,7 @@ #include "ortools/glop/reduced_costs.h" #include +#include #include #ifdef OMP diff --git a/ortools/glop/revised_simplex.cc b/ortools/glop/revised_simplex.cc index a72585fbdd..8b793b5b38 100644 --- a/ortools/glop/revised_simplex.cc +++ b/ortools/glop/revised_simplex.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/ortools/glop/update_row.cc b/ortools/glop/update_row.cc index 8b8fe8a2b1..a0d7365283 100644 --- a/ortools/glop/update_row.cc +++ b/ortools/glop/update_row.cc @@ -13,6 +13,7 @@ #include "ortools/glop/update_row.h" +#include #include #include "ortools/lp_data/lp_utils.h" diff --git a/ortools/glop/variable_values.cc b/ortools/glop/variable_values.cc index 83d3ed1563..6616731284 100644 --- a/ortools/glop/variable_values.cc +++ b/ortools/glop/variable_values.cc @@ -14,6 +14,7 @@ #include "ortools/glop/variable_values.h" #include +#include #include #include "ortools/graph/iterators.h" diff --git a/ortools/glop/variables_info.cc b/ortools/glop/variables_info.cc index 7289ddc108..6c67c1eb1d 100644 --- a/ortools/glop/variables_info.cc +++ b/ortools/glop/variables_info.cc @@ -13,6 +13,7 @@ #include "ortools/glop/variables_info.h" +#include #include namespace operations_research { diff --git a/ortools/graph/min_cost_flow.cc b/ortools/graph/min_cost_flow.cc index 9ec3d56869..de9c960e5a 100644 --- a/ortools/graph/min_cost_flow.cc +++ b/ortools/graph/min_cost_flow.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/ortools/graph/perfect_matching.cc b/ortools/graph/perfect_matching.cc index f1dd4d10a3..5f9bf246ca 100644 --- a/ortools/graph/perfect_matching.cc +++ b/ortools/graph/perfect_matching.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include #include diff --git a/ortools/java/com/google/ortools/BUILD.bazel b/ortools/java/com/google/ortools/BUILD.bazel index 871cb8e936..ece1787556 100644 --- a/ortools/java/com/google/ortools/BUILD.bazel +++ b/ortools/java/com/google/ortools/BUILD.bazel @@ -14,11 +14,11 @@ # Utilities to load native libraries in java or-tools. cc_binary( name = "libjniortools.so", - target_compatible_with = select({ - "@platforms//os:linux": [], - "//conditions:default": ["@platforms//:incompatible"], - }), linkshared = True, + target_compatible_with = select({ + "@platforms//os:linux": [], + "//conditions:default": ["@platforms//:incompatible"], + }), visibility = ["//visibility:public"], deps = [ "//ortools/algorithms/java:knapsacksolver_cc", @@ -32,11 +32,11 @@ cc_binary( cc_binary( name = "libjniortools.dylib", - target_compatible_with = select({ - "@platforms//os:osx": [], - "//conditions:default": ["@platforms//:incompatible"], - }), linkshared = True, + target_compatible_with = select({ + "@platforms//os:osx": [], + "//conditions:default": ["@platforms//:incompatible"], + }), visibility = ["//visibility:public"], deps = [ "//ortools/algorithms/java:knapsacksolver_cc", @@ -50,11 +50,11 @@ cc_binary( cc_binary( name = "jniortools.dll", - target_compatible_with = select({ - "@platforms//os:windows": [], - "//conditions:default": ["@platforms//:incompatible"], - }), linkshared = True, + target_compatible_with = select({ + "@platforms//os:windows": [], + "//conditions:default": ["@platforms//:incompatible"], + }), visibility = ["//visibility:public"], deps = [ "//ortools/algorithms/java:knapsacksolver_cc", @@ -71,9 +71,9 @@ java_library( srcs = ["Loader.java"], visibility = ["//visibility:public"], runtime_deps = select({ - "@platforms//os:linux": ["//ortools/java/com/google/ortools:libjniortools.so"], - "@platforms//os:osx": ["//ortools/java/com/google/ortools:libjniortools.dylib"], - "@platforms//os:windows": ["//ortools/java/com/google/ortools:jniortools.dll"], + "@platforms//os:linux": ["//ortools/java/com/google/ortools:libjniortools.so"], + "@platforms//os:osx": ["//ortools/java/com/google/ortools:libjniortools.dylib"], + "@platforms//os:windows": ["//ortools/java/com/google/ortools:jniortools.dll"], }), deps = [ "@maven//:net_java_dev_jna_jna", diff --git a/ortools/java/com/google/ortools/Loader.java b/ortools/java/com/google/ortools/Loader.java index b679687f01..f160bf99cb 100644 --- a/ortools/java/com/google/ortools/Loader.java +++ b/ortools/java/com/google/ortools/Loader.java @@ -105,8 +105,8 @@ public class Loader { if (!loaded) { try { // prints the name of the Operating System - //System.out.println("OS: " + System.getProperty("os.name")); - //System.out.println("Library: " + System.mapLibraryName("jniortools")); + // System.out.println("OS: " + System.getProperty("os.name")); + // System.out.println("Library: " + System.mapLibraryName("jniortools")); System.loadLibrary("jniortools"); loaded = true; diff --git a/ortools/linear_solver/linear_expr.cc b/ortools/linear_solver/linear_expr.cc index 86522f22be..8e76c197ec 100644 --- a/ortools/linear_solver/linear_expr.cc +++ b/ortools/linear_solver/linear_expr.cc @@ -14,6 +14,7 @@ #include "ortools/linear_solver/linear_expr.h" #include +#include #include #include #include diff --git a/ortools/linear_solver/linear_solver.h b/ortools/linear_solver/linear_solver.h index ab8d874d4c..50bef852fc 100644 --- a/ortools/linear_solver/linear_solver.h +++ b/ortools/linear_solver/linear_solver.h @@ -163,6 +163,8 @@ #include "ortools/port/proto_utils.h" ABSL_DECLARE_FLAG(bool, linear_solver_enable_verbose_output); +ABSL_DECLARE_FLAG(bool, log_verification_errors); +ABSL_DECLARE_FLAG(bool, verify_solution); namespace operations_research { diff --git a/ortools/linear_solver/model_validator.cc b/ortools/linear_solver/model_validator.cc index 728ed6b06c..932140ad34 100644 --- a/ortools/linear_solver/model_validator.cc +++ b/ortools/linear_solver/model_validator.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include #include diff --git a/ortools/linear_solver/proto_solver/sat_proto_solver.cc b/ortools/linear_solver/proto_solver/sat_proto_solver.cc index 987e80010d..52c1a71f29 100644 --- a/ortools/linear_solver/proto_solver/sat_proto_solver.cc +++ b/ortools/linear_solver/proto_solver/sat_proto_solver.cc @@ -14,8 +14,10 @@ #include "ortools/linear_solver/proto_solver/sat_proto_solver.h" #include +#include #include #include +#include #include #include #include diff --git a/ortools/linear_solver/proto_solver/sat_proto_solver.h b/ortools/linear_solver/proto_solver/sat_proto_solver.h index 59da3f5d66..3b05df85ba 100644 --- a/ortools/linear_solver/proto_solver/sat_proto_solver.h +++ b/ortools/linear_solver/proto_solver/sat_proto_solver.h @@ -14,6 +14,7 @@ #ifndef OR_TOOLS_LINEAR_SOLVER_PROTO_SOLVER_SAT_PROTO_SOLVER_H_ #define OR_TOOLS_LINEAR_SOLVER_PROTO_SOLVER_SAT_PROTO_SOLVER_H_ +#include #include #include diff --git a/ortools/linear_solver/proto_solver/scip_proto_solver.cc b/ortools/linear_solver/proto_solver/scip_proto_solver.cc index dd036ea517..4dba1cd690 100644 --- a/ortools/linear_solver/proto_solver/scip_proto_solver.cc +++ b/ortools/linear_solver/proto_solver/scip_proto_solver.cc @@ -17,6 +17,7 @@ #include #include +#include #include #include #include diff --git a/ortools/linear_solver/scip_interface.cc b/ortools/linear_solver/scip_interface.cc index e72f480042..52539129db 100644 --- a/ortools/linear_solver/scip_interface.cc +++ b/ortools/linear_solver/scip_interface.cc @@ -16,6 +16,7 @@ #include #include +#include #include #include #include diff --git a/ortools/linear_solver/solve.cc b/ortools/linear_solver/solve.cc index 89a108af72..168fec8685 100644 --- a/ortools/linear_solver/solve.cc +++ b/ortools/linear_solver/solve.cc @@ -116,6 +116,8 @@ ABSL_FLAG(std::string, sol_file, "", "If non-empty, output the best solution in Miplib .sol format."); ABSL_DECLARE_FLAG(bool, verify_solution); // Defined in ./linear_solver.cc +ABSL_DECLARE_FLAG(bool, + log_verification_errors); // Defined in ./linear_solver.cc ABSL_DECLARE_FLAG( bool, linear_solver_enable_verbose_output); // Defined in ./linear_solver.cc @@ -239,10 +241,12 @@ MPSolutionResponse LocalSolve(const MPModelRequest& request_proto) { // a verification step here. if ((status == MPSolver::OPTIMAL || status == MPSolver::FEASIBLE) && !absl::GetFlag(FLAGS_verify_solution)) { - LOG(INFO) << "Verifying the solution"; - solver.VerifySolution(/*tolerance=*/MPSolverParameters().GetDoubleParam( - MPSolverParameters::PRIMAL_TOLERANCE), - /*log_errors=*/true); + const bool verified = + solver.VerifySolution(/*tolerance=*/MPSolverParameters().GetDoubleParam( + MPSolverParameters::PRIMAL_TOLERANCE), + absl::GetFlag(FLAGS_log_verification_errors)); + LOG(INFO) << "The solution " + << (verified ? "was verified." : "didn't pass verification."); } // If the solver is a MIP, print the number of nodes. diff --git a/ortools/lp_data/lp_data.cc b/ortools/lp_data/lp_data.cc index fd392a046b..b9591615bf 100644 --- a/ortools/lp_data/lp_data.cc +++ b/ortools/lp_data/lp_data.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/ortools/lp_data/lp_utils.h b/ortools/lp_data/lp_utils.h index a8a72d245d..4d293ca780 100644 --- a/ortools/lp_data/lp_utils.h +++ b/ortools/lp_data/lp_utils.h @@ -17,6 +17,7 @@ #define OR_TOOLS_LP_DATA_LP_UTILS_H_ #include +#include #include "ortools/base/accurate_sum.h" #include "ortools/lp_data/lp_types.h" diff --git a/ortools/lp_data/matrix_scaler.cc b/ortools/lp_data/matrix_scaler.cc index e3bce7a307..5bc202c52b 100644 --- a/ortools/lp_data/matrix_scaler.cc +++ b/ortools/lp_data/matrix_scaler.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include #include diff --git a/ortools/lp_data/matrix_utils.cc b/ortools/lp_data/matrix_utils.cc index 101d1d1286..7383ae10ad 100644 --- a/ortools/lp_data/matrix_utils.cc +++ b/ortools/lp_data/matrix_utils.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include diff --git a/ortools/lp_data/sparse.cc b/ortools/lp_data/sparse.cc index 339f8ece2d..2ecd16553f 100644 --- a/ortools/lp_data/sparse.cc +++ b/ortools/lp_data/sparse.cc @@ -14,6 +14,7 @@ #include "ortools/lp_data/sparse.h" #include +#include #include #include #include diff --git a/ortools/pdlp/BUILD.bazel b/ortools/pdlp/BUILD.bazel index 8a56b48152..06d71b173c 100644 --- a/ortools/pdlp/BUILD.bazel +++ b/ortools/pdlp/BUILD.bazel @@ -47,7 +47,7 @@ cc_proto_library( py_proto_library( name = "solvers_py_pb2", deps = [ - ":solvers_proto", + ":solvers_proto", ], ) diff --git a/ortools/pdlp/primal_dual_hybrid_gradient.cc b/ortools/pdlp/primal_dual_hybrid_gradient.cc index 2fb21f950d..ea09124d95 100644 --- a/ortools/pdlp/primal_dual_hybrid_gradient.cc +++ b/ortools/pdlp/primal_dual_hybrid_gradient.cc @@ -33,6 +33,8 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" #include "ortools/base/logging.h" #include "ortools/base/mathutil.h" #include "ortools/base/timer.h" @@ -258,9 +260,11 @@ void LogIterationStats(int verbosity_level, bool use_feasibility_polishing, LogInfoWithoutPrefix(absl::StrCat(phase_string, iterate_string, iteration_string, " | ", convergence_string)); + } else { + // No convergence information, just log the basic work stats. + LogInfoWithoutPrefix(absl::StrCat( + phase_string, verbosity_level >= 4 ? "? " : "", iteration_string)); } - LogInfoWithoutPrefix(absl::StrCat( - phase_string, verbosity_level >= 4 ? "? " : "", iteration_string)); } void LogIterationStatsHeader(int verbosity_level, diff --git a/ortools/pdlp/sharder.cc b/ortools/pdlp/sharder.cc index 0de3b81119..1884fc4af2 100644 --- a/ortools/pdlp/sharder.cc +++ b/ortools/pdlp/sharder.cc @@ -78,17 +78,22 @@ Sharder::Sharder(const int64_t num_elements, const int num_shards, return; } CHECK_GE(num_shards, 1); - shard_starts_.reserve( - std::min(static_cast(num_shards), num_elements) + 1); - shard_masses_.reserve( - std::min(static_cast(num_shards), num_elements)); - for (int shard = 0; shard < num_shards; ++shard) { - const int64_t this_shard_start = ((num_elements * shard) / num_shards); - const int64_t next_shard_start = - ((num_elements * (shard + 1)) / num_shards); - if (next_shard_start - this_shard_start > 0) { - shard_starts_.push_back(this_shard_start); - shard_masses_.push_back(next_shard_start - this_shard_start); + shard_starts_.reserve(std::min(int64_t{num_shards}, num_elements) + 1); + shard_masses_.reserve(std::min(int64_t{num_shards}, num_elements)); + if (num_shards >= num_elements) { + for (int64_t element = 0; element < num_elements; ++element) { + shard_starts_.push_back(static_cast(element)); + shard_masses_.push_back(1); + } + } else { + for (int shard = 0; shard < num_shards; ++shard) { + const int64_t this_shard_start = ((num_elements * shard) / num_shards); + const int64_t next_shard_start = + ((num_elements * (shard + 1)) / num_shards); + if (next_shard_start - this_shard_start > 0) { + shard_starts_.push_back(this_shard_start); + shard_masses_.push_back(next_shard_start - this_shard_start); + } } } shard_starts_.push_back(num_elements); diff --git a/ortools/pdlp/solvers.proto b/ortools/pdlp/solvers.proto index 0a6a183c3a..1f8b702e6c 100644 --- a/ortools/pdlp/solvers.proto +++ b/ortools/pdlp/solvers.proto @@ -299,6 +299,13 @@ message PrimalDualHybridGradientParams { // Logging at levels 2-4 also includes messages from level 1. optional int32 verbosity_level = 26 [default = 0]; + // Time between iteration-level statistics logging (if `verbosity_level > 1`). + // Since iteration-level statistics are only generated when performing + // termination checks, logs will be generated from next termination check + // after `log_interval_seconds` have elapsed. Should be >= 0.0. 0.0 (the + // default) means log statistics at every termination check. + optional double log_interval_seconds = 31 [default = 0.0]; + // The frequency at which extra work is performed to make major algorithmic // decisions, e.g., performing restarts and updating the primal weight. Major // iterations also trigger a termination check. For best performance using the diff --git a/ortools/pdlp/solvers_proto_validation.cc b/ortools/pdlp/solvers_proto_validation.cc index 737a998255..4c9290c8d2 100644 --- a/ortools/pdlp/solvers_proto_validation.cc +++ b/ortools/pdlp/solvers_proto_validation.cc @@ -173,6 +173,12 @@ absl::Status ValidatePrimalDualHybridGradientParams( if (params.verbosity_level() < 0) { return InvalidArgumentError("verbosity_level must be non-negative"); } + if (params.log_interval_seconds() < 0.0) { + return InvalidArgumentError("log_interval_seconds must be non-negative"); + } + if (std::isnan(params.log_interval_seconds())) { + return InvalidArgumentError("log_interval_seconds is NAN"); + } if (params.major_iteration_frequency() <= 0) { return InvalidArgumentError("major_iteration_frequency must be positive"); } diff --git a/ortools/pdlp/solvers_proto_validation_test.cc b/ortools/pdlp/solvers_proto_validation_test.cc index 56668e25ac..2a954e55a8 100644 --- a/ortools/pdlp/solvers_proto_validation_test.cc +++ b/ortools/pdlp/solvers_proto_validation_test.cc @@ -386,6 +386,22 @@ TEST(ValidatePrimalDualHybridGradientParams, BadVerbosityLevel) { EXPECT_THAT(status.message(), HasSubstr("verbosity_level")); } +TEST(ValidatePrimalDualHybridGradientParams, BadLogIntervalSeconds) { + PrimalDualHybridGradientParams params_negative; + params_negative.set_log_interval_seconds(-1.0); + const absl::Status status_negative = + ValidatePrimalDualHybridGradientParams(params_negative); + EXPECT_EQ(status_negative.code(), absl::StatusCode::kInvalidArgument); + EXPECT_THAT(status_negative.message(), HasSubstr("log_interval_seconds")); + + PrimalDualHybridGradientParams params_nan; + params_nan.set_log_interval_seconds(std::numeric_limits::quiet_NaN()); + const absl::Status status_nan = + ValidatePrimalDualHybridGradientParams(params_nan); + EXPECT_EQ(status_nan.code(), absl::StatusCode::kInvalidArgument); + EXPECT_THAT(status_nan.message(), HasSubstr("log_interval_seconds")); +} + TEST(ValidatePrimalDualHybridGradientParams, BadMajorIterationFrequency) { PrimalDualHybridGradientParams params; params.set_major_iteration_frequency(0); diff --git a/ortools/routing/solution_serializer_test.cc b/ortools/routing/solution_serializer_test.cc index 5a0726d2a8..064e6f7f6e 100644 --- a/ortools/routing/solution_serializer_test.cc +++ b/ortools/routing/solution_serializer_test.cc @@ -17,11 +17,15 @@ #include #include +#include "gmock/gmock.h" #include "gtest/gtest.h" #include "ortools/base/mutable_memfile.h" namespace operations_research { namespace { + +using testing::MatchesRegex; + TEST(RoutingSolutionSerializerTest, RoutingSolutionEventComparison) { RoutingSolution::Event t1 = {RoutingSolution::Event::Type::kStart, 0, Arc{0, 0}}; @@ -150,11 +154,13 @@ TEST(RoutingSolutionSerializerTest, FromSplitRoutesWithTwoRoutes) { TEST(RoutingSolutionSerializerTest, SolutionToTsplib) { const std::vector solution{0, 1, 2, 3, 0, -1, 0, 4, 5, 6, 0, -1}; - const std::string expected_output = "0\n1\n2\n3\n0\n-1\n0\n4\n5\n6\n0\n-1\n"; - EXPECT_EQ(RoutingSolution::FromSplitRoutes( - RoutingSolution::SplitRoutes(solution, -1), 0) - .SerializeToString(RoutingOutputFormat::kTSPLIB), - expected_output); + const std::string expected_output = + "0\\r?\\n1\\r?\\n2\\r?\\n3\\r?\\n0\\r?\\n-1\\r?\\n" + "0\\r?\\n4\\r?\\n5\\r?\\n6\\r?\\n0\\r?\\n-1\\r?\\n"; + EXPECT_THAT(RoutingSolution::FromSplitRoutes( + RoutingSolution::SplitRoutes(solution, -1), 0) + .SerializeToString(RoutingOutputFormat::kTSPLIB), + MatchesRegex(expected_output)); } TEST(RoutingSolutionSerializerTest, SolutionToTsplibFile) { @@ -164,12 +170,13 @@ TEST(RoutingSolutionSerializerTest, SolutionToTsplibFile) { const std::vector> solution_vector{{0, 1, 2, 3, 0}, {0, 4, 5, 6, 0}}; const std::string expected_output = - "NAME : Test name\n" - "COMMENT : Length = -1; Total time = -1.000000 s\n" - "TYPE : TOUR\n" - "DIMENSION : 7\n" - "TOUR_SECTION\n" - "0\n1\n2\n3\n0\n-1\n0\n4\n5\n6\n0\n-1\n" + "NAME : Test name\\r?\\n" + "COMMENT : Length = -1; Total time = -1.000000 s\\r?\\n" + "TYPE : TOUR\\r?\\n" + "DIMENSION : 7\\r?\\n" + "TOUR_SECTION\\r?\\n" + "0\\r?\\n1\\r?\\n2\\r?\\n3\\r?\\n0\\r?\\n-1\\r?\\n" + "0\\r?\\n4\\r?\\n5\\r?\\n6\\r?\\n0\\r?\\n-1\\r?\\n" "EOF"; RoutingSolution solution = @@ -178,18 +185,20 @@ TEST(RoutingSolutionSerializerTest, SolutionToTsplibFile) { solution.WriteToSolutionFile(RoutingOutputFormat::kTSPLIB, file_name); std::string written_solution; CHECK_OK(file::GetContents(file_name, &written_solution, file::Defaults())); - EXPECT_EQ(written_solution, expected_output); + EXPECT_THAT(written_solution, MatchesRegex(expected_output)); } TEST(RoutingSolutionSerializerTest, SolutionToCvrplib) { // Depot: 1. const std::vector solution{1, 2, 3, 1, -1, 1, 4, 5, 6, 1, -1}; - const std::string expected_output = "Route #1: 1 2\nRoute #2: 3 4 5\n"; + const std::string expected_output = + "Route #1: 1 2\\r?\\n" + "Route #2: 3 4 5\\r?\\n"; - EXPECT_EQ(RoutingSolution::FromSplitRoutes( - RoutingSolution::SplitRoutes(solution, -1), 1) - .SerializeToString(RoutingOutputFormat::kCVRPLIB), - expected_output); + EXPECT_THAT(RoutingSolution::FromSplitRoutes( + RoutingSolution::SplitRoutes(solution, -1), 1) + .SerializeToString(RoutingOutputFormat::kCVRPLIB), + MatchesRegex(expected_output)); } TEST(RoutingSolutionSerializerTest, SolutionToCvrplibInvalidNoStart) { @@ -230,24 +239,28 @@ TEST(RoutingSolutionSerializerTest, SolutionToCvrplibDepot0Dimacs) { // Section 7 from // http://dimacs.rutgers.edu/files/6916/3848/0327/CVRP_Competition_Rules.pdf const std::vector solution{0, 1, 4, 0, -1, 0, 3, 2, 5, 0, -1}; - const std::string expected_output = "Route #1: 1 4\nRoute #2: 3 2 5\n"; + const std::string expected_output = + "Route #1: 1 4\\r?\\n" + "Route #2: 3 2 5\\r?\\n"; - EXPECT_EQ(RoutingSolution::FromSplitRoutes( - RoutingSolution::SplitRoutes(solution, -1), 0) - .SerializeToString(RoutingOutputFormat::kCVRPLIB), - expected_output); + EXPECT_THAT(RoutingSolution::FromSplitRoutes( + RoutingSolution::SplitRoutes(solution, -1), 0) + .SerializeToString(RoutingOutputFormat::kCVRPLIB), + MatchesRegex(expected_output)); } TEST(RoutingSolutionSerializerTest, SolutionToCvrplibDepot1Dimacs) { // Section 7 from // http://dimacs.rutgers.edu/files/6916/3848/0327/CVRP_Competition_Rules.pdf const std::vector solution{1, 2, 5, 1, -1, 1, 4, 3, 6, 1, -1}; - const std::string expected_output = "Route #1: 1 4\nRoute #2: 3 2 5\n"; + const std::string expected_output = + "Route #1: 1 4\\r?\\n" + "Route #2: 3 2 5\\r?\\n"; - EXPECT_EQ(RoutingSolution::FromSplitRoutes( - RoutingSolution::SplitRoutes(solution, -1), 1) - .SerializeToString(RoutingOutputFormat::kCVRPLIB), - expected_output); + EXPECT_THAT(RoutingSolution::FromSplitRoutes( + RoutingSolution::SplitRoutes(solution, -1), 1) + .SerializeToString(RoutingOutputFormat::kCVRPLIB), + MatchesRegex(expected_output)); } TEST(RoutingSolutionSerializerTest, SolutionToCvrplibFile) { @@ -257,8 +270,8 @@ TEST(RoutingSolutionSerializerTest, SolutionToCvrplibFile) { const std::vector> solution_vector{{0, 1, 2, 3, 0}, {0, 4, 5, 6, 0}}; const std::string expected_output = - "Route #1: 1 2 3\n" - "Route #2: 4 5 6\n" + "Route #1: 1 2 3\\r?\\n" + "Route #2: 4 5 6\\r?\\n" "Cost 4857"; RoutingSolution solution = @@ -267,7 +280,7 @@ TEST(RoutingSolutionSerializerTest, SolutionToCvrplibFile) { solution.WriteToSolutionFile(RoutingOutputFormat::kCVRPLIB, file_name); std::string written_solution; CHECK_OK(file::GetContents(file_name, &written_solution, file::Defaults())); - EXPECT_EQ(written_solution, expected_output); + EXPECT_THAT(written_solution, MatchesRegex(expected_output)); } RoutingSolution MakeTestArcRoutingInstance() { @@ -395,19 +408,19 @@ RoutingSolution MakeTestEdgeNodeArcRoutingInstance() { TEST(RoutingSolutionSerializerTest, CarpSolutionToCarplib) { // http://dimacs.rutgers.edu/programs/challenge/vrp/carp/ const std::string expected_solution_output = - "0 1 1 5 76 7 (D 0,1,1) (S 12,5,11) (S 21,11,9) (S 8,9,2) (S 7,2,4) " - "(S 2,4,1) (D 0,1,1)\n" - "0 1 2 5 60 7 (D 0,1,1) (S 5,1,12) (S 14,6,7) (S 19,8,11) (S 22,11,10) " - "(S 4,10,1) (D 0,1,1)\n" - "0 1 3 5 86 7 (D 0,1,1) (S 13,12,5) (S 9,3,4) (S 6,2,3) (S 10,3,5) " - "(S 11,5,6) (D 0,1,1)\n" - "0 1 4 5 53 7 (D 0,1,1) (S 15,12,6) (S 16,7,8) (S 18,8,10) (S 20,10,9) " - "(S 1,2,1) (D 0,1,1)\n" - "0 1 5 2 41 4 (D 0,1,1) (S 17,12,7) (S 3,7,1) (D 0,1,1)"; + "0 1 1 5 76 7 \\(D 0,1,1\\) \\(S 12,5,11\\) \\(S 21,11,9\\) " + "\\(S 8,9,2\\) \\(S 7,2,4\\) \\(S 2,4,1\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 2 5 60 7 \\(D 0,1,1\\) \\(S 5,1,12\\) \\(S 14,6,7\\) " + "\\(S 19,8,11\\) \\(S 22,11,10\\) \\(S 4,10,1\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 3 5 86 7 \\(D 0,1,1\\) \\(S 13,12,5\\) \\(S 9,3,4\\) " + "\\(S 6,2,3\\) \\(S 10,3,5\\) \\(S 11,5,6\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 4 5 53 7 \\(D 0,1,1\\) \\(S 15,12,6\\) \\(S 16,7,8\\) " + "\\(S 18,8,10\\) \\(S 20,10,9\\) \\(S 1,2,1\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 5 2 41 4 \\(D 0,1,1\\) \\(S 17,12,7\\) \\(S 3,7,1\\) \\(D 0,1,1\\)"; const RoutingSolution solution = MakeTestArcRoutingInstance(); - EXPECT_EQ(solution.SerializeToString(RoutingOutputFormat::kCARPLIB), - expected_solution_output); + EXPECT_THAT(solution.SerializeToString(RoutingOutputFormat::kCARPLIB), + MatchesRegex(expected_solution_output)); } TEST(RoutingSolutionSerializerTest, CarpSolutionToCarplibFile) { @@ -416,41 +429,41 @@ TEST(RoutingSolutionSerializerTest, CarpSolutionToCarplibFile) { RoutingSolution solution = MakeTestArcRoutingInstance(); const std::string expected_output = - "7\n" - "5\n" - "30.840000\n" - "0 1 1 5 76 7 (D 0,1,1) (S 12,5,11) (S 21,11,9) (S 8,9,2) (S 7,2,4) " - "(S 2,4,1) (D 0,1,1)\n" - "0 1 2 5 60 7 (D 0,1,1) (S 5,1,12) (S 14,6,7) (S 19,8,11) (S 22,11,10) " - "(S 4,10,1) (D 0,1,1)\n" - "0 1 3 5 86 7 (D 0,1,1) (S 13,12,5) (S 9,3,4) (S 6,2,3) (S 10,3,5) " - "(S 11,5,6) (D 0,1,1)\n" - "0 1 4 5 53 7 (D 0,1,1) (S 15,12,6) (S 16,7,8) (S 18,8,10) (S 20,10,9) " - "(S 1,2,1) (D 0,1,1)\n" - "0 1 5 2 41 4 (D 0,1,1) (S 17,12,7) (S 3,7,1) (D 0,1,1)"; + "7\\r?\\n" + "5\\r?\\n" + "30.840000\\r?\\n" + "0 1 1 5 76 7 \\(D 0,1,1\\) \\(S 12,5,11\\) \\(S 21,11,9\\) " + "\\(S 8,9,2\\) \\(S 7,2,4\\) \\(S 2,4,1\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 2 5 60 7 \\(D 0,1,1\\) \\(S 5,1,12\\) \\(S 14,6,7\\) " + "\\(S 19,8,11\\) \\(S 22,11,10\\) \\(S 4,10,1\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 3 5 86 7 \\(D 0,1,1\\) \\(S 13,12,5\\) \\(S 9,3,4\\) \\(S 6,2,3\\) " + "\\(S 10,3,5\\) \\(S 11,5,6\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 4 5 53 7 \\(D 0,1,1\\) \\(S 15,12,6\\) \\(S 16,7,8\\) " + "\\(S 18,8,10\\) \\(S 20,10,9\\) \\(S 1,2,1\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 5 2 41 4 \\(D 0,1,1\\) \\(S 17,12,7\\) \\(S 3,7,1\\) \\(D 0,1,1\\)"; solution.SetName("Test name"); solution.WriteToSolutionFile(RoutingOutputFormat::kCARPLIB, file_name); std::string written_solution; CHECK_OK(file::GetContents(file_name, &written_solution, file::Defaults())); - EXPECT_EQ(written_solution, expected_output); + EXPECT_THAT(written_solution, MatchesRegex(expected_output)); } TEST(RoutingSolutionSerializerTest, NearpSolutionToCarplib) { const std::string expected_solution_output = - "0 1 1 5 76 7 (D 0,1,1) (S 12,5,11) (S 21,11,9) (S 8,9,9) (S 7,2,4) " - "(S 2,4,1) (D 0,1,1)\n" - "0 1 2 5 60 7 (D 0,1,1) (S 5,1,12) (S 14,6,7) (S 19,8,11) (S 22,11,10) " - "(S 4,10,1) (D 0,1,1)\n" - "0 1 3 5 86 7 (D 0,1,1) (S 13,12,5) (S 9,3,4) (S 6,2,3) (S 10,3,3) " - "(S 11,5,6) (D 0,1,1)\n" - "0 1 4 5 53 7 (D 0,1,1) (S 15,12,12) (S 16,12,8) (S 18,8,10) (S 20,10,9) " - "(S 1,2,1) (D 0,1,1)\n" - "0 1 5 2 41 4 (D 0,1,1) (S 17,12,12) (S 3,7,7) (D 0,1,1)"; + "0 1 1 5 76 7 \\(D 0,1,1\\) \\(S 12,5,11\\) \\(S 21,11,9\\) " + "\\(S 8,9,9\\) \\(S 7,2,4\\) \\(S 2,4,1\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 2 5 60 7 \\(D 0,1,1\\) \\(S 5,1,12\\) \\(S 14,6,7\\) " + "\\(S 19,8,11\\) \\(S 22,11,10\\) \\(S 4,10,1\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 3 5 86 7 \\(D 0,1,1\\) \\(S 13,12,5\\) \\(S 9,3,4\\) \\(S 6,2,3\\) " + "\\(S 10,3,3\\) \\(S 11,5,6\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 4 5 53 7 \\(D 0,1,1\\) \\(S 15,12,12\\) \\(S 16,12,8\\) " + "\\(S 18,8,10\\) \\(S 20,10,9\\) \\(S 1,2,1\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 5 2 41 4 \\(D 0,1,1\\) \\(S 17,12,12\\) \\(S 3,7,7\\) \\(D 0,1,1\\)"; const RoutingSolution solution = MakeTestEdgeNodeArcRoutingInstance(); - EXPECT_EQ(solution.SerializeToString(RoutingOutputFormat::kCARPLIB), - expected_solution_output); + EXPECT_THAT(solution.SerializeToString(RoutingOutputFormat::kCARPLIB), + MatchesRegex(expected_solution_output)); } TEST(RoutingSolutionSerializerTest, NearpSolutionToCarplibFile) { @@ -459,37 +472,37 @@ TEST(RoutingSolutionSerializerTest, NearpSolutionToCarplibFile) { RoutingSolution solution = MakeTestEdgeNodeArcRoutingInstance(); const std::string expected_output = - "7\n" - "5\n" - "30.840000\n" - "0 1 1 5 76 7 (D 0,1,1) (S 12,5,11) (S 21,11,9) (S 8,9,9) (S 7,2,4) " - "(S 2,4,1) (D 0,1,1)\n" - "0 1 2 5 60 7 (D 0,1,1) (S 5,1,12) (S 14,6,7) (S 19,8,11) (S 22,11,10) " - "(S 4,10,1) (D 0,1,1)\n" - "0 1 3 5 86 7 (D 0,1,1) (S 13,12,5) (S 9,3,4) (S 6,2,3) (S 10,3,3) " - "(S 11,5,6) (D 0,1,1)\n" - "0 1 4 5 53 7 (D 0,1,1) (S 15,12,12) (S 16,12,8) (S 18,8,10) (S 20,10,9) " - "(S 1,2,1) (D 0,1,1)\n" - "0 1 5 2 41 4 (D 0,1,1) (S 17,12,12) (S 3,7,7) (D 0,1,1)"; + "7\\r?\\n" + "5\\r?\\n" + "30.840000\\r?\\n" + "0 1 1 5 76 7 \\(D 0,1,1\\) \\(S 12,5,11\\) \\(S 21,11,9\\) " + "\\(S 8,9,9\\) \\(S 7,2,4\\) \\(S 2,4,1\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 2 5 60 7 \\(D 0,1,1\\) \\(S 5,1,12\\) \\(S 14,6,7\\) " + "\\(S 19,8,11\\) \\(S 22,11,10\\) \\(S 4,10,1\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 3 5 86 7 \\(D 0,1,1\\) \\(S 13,12,5\\) \\(S 9,3,4\\) \\(S 6,2,3\\) " + "\\(S 10,3,3\\) \\(S 11,5,6\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 4 5 53 7 \\(D 0,1,1\\) \\(S 15,12,12\\) \\(S 16,12,8\\) " + "\\(S 18,8,10\\) \\(S 20,10,9\\) \\(S 1,2,1\\) \\(D 0,1,1\\)\\r?\\n" + "0 1 5 2 41 4 \\(D 0,1,1\\) \\(S 17,12,12\\) \\(S 3,7,7\\) \\(D 0,1,1\\)"; solution.SetName("Test name"); solution.WriteToSolutionFile(RoutingOutputFormat::kCARPLIB, file_name); std::string written_solution; CHECK_OK(file::GetContents(file_name, &written_solution, file::Defaults())); - EXPECT_EQ(written_solution, expected_output); + EXPECT_THAT(written_solution, MatchesRegex(expected_output)); } TEST(RoutingSolutionSerializerTest, CarpSolutionToNearplib) { const std::string expected_solution_output = - "Route #1 : 1 5-A1-11-A2-9-A3-2-A4-4-A5-1\n" - "Route #2 : 1-A6-12 6-A7-7 8-A8-11-A9-10-A10-1\n" - "Route #3 : 1 12-A11-5 3-A12-4 2-A13-3-A14-5-A15-6 1\n" - "Route #4 : 1 12-A16-6 7-A17-8-A18-10-A19-9 2-A20-1\n" + "Route #1 : 1 5-A1-11-A2-9-A3-2-A4-4-A5-1\\r?\\n" + "Route #2 : 1-A6-12 6-A7-7 8-A8-11-A9-10-A10-1\\r?\\n" + "Route #3 : 1 12-A11-5 3-A12-4 2-A13-3-A14-5-A15-6 1\\r?\\n" + "Route #4 : 1 12-A16-6 7-A17-8-A18-10-A19-9 2-A20-1\\r?\\n" "Route #5 : 1 12-A21-7-A22-1"; const RoutingSolution solution = MakeTestArcRoutingInstance(); - EXPECT_EQ(solution.SerializeToString(RoutingOutputFormat::kNEARPLIB), - expected_solution_output); + EXPECT_THAT(solution.SerializeToString(RoutingOutputFormat::kNEARPLIB), + MatchesRegex(expected_solution_output)); } TEST(RoutingSolutionSerializerTest, CarpSolutionToNearplibFile) { @@ -500,18 +513,18 @@ TEST(RoutingSolutionSerializerTest, CarpSolutionToNearplibFile) { const std::string date = absl::FormatTime("%B %d, %E4Y", absl::Now(), absl::LocalTimeZone()); const std::string expected_output = - "Instance name: Test name\n" - "Authors: DIMACS CARP\n" + "Instance name: Test name\\r?\\n" + "Authors: DIMACS CARP\\r?\\n" "Date: " + date + - "\n" - "Reference: OR-Tools\n" - "Solution\n" - "Route #1 : 1 5-A1-11-A2-9-A3-2-A4-4-A5-1\n" - "Route #2 : 1-A6-12 6-A7-7 8-A8-11-A9-10-A10-1\n" - "Route #3 : 1 12-A11-5 3-A12-4 2-A13-3-A14-5-A15-6 1\n" - "Route #4 : 1 12-A16-6 7-A17-8-A18-10-A19-9 2-A20-1\n" - "Route #5 : 1 12-A21-7-A22-1\n" + "\\r?\\n" + "Reference: OR-Tools\\r?\\n" + "Solution\\r?\\n" + "Route #1 : 1 5-A1-11-A2-9-A3-2-A4-4-A5-1\\r?\\n" + "Route #2 : 1-A6-12 6-A7-7 8-A8-11-A9-10-A10-1\\r?\\n" + "Route #3 : 1 12-A11-5 3-A12-4 2-A13-3-A14-5-A15-6 1\\r?\\n" + "Route #4 : 1 12-A16-6 7-A17-8-A18-10-A19-9 2-A20-1\\r?\\n" + "Route #5 : 1 12-A21-7-A22-1\\r?\\n" "Total cost: 7"; solution.SetName("Test name"); solution.SetAuthors("DIMACS CARP"); @@ -519,15 +532,15 @@ TEST(RoutingSolutionSerializerTest, CarpSolutionToNearplibFile) { std::string written_solution; CHECK_OK(file::GetContents(file_name, &written_solution, file::Defaults())); - EXPECT_EQ(written_solution, expected_output); + EXPECT_THAT(written_solution, MatchesRegex(expected_output)); } TEST(RoutingSolutionSerializerTest, NearpSolutionToNearplib) { const std::string expected_solution_output = - "Route #1 : 1 5-E1-11-A2-9 N9 2-E3-4-A4-1\n" - "Route #2 : 1-E5-12 6-E6-7 8-E7-11-E8-10-E9-1\n" - "Route #3 : 1 12-A10-5 3-E11-4 2-A12-3 N3 5-E13-6 1\n" - "Route #4 : 1 N12-E14-8-E15-10-E16-9 2-E17-1\n" + "Route #1 : 1 5-E1-11-A2-9 N9 2-E3-4-A4-1\\r?\\n" + "Route #2 : 1-E5-12 6-E6-7 8-E7-11-E8-10-E9-1\\r?\\n" + "Route #3 : 1 12-A10-5 3-E11-4 2-A12-3 N3 5-E13-6 1\\r?\\n" + "Route #4 : 1 N12-E14-8-E15-10-E16-9 2-E17-1\\r?\\n" "Route #5 : 1 N12 N7 1"; // TODO(user): the following output would be ideal (because shorter). It // would be achieved by implementing the relevant TODO in @@ -536,8 +549,8 @@ TEST(RoutingSolutionSerializerTest, NearpSolutionToNearplib) { // Route #3 : 1 12-A10-5 3-E11-4 2-A12-N3 5-E13-6 1 const RoutingSolution solution = MakeTestEdgeNodeArcRoutingInstance(); - EXPECT_EQ(solution.SerializeToString(RoutingOutputFormat::kNEARPLIB), - expected_solution_output); + EXPECT_THAT(solution.SerializeToString(RoutingOutputFormat::kNEARPLIB), + MatchesRegex(expected_solution_output)); } TEST(RoutingSolutionSerializerTest, NearpSolutionToNearplibFile) { @@ -548,18 +561,18 @@ TEST(RoutingSolutionSerializerTest, NearpSolutionToNearplibFile) { const std::string date = absl::FormatTime("%B %d, %E4Y", absl::Now(), absl::LocalTimeZone()); const std::string expected_output = - "Instance name: Test name\n" - "Authors: Based on DIMACS CARP\n" + "Instance name: Test name\\r?\\n" + "Authors: Based on DIMACS CARP\\r?\\n" "Date: " + date + - "\n" - "Reference: OR-Tools\n" - "Solution\n" - "Route #1 : 1 5-E1-11-A2-9 N9 2-E3-4-A4-1\n" - "Route #2 : 1-E5-12 6-E6-7 8-E7-11-E8-10-E9-1\n" - "Route #3 : 1 12-A10-5 3-E11-4 2-A12-3 N3 5-E13-6 1\n" - "Route #4 : 1 N12-E14-8-E15-10-E16-9 2-E17-1\n" - "Route #5 : 1 N12 N7 1\n" + "\\r?\\n" + "Reference: OR-Tools\\r?\\n" + "Solution\\r?\\n" + "Route #1 : 1 5-E1-11-A2-9 N9 2-E3-4-A4-1\\r?\\n" + "Route #2 : 1-E5-12 6-E6-7 8-E7-11-E8-10-E9-1\\r?\\n" + "Route #3 : 1 12-A10-5 3-E11-4 2-A12-3 N3 5-E13-6 1\\r?\\n" + "Route #4 : 1 N12-E14-8-E15-10-E16-9 2-E17-1\\r?\\n" + "Route #5 : 1 N12 N7 1\\r?\\n" "Total cost: 7"; solution.SetName("Test name"); solution.SetAuthors("Based on DIMACS CARP"); @@ -567,7 +580,7 @@ TEST(RoutingSolutionSerializerTest, NearpSolutionToNearplibFile) { std::string written_solution; CHECK_OK(file::GetContents(file_name, &written_solution, file::Defaults())); - EXPECT_EQ(written_solution, expected_output); + EXPECT_THAT(written_solution, MatchesRegex(expected_output)); } TEST(RoutingSolutionSerializerTest, FormatStatisticAsTsplib) {