switch flags setters and getters to the absl format

This commit is contained in:
Laurent Perron
2020-10-21 00:21:54 +02:00
parent 1bf7ccf721
commit a4258f2bdf
527 changed files with 48384 additions and 45461 deletions

View File

@@ -1,524 +1,282 @@
cc_binary(
name = "constraint_programming_cp",
srcs = ["constraint_programming_cp.cc"],
deps = [
"//ortools/base",
"//ortools/constraint_solver:cp",
],
)
cc_binary(name = "constraint_programming_cp",
srcs = ["constraint_programming_cp.cc"],
deps = ["//ortools/base", "//ortools/constraint_solver:cp", ], )
cc_binary(
name = "costas_array_sat",
srcs = ["costas_array_sat.cc"],
deps = [
"//ortools/base",
"//ortools/base:random",
"//ortools/sat:cp_model",
"//ortools/sat:model",
],
)
cc_binary(name = "costas_array_sat", srcs = ["costas_array_sat.cc"],
deps = ["//ortools/base",
"//ortools/base:random", "//ortools/sat:cp_model",
"//ortools/sat:model",
], )
cc_library(
name = "cvrptw_lib",
hdrs = ["cvrptw_lib.h"],
deps = [
"//ortools/base",
"//ortools/base:random",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
],
)
name = "cvrptw_lib", hdrs = ["cvrptw_lib.h"],
deps = ["//ortools/base",
"//ortools/base:random", "//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
], )
cc_binary(
name = "cvrptw",
srcs = ["cvrptw.cc"],
deps = [
":cvrptw_lib",
"//ortools/base",
"//ortools/base:random",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
],
)
cc_binary(name = "cvrptw", srcs = ["cvrptw.cc"],
deps = [":cvrptw_lib",
"//ortools/base", "//ortools/base:random",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
], )
cc_binary(
name = "cvrp_disjoint_tw",
srcs = ["cvrp_disjoint_tw.cc"],
deps = [
":cvrptw_lib",
"//ortools/base",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
],
)
cc_binary(name = "cvrp_disjoint_tw", srcs = ["cvrp_disjoint_tw.cc"],
deps = [":cvrptw_lib",
"//ortools/base", "//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
], )
cc_binary(
name = "cvrptw_with_breaks",
srcs = ["cvrptw_with_breaks.cc"],
deps = [
":cvrptw_lib",
"//ortools/base",
"//ortools/base:random",
"@com_google_absl//absl/strings",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_enums_cc_proto",
"//ortools/constraint_solver:routing_flags",
],
)
cc_binary(name = "cvrptw_with_breaks", srcs = ["cvrptw_with_breaks.cc"],
deps = [":cvrptw_lib",
"//ortools/base", "//ortools/base:random",
"@com_google_absl//absl/strings",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_enums_cc_proto",
"//ortools/constraint_solver:routing_flags",
], )
cc_binary(
name = "cvrptw_with_resources",
srcs = ["cvrptw_with_resources.cc"],
deps = [
":cvrptw_lib",
"//ortools/base",
"//ortools/base:random",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
],
)
cc_binary(name = "cvrptw_with_resources", srcs = ["cvrptw_with_resources.cc"],
deps = [":cvrptw_lib",
"//ortools/base", "//ortools/base:random",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
], )
cc_binary(
name = "cvrptw_with_stop_times_and_resources",
srcs = ["cvrptw_with_stop_times_and_resources.cc"],
deps = [
":cvrptw_lib",
"//ortools/base",
"//ortools/base:random",
"@com_google_absl//absl/strings",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
],
)
cc_binary(name = "cvrptw_with_stop_times_and_resources",
srcs = ["cvrptw_with_stop_times_and_resources.cc"],
deps = [":cvrptw_lib",
"//ortools/base", "//ortools/base:random",
"@com_google_absl//absl/strings",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
], )
cc_binary(
name = "cvrptw_with_refueling",
srcs = ["cvrptw_with_refueling.cc"],
deps = [
":cvrptw_lib",
"//ortools/base",
"//ortools/base:random",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
],
)
cc_binary(name = "cvrptw_with_refueling", srcs = ["cvrptw_with_refueling.cc"],
deps = [":cvrptw_lib",
"//ortools/base", "//ortools/base:random",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
], )
cc_library(
name = "print_dimacs_assignment",
hdrs = ["print_dimacs_assignment.h"],
deps = [
"//ortools/base",
"//ortools/base:file",
"@com_google_absl//absl/status",
"//ortools/graph:ebert_graph",
"//ortools/graph:linear_assignment",
],
)
name = "print_dimacs_assignment", hdrs = ["print_dimacs_assignment.h"],
deps = ["//ortools/base",
"//ortools/base:file", "@com_google_absl//absl/status",
"//ortools/graph:ebert_graph", "//ortools/graph:linear_assignment",
], )
cc_library(
name = "parse_dimacs_assignment",
hdrs = ["parse_dimacs_assignment.h"],
deps = [
"//ortools/base",
"//ortools/base:filelineiter",
"//ortools/graph:ebert_graph",
"//ortools/graph:linear_assignment",
],
)
cc_library(name = "parse_dimacs_assignment",
hdrs = ["parse_dimacs_assignment.h"],
deps = ["//ortools/base",
"//ortools/base:filelineiter", "//ortools/graph:ebert_graph",
"//ortools/graph:linear_assignment",
], )
cc_binary(
name = "dimacs_assignment",
srcs = ["dimacs_assignment.cc"],
deps = [
":parse_dimacs_assignment",
":print_dimacs_assignment",
"//ortools/algorithms:hungarian",
"//ortools/base",
"//ortools/base:timer",
"//ortools/graph:ebert_graph",
"//ortools/graph:linear_assignment",
],
)
name = "dimacs_assignment", srcs = ["dimacs_assignment.cc"],
deps = [":parse_dimacs_assignment",
":print_dimacs_assignment", "//ortools/algorithms:hungarian",
"//ortools/base", "//ortools/base:timer",
"//ortools/graph:ebert_graph", "//ortools/graph:linear_assignment",
], )
cc_binary(name = "dobble_ls", srcs = ["dobble_ls.cc"],
deps = ["//ortools/base",
"//ortools/base:map_util", "//ortools/base:random",
"//ortools/constraint_solver:cp", "//ortools/util:bitset",
], )
cc_binary(name = "flow_api", srcs = ["flow_api.cc"],
deps = ["//ortools/base",
"//ortools/graph:ebert_graph", "//ortools/graph:max_flow",
"//ortools/graph:min_cost_flow",
], )
cc_library(name = "fap_parser", hdrs = ["fap_parser.h"],
deps = ["//ortools/base",
"//ortools/base:file", "//ortools/base:hash",
"//ortools/base:map_util", "@com_google_absl//absl/strings",
], )
cc_library(name = "fap_model_printer", hdrs = ["fap_model_printer.h"],
deps = [":fap_parser",
"//ortools/base", "//ortools/base:file",
"@com_google_absl//absl/strings",
], )
cc_library(name = "fap_utilities", hdrs = ["fap_utilities.h"],
deps = [":fap_parser",
"//ortools/base", "//ortools/base:map_util",
"//ortools/constraint_solver:cp",
], )
cc_binary(name = "frequency_assignment_problem",
srcs = ["frequency_assignment_problem.cc"],
deps = [":fap_model_printer",
":fap_parser", ":fap_utilities", "//ortools/base",
"//ortools/base:map_util", "//ortools/constraint_solver:cp",
], )
cc_binary(name = "golomb_sat", srcs = ["golomb_sat.cc"],
deps = ["//ortools/base",
"@com_google_absl//absl/strings", "//ortools/sat:cp_model",
"//ortools/sat:model",
], )
cc_binary(name = "integer_programming", srcs = ["integer_programming.cc"],
deps = ["//ortools/base", "//ortools/linear_solver", ], )
cc_binary(name = "jobshop_sat", srcs = ["jobshop_sat.cc", ],
deps = ["//ortools/base",
"//ortools/base:file", "@com_google_absl//absl/strings",
"//ortools/base:timer",
"//ortools/data:jobshop_scheduling_cc_proto",
"//ortools/data:jobshop_scheduling_parser",
"//ortools/sat:cp_model", "//ortools/sat:cp_model_solver",
"//ortools/sat:disjunctive", "//ortools/sat:integer",
"//ortools/sat:intervals", "//ortools/sat:model",
"//ortools/sat:optimization", "//ortools/sat:precedences",
"//ortools/sat:sat_solver",
], )
cc_binary(
name = "dobble_ls",
srcs = ["dobble_ls.cc"],
deps = [
"//ortools/base",
"//ortools/base:map_util",
"//ortools/base:random",
"//ortools/constraint_solver:cp",
"//ortools/util:bitset",
],
)
name = "linear_assignment_api", srcs = ["linear_assignment_api.cc"],
deps = ["//ortools/base",
"//ortools/graph:ebert_graph", "//ortools/graph:linear_assignment",
], )
cc_binary(name = "linear_programming", srcs = ["linear_programming.cc"],
deps = ["//ortools/base",
"//ortools/linear_solver",
"//ortools/linear_solver:linear_solver_cc_proto",
], )
cc_binary(name = "linear_solver_protocol_buffers",
srcs = ["linear_solver_protocol_buffers.cc"],
deps = ["//ortools/base",
"//ortools/linear_solver",
"//ortools/linear_solver:linear_solver_cc_proto",
], )
cc_binary(name = "magic_square_sat", srcs = ["magic_square_sat.cc"],
deps = ["//ortools/base",
"@com_google_absl//absl/strings", "//ortools/sat:cp_model",
"//ortools/sat:model",
], )
cc_binary(name = "max_flow", srcs = ["max_flow.cc"],
deps = ["//ortools/base", "//ortools/graph:max_flow", ], )
cc_binary(name = "min_cost_flow", srcs = ["min_cost_flow.cc"],
deps = ["//ortools/base", "//ortools/graph:min_cost_flow", ], )
cc_binary(
name = "flow_api",
srcs = ["flow_api.cc"],
deps = [
"//ortools/base",
"//ortools/graph:ebert_graph",
"//ortools/graph:max_flow",
"//ortools/graph:min_cost_flow",
],
)
name = "mps_driver", srcs = ["mps_driver.cc"],
deps = ["//ortools/base",
"@com_google_absl//absl/strings", "//ortools/base:timer",
"//ortools/glop:lp_solver", "//ortools/glop:parameters_cc_proto",
"//ortools/lp_data:mps_reader", "//ortools/util:proto_tools",
"@com_google_protobuf//:protobuf",
], )
cc_library(
name = "fap_parser",
hdrs = ["fap_parser.h"],
deps = [
"//ortools/base",
"//ortools/base:file",
"//ortools/base:hash",
"//ortools/base:map_util",
"@com_google_absl//absl/strings",
],
)
cc_binary(name = "network_routing_sat", srcs = ["network_routing_sat.cc"],
deps = ["//ortools/base",
"//ortools/base:hash", "//ortools/base:map_util",
"//ortools/base:random", "@com_google_absl//absl/strings",
"//ortools/graph:shortestpaths", "//ortools/sat:cp_model",
"//ortools/sat:model", "//ortools/util:tuple_set",
], )
cc_library(
name = "fap_model_printer",
hdrs = ["fap_model_printer.h"],
deps = [
":fap_parser",
"//ortools/base",
"//ortools/base:file",
"@com_google_absl//absl/strings",
],
)
cc_binary(name = "nqueens", srcs = ["nqueens.cc"],
deps = ["//ortools/base",
"//ortools/base:map_util", "//ortools/constraint_solver:cp",
], )
cc_library(
name = "fap_utilities",
hdrs = ["fap_utilities.h"],
deps = [
":fap_parser",
"//ortools/base",
"//ortools/base:map_util",
"//ortools/constraint_solver:cp",
],
)
cc_binary(name = "pdptw", srcs = ["pdptw.cc"],
deps = ["//ortools/base",
"//ortools/base:file", "//ortools/base:mathutil",
"@com_google_absl//absl/strings",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
], )
cc_binary(
name = "frequency_assignment_problem",
srcs = ["frequency_assignment_problem.cc"],
deps = [
":fap_model_printer",
":fap_parser",
":fap_utilities",
"//ortools/base",
"//ortools/base:map_util",
"//ortools/constraint_solver:cp",
],
)
cc_binary(
name = "golomb_sat",
srcs = ["golomb_sat.cc"],
deps = [
"//ortools/base",
"@com_google_absl//absl/strings",
"//ortools/sat:cp_model",
"//ortools/sat:model",
],
)
cc_binary(
name = "integer_programming",
srcs = ["integer_programming.cc"],
deps = [
"//ortools/base",
"//ortools/linear_solver",
],
)
cc_binary(
name = "jobshop_sat",
srcs = [
"jobshop_sat.cc",
],
deps = [
"//ortools/base",
"//ortools/base:file",
"@com_google_absl//absl/strings",
"//ortools/base:timer",
"//ortools/data:jobshop_scheduling_cc_proto",
"//ortools/data:jobshop_scheduling_parser",
"//ortools/sat:cp_model",
"//ortools/sat:cp_model_solver",
"//ortools/sat:disjunctive",
"//ortools/sat:integer",
"//ortools/sat:intervals",
"//ortools/sat:model",
"//ortools/sat:optimization",
"//ortools/sat:precedences",
"//ortools/sat:sat_solver",
],
)
cc_binary(
name = "linear_assignment_api",
srcs = ["linear_assignment_api.cc"],
deps = [
"//ortools/base",
"//ortools/graph:ebert_graph",
"//ortools/graph:linear_assignment",
],
)
cc_binary(
name = "linear_programming",
srcs = ["linear_programming.cc"],
deps = [
"//ortools/base",
"//ortools/linear_solver",
"//ortools/linear_solver:linear_solver_cc_proto",
],
)
cc_binary(
name = "linear_solver_protocol_buffers",
srcs = ["linear_solver_protocol_buffers.cc"],
deps = [
"//ortools/base",
"//ortools/linear_solver",
"//ortools/linear_solver:linear_solver_cc_proto",
],
)
cc_binary(
name = "magic_square_sat",
srcs = ["magic_square_sat.cc"],
deps = [
"//ortools/base",
"@com_google_absl//absl/strings",
"//ortools/sat:cp_model",
"//ortools/sat:model",
],
)
cc_binary(
name = "max_flow",
srcs = ["max_flow.cc"],
deps = [
"//ortools/base",
"//ortools/graph:max_flow",
],
)
cc_binary(
name = "min_cost_flow",
srcs = ["min_cost_flow.cc"],
deps = [
"//ortools/base",
"//ortools/graph:min_cost_flow",
],
)
cc_binary(
name = "mps_driver",
srcs = ["mps_driver.cc"],
deps = [
"//ortools/base",
"@com_google_absl//absl/strings",
"//ortools/base:timer",
"//ortools/glop:lp_solver",
"//ortools/glop:parameters_cc_proto",
"//ortools/lp_data:mps_reader",
"//ortools/util:proto_tools",
"@com_google_protobuf//:protobuf",
],
)
cc_binary(
name = "network_routing_sat",
srcs = ["network_routing_sat.cc"],
deps = [
"//ortools/base",
"//ortools/base:hash",
"//ortools/base:map_util",
"//ortools/base:random",
"@com_google_absl//absl/strings",
"//ortools/graph:shortestpaths",
"//ortools/sat:cp_model",
"//ortools/sat:model",
"//ortools/util:tuple_set",
],
)
cc_binary(
name = "nqueens",
srcs = ["nqueens.cc"],
deps = [
"//ortools/base",
"//ortools/base:map_util",
"//ortools/constraint_solver:cp",
],
)
cc_binary(
name = "pdptw",
srcs = ["pdptw.cc"],
deps = [
"//ortools/base",
"//ortools/base:file",
"//ortools/base:mathutil",
"@com_google_absl//absl/strings",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
],
)
cc_binary(
name = "random_tsp",
srcs = ["random_tsp.cc"],
deps = [
"//ortools/base",
"//ortools/base:random",
"@com_google_absl//absl/strings",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
"@com_google_protobuf//:protobuf",
],
)
cc_binary(name = "random_tsp", srcs = ["random_tsp.cc"],
deps = ["//ortools/base",
"//ortools/base:random", "@com_google_absl//absl/strings",
"//ortools/constraint_solver:routing",
"//ortools/constraint_solver:routing_flags",
"@com_google_protobuf//:protobuf",
], )
cc_binary(
name = "sat_runner",
srcs = [
"opb_reader.h",
"sat_cnf_reader.h",
"sat_runner.cc",
],
deps = [
"//ortools/algorithms:sparse_permutation",
"//ortools/base",
"//ortools/base:file",
"//ortools/base:filelineiter",
"//ortools/base:random",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"//ortools/base:threadpool",
"//ortools/lp_data:mps_reader",
"//ortools/lp_data:proto_utils",
"//ortools/sat:boolean_problem",
"//ortools/sat:boolean_problem_cc_proto",
"//ortools/sat:cp_model_cc_proto",
"//ortools/sat:cp_model_solver",
"//ortools/sat:drat_proof_handler",
"//ortools/sat:lp_utils",
"//ortools/sat:optimization",
"//ortools/sat:sat_solver",
"//ortools/sat:simplification",
"//ortools/sat:symmetry",
"//ortools/util:sigint",
"//ortools/util:time_limit",
"@com_google_protobuf//:protobuf",
],
)
srcs = ["opb_reader.h", "sat_cnf_reader.h", "sat_runner.cc", ],
deps = ["//ortools/algorithms:sparse_permutation",
"//ortools/base", "//ortools/base:file",
"//ortools/base:filelineiter", "//ortools/base:random",
"@com_google_absl//absl/status", "@com_google_absl//absl/strings",
"//ortools/base:threadpool", "//ortools/lp_data:mps_reader",
"//ortools/lp_data:proto_utils", "//ortools/sat:boolean_problem",
"//ortools/sat:boolean_problem_cc_proto",
"//ortools/sat:cp_model_cc_proto", "//ortools/sat:cp_model_solver",
"//ortools/sat:drat_proof_handler", "//ortools/sat:lp_utils",
"//ortools/sat:optimization", "//ortools/sat:sat_solver",
"//ortools/sat:simplification", "//ortools/sat:symmetry",
"//ortools/util:sigint", "//ortools/util:time_limit",
"@com_google_protobuf//:protobuf",
], )
cc_binary(name = "shift_minimization_sat",
srcs = ["shift_minimization_sat.cc", ],
deps = ["//ortools/base",
"//ortools/base:file", "//ortools/base:filelineiter",
"@com_google_absl//absl/strings", "//ortools/sat:cp_model",
"//ortools/sat:model",
], )
cc_binary(
name = "shift_minimization_sat",
srcs = [
"shift_minimization_sat.cc",
],
deps = [
"//ortools/base",
"//ortools/base:file",
"//ortools/base:filelineiter",
"@com_google_absl//absl/strings",
"//ortools/sat:cp_model",
"//ortools/sat:model",
],
)
name = "slitherlink_sat", srcs = ["slitherlink_sat.cc"],
deps =
["//ortools/base", "//ortools/sat:cp_model", "//ortools/sat:model", ], )
cc_binary(
name = "slitherlink_sat",
srcs = ["slitherlink_sat.cc"],
deps = [
"//ortools/base",
"//ortools/sat:cp_model",
"//ortools/sat:model",
],
)
name = "solve", srcs = ["solve.cc"],
deps = ["//ortools/base",
"//ortools/linear_solver",
"//ortools/linear_solver:linear_solver_cc_proto",
"//ortools/lp_data:model_reader", "//ortools/lp_data:mps_reader",
], )
cc_binary(
name = "solve",
srcs = ["solve.cc"],
deps = [
"//ortools/base",
"//ortools/linear_solver",
"//ortools/linear_solver:linear_solver_cc_proto",
"//ortools/lp_data:model_reader",
"//ortools/lp_data:mps_reader",
],
)
cc_binary(name = "sports_scheduling_sat", srcs = ["sports_scheduling_sat.cc"],
deps = ["//ortools/base",
"@com_google_absl//absl/strings", "//ortools/sat:cp_model",
"//ortools/sat:model",
], )
cc_binary(
name = "sports_scheduling_sat",
srcs = ["sports_scheduling_sat.cc"],
deps = [
"//ortools/base",
"@com_google_absl//absl/strings",
"//ortools/sat:cp_model",
"//ortools/sat:model",
],
)
cc_binary(name = "stigler_diet", srcs = ["stigler_diet.cc"],
deps = ["//ortools/base", "//ortools/linear_solver", ], )
cc_binary(
name = "stigler_diet",
srcs = ["stigler_diet.cc"],
deps = [
"//ortools/base",
"//ortools/linear_solver",
],
)
cc_binary(name = "strawberry_fields_with_column_generation",
srcs = ["strawberry_fields_with_column_generation.cc"],
deps = ["//ortools/base", "//ortools/linear_solver", ], )
cc_binary(
name = "strawberry_fields_with_column_generation",
srcs = ["strawberry_fields_with_column_generation.cc"],
deps = [
"//ortools/base",
"//ortools/linear_solver",
],
)
cc_binary(name = "uncapacitated_facility_location",
srcs = ["uncapacitated_facility_location.cc"],
deps = ["//ortools/base", "//ortools/linear_solver", ], )
cc_binary(
name = "uncapacitated_facility_location",
srcs = ["uncapacitated_facility_location.cc"],
deps = [
"//ortools/base",
"//ortools/linear_solver",
],
)
cc_binary(name = "variable_intervals_sat", srcs = ["variable_intervals_sat.cc"],
deps = ["//ortools/sat:cp_model", "//ortools/util:time_limit", ], )
cc_binary(
name = "variable_intervals_sat",
srcs = ["variable_intervals_sat.cc"],
deps = [
"//ortools/sat:cp_model",
"//ortools/util:time_limit",
],
)
cc_binary(
name = "weighted_tardiness_sat",
srcs = [
"weighted_tardiness_sat.cc",
],
deps = [
"//ortools/base",
"//ortools/base:file",
"//ortools/base:filelineiter",
"@com_google_absl//absl/strings",
"//ortools/sat:cp_model",
"//ortools/sat:cp_model_solver",
"//ortools/sat:disjunctive",
"//ortools/sat:integer",
"//ortools/sat:integer_expr",
"//ortools/sat:intervals",
"//ortools/sat:model",
"//ortools/sat:optimization",
"//ortools/sat:precedences",
"//ortools/sat:sat_solver",
"@com_google_protobuf//:protobuf",
],
)
cc_binary(name = "weighted_tardiness_sat",
srcs = ["weighted_tardiness_sat.cc", ],
deps = ["//ortools/base",
"//ortools/base:file", "//ortools/base:filelineiter",
"@com_google_absl//absl/strings", "//ortools/sat:cp_model",
"//ortools/sat:cp_model_solver", "//ortools/sat:disjunctive",
"//ortools/sat:integer", "//ortools/sat:integer_expr",
"//ortools/sat:intervals", "//ortools/sat:model",
"//ortools/sat:optimization", "//ortools/sat:precedences",
"//ortools/sat:sat_solver", "@com_google_protobuf//:protobuf",
], )

View File

@@ -1,91 +1,66 @@
if(NOT BUILD_CXX_EXAMPLES)
return()
endif()
if(APPLE)
set(CMAKE_INSTALL_RPATH
"@loader_path/../${CMAKE_INSTALL_LIBDIR};@loader_path")
elseif(UNIX)
set(CMAKE_INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:$ORIGIN")
endif()
include(GNUInstallDirs)
foreach(EXECUTABLE IN ITEMS
constraint_programming_cp
costas_array_sat
cvrp_disjoint_tw
cvrptw
cvrptw_with_breaks
cvrptw_with_refueling
cvrptw_with_resources
cvrptw_with_stop_times_and_resources
dimacs_assignment
dobble_ls
flow_api
frequency_assignment_problem
golomb_sat
integer_programming
jobshop_sat
linear_assignment_api
linear_programming
linear_solver_protocol_buffers
magic_square_sat
max_flow
min_cost_flow
mps_driver
network_routing_sat
nqueens
pdptw
random_tsp
shift_minimization_sat
slitherlink_sat
solve
sports_scheduling_sat
stigler_diet
strawberry_fields_with_column_generation
uncapacitated_facility_location
variable_intervals_sat
weighted_tardiness_sat)
add_executable(${EXECUTABLE} ${EXECUTABLE}.cc)
target_include_directories(${EXECUTABLE} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_features(${EXECUTABLE} PRIVATE cxx_std_17)
target_link_libraries(${EXECUTABLE} PRIVATE ortools::ortools)
install(TARGETS ${EXECUTABLE})
endforeach()
foreach(TEST IN ITEMS
costas_array_sat
cvrp_disjoint_tw
cvrptw
#cvrptw_with_breaks # Too long
#cvrptw_with_refueling # Too long
cvrptw_with_resources
cvrptw_with_stop_times_and_resources
#dimacs_assignment
#dobble_ls # Too long
flow_api
#frequency_assignment_problem
golomb_sat
integer_programming
#jobshop_sat
knapsack
linear_assignment_api
linear_programming
linear_solver_protocol_buffers
magic_square_sat
#mps_driver
#network_routing_sat
nqueens
#pdptw
#rcpsp_sat
#shift_minimization_sat
#solve
#sports_scheduling_sat # Too long
#stigler_diet
#strawberry_fields_with_column_generation # Too long
uncapacitated_facility_location
#variable_intervals_sat
#weighted_tardiness_sat
)
add_test(NAME cxx_${TEST} COMMAND ${TEST})
endforeach()
if (NOT BUILD_CXX_EXAMPLES)
return () endif() if (APPLE)
set(CMAKE_INSTALL_RPATH
"@loader_path/../${CMAKE_INSTALL_LIBDIR};@loader_path") elseif(UNIX)
set(CMAKE_INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:$ORIGIN")
endif() include(GNUInstallDirs) foreach(
EXECUTABLE IN ITEMS constraint_programming_cp costas_array_sat cvrp_disjoint_tw
cvrptw cvrptw_with_breaks cvrptw_with_refueling cvrptw_with_resources
cvrptw_with_stop_times_and_resources dimacs_assignment dobble_ls
flow_api frequency_assignment_problem golomb_sat
integer_programming jobshop_sat linear_assignment_api
linear_programming linear_solver_protocol_buffers
magic_square_sat max_flow min_cost_flow mps_driver
network_routing_sat nqueens pdptw random_tsp
shift_minimization_sat slitherlink_sat
solve sports_scheduling_sat stigler_diet
strawberry_fields_with_column_generation
uncapacitated_facility_location
variable_intervals_sat
weighted_tardiness_sat)
add_executable($ {
EXECUTABLE
} $ {
EXECUTABLE
}
.cc) target_include_directories($ {
EXECUTABLE
} PUBLIC $ {
CMAKE_CURRENT_SOURCE_DIR
}) target_compile_features($ {
EXECUTABLE
} PRIVATE cxx_std_17) target_link_libraries($ {
EXECUTABLE
} PRIVATE ortools::ortools) install(TARGETS $ {
EXECUTABLE
}) endforeach()
foreach(TEST IN ITEMS costas_array_sat cvrp_disjoint_tw cvrptw
#cvrptw_with_breaks #Too long
#cvrptw_with_refueling #Too long
cvrptw_with_resources cvrptw_with_stop_times_and_resources
#dimacs_assignment
#dobble_ls #Too long
flow_api
#frequency_assignment_problem
golomb_sat integer_programming
#jobshop_sat
knapsack linear_assignment_api linear_programming
linear_solver_protocol_buffers magic_square_sat
#mps_driver
#network_routing_sat
nqueens
#pdptw
#rcpsp_sat
#shift_minimization_sat
#solve
#sports_scheduling_sat #Too long
#stigler_diet
#strawberry_fields_with_column_generation #Too long
uncapacitated_facility_location
#variable_intervals_sat
#weighted_tardiness_sat
) add_test(NAME cxx_$ {
TEST
} COMMAND $ {
TEST
}) endforeach()

View File

@@ -1,4 +1,4 @@
# C++ examples
#C++ examples
The following examples showcase how to use the different Operations Research libraries.
## Examples list
@@ -55,10 +55,9 @@ The following examples showcase how to use the different Operations Research lib
- model_util.cc A utility to manipulate model files (.cp) dumped by the
solver.
# Execution
#Execution
Running the examples will involve building them, then running them.
You can run the following command from the **top** directory:
```shell
make build SOURCE=examples/cpp/<example>.cc
make run SOURCE=examples/cpp/<example>.cc
```

View File

@@ -23,19 +23,19 @@ void RunConstraintProgrammingExample() {
const int64 numVals = 3;
// Define decision variables.
IntVar* const x = solver.MakeIntVar(0, numVals - 1, "x");
IntVar* const y = solver.MakeIntVar(0, numVals - 1, "y");
IntVar* const z = solver.MakeIntVar(0, numVals - 1, "z");
IntVar *const x = solver.MakeIntVar(0, numVals - 1, "x");
IntVar *const y = solver.MakeIntVar(0, numVals - 1, "y");
IntVar *const z = solver.MakeIntVar(0, numVals - 1, "z");
// Define constraints.
std::vector<IntVar*> xyvars = {x, y};
std::vector<IntVar *> xyvars = { x, y };
solver.AddConstraint(solver.MakeAllDifferent(xyvars));
LOG(INFO) << "Number of constraints: " << solver.constraints();
// Create decision builder to search for solutions.
std::vector<IntVar*> allvars = {x, y, z};
DecisionBuilder* const db = solver.MakePhase(
std::vector<IntVar *> allvars = { x, y, z };
DecisionBuilder *const db = solver.MakePhase(
allvars, Solver::CHOOSE_FIRST_UNBOUND, Solver::ASSIGN_MIN_VALUE);
solver.NewSearch(db);
@@ -51,11 +51,11 @@ void RunConstraintProgrammingExample() {
LOG(INFO) << "Problem solved in " << solver.wall_time() << "ms";
LOG(INFO) << "Memory usage: " << Solver::MemoryUsage() << " bytes";
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
google::InitGoogleLogging(argv[0]);
FLAGS_logtostderr = 1;
absl::GetFlag(FLAGS_logtostderr) = 1;
operations_research::RunConstraintProgrammingExample();
return EXIT_SUCCESS;
}

View File

@@ -93,8 +93,8 @@ void CostasHard(const int dim) {
std::vector<IntVar> vars;
Domain domain(1, dim);
for (int i = 0; i < dim; ++i) {
vars.push_back(
cp_model.NewIntVar(domain).WithName(absl::StrCat("var_", i)));
vars.push_back(cp_model.NewIntVar(domain)
.WithName(absl::StrCat("var_", i)));
}
cp_model.AddAllDifferent(vars);
@@ -106,15 +106,18 @@ void CostasHard(const int dim) {
for (int j = 0; j < dim - i; ++j) {
subset.push_back(cp_model.NewIntVar(diff));
cp_model.AddEquality(LinearExpr::Sum({subset[j], vars[j]}), vars[j + i]);
cp_model.AddEquality(LinearExpr::Sum({
subset[j], vars[j]
}),
vars[j + i]);
}
cp_model.AddAllDifferent(subset);
}
Model model;
if (!FLAGS_params.empty()) {
model.Add(NewSatParameters(FLAGS_params));
if (!absl::GetFlag(FLAGS_params).empty()) {
model.Add(NewSatParameters(absl::GetFlag(FLAGS_params)));
}
const CpSolverResponse response = SolveCpModel(cp_model.Build(), &model);
@@ -142,8 +145,8 @@ void CostasBool(const int dim) {
CpModelBuilder cp_model;
// create the variables
std::vector<std::vector<BoolVar>> vars(dim);
std::vector<std::vector<BoolVar>> transposed_vars(dim);
std::vector<std::vector<BoolVar> > vars(dim);
std::vector<std::vector<BoolVar> > transposed_vars(dim);
for (int i = 0; i < dim; ++i) {
for (int j = 0; j < dim; ++j) {
const BoolVar var = cp_model.NewBoolVar();
@@ -168,10 +171,12 @@ void CostasBool(const int dim) {
const BoolVar neg = cp_model.NewBoolVar();
positive_diffs.push_back(pos);
negative_diffs.push_back(neg);
cp_model.AddBoolOr({Not(vars[var][value]),
Not(vars[var + step][value + diff]), pos});
cp_model.AddBoolOr({Not(vars[var][value + diff]),
Not(vars[var + step][value]), neg});
cp_model.AddBoolOr({
Not(vars[var][value]), Not(vars[var + step][value + diff]), pos
});
cp_model.AddBoolOr({
Not(vars[var][value + diff]), Not(vars[var + step][value]), neg
});
}
}
cp_model.AddLessOrEqual(LinearExpr::BooleanSum(positive_diffs), 1);
@@ -180,8 +185,8 @@ void CostasBool(const int dim) {
}
Model model;
if (!FLAGS_params.empty()) {
model.Add(NewSatParameters(FLAGS_params));
if (!absl::GetFlag(FLAGS_params).empty()) {
model.Add(NewSatParameters(absl::GetFlag(FLAGS_params)));
}
const CpSolverResponse response = SolveCpModel(cp_model.Build(), &model);
@@ -213,8 +218,8 @@ void CostasBoolSoft(const int dim) {
CpModelBuilder cp_model;
// create the variables
std::vector<std::vector<BoolVar>> vars(dim);
std::vector<std::vector<BoolVar>> transposed_vars(dim);
std::vector<std::vector<BoolVar> > vars(dim);
std::vector<std::vector<BoolVar> > transposed_vars(dim);
for (int i = 0; i < dim; ++i) {
for (int j = 0; j < dim; ++j) {
const BoolVar var = cp_model.NewBoolVar();
@@ -240,10 +245,12 @@ void CostasBoolSoft(const int dim) {
const BoolVar neg = cp_model.NewBoolVar();
positive_diffs.push_back(pos);
negative_diffs.push_back(neg);
cp_model.AddBoolOr({Not(vars[var][value]),
Not(vars[var + step][value + diff]), pos});
cp_model.AddBoolOr({Not(vars[var][value + diff]),
Not(vars[var + step][value]), neg});
cp_model.AddBoolOr({
Not(vars[var][value]), Not(vars[var + step][value + diff]), pos
});
cp_model.AddBoolOr({
Not(vars[var][value + diff]), Not(vars[var + step][value]), neg
});
}
}
const IntVar pos_var =
@@ -262,8 +269,8 @@ void CostasBoolSoft(const int dim) {
cp_model.Minimize(LinearExpr::Sum(all_violations));
Model model;
if (!FLAGS_params.empty()) {
model.Add(NewSatParameters(FLAGS_params));
if (!absl::GetFlag(FLAGS_params).empty()) {
model.Add(NewSatParameters(absl::GetFlag(FLAGS_params)));
}
const CpSolverResponse response = SolveCpModel(cp_model.Build(), &model);
@@ -290,19 +297,19 @@ void CostasBoolSoft(const int dim) {
}
}
} // namespace sat
} // namespace operations_research
} // namespace sat
} // namespace operations_research
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
int min = 1;
int max = 10;
if (FLAGS_minsize != 0) {
min = FLAGS_minsize;
if (absl::GetFlag(FLAGS_minsize) != 0) {
min = absl::GetFlag(FLAGS_minsize);
if (FLAGS_maxsize != 0) {
max = FLAGS_maxsize;
if (absl::GetFlag(FLAGS_maxsize) != 0) {
max = absl::GetFlag(FLAGS_maxsize);
} else {
max = min;
}
@@ -310,11 +317,11 @@ int main(int argc, char **argv) {
for (int size = min; size <= max; ++size) {
LOG(INFO) << "Computing Costas Array for dim = " << size;
if (FLAGS_model == 1) {
if (absl::GetFlag(FLAGS_model) == 1) {
operations_research::sat::CostasHard(size);
} else if (FLAGS_model == 2) {
} else if (absl::GetFlag(FLAGS_model) == 2) {
operations_research::sat::CostasBool(size);
} else if (FLAGS_model == 3) {
} else if (absl::GetFlag(FLAGS_model) == 3) {
operations_research::sat::CostasBoolSoft(size);
}
}

View File

@@ -59,75 +59,81 @@ DEFINE_string(routing_search_parameters, "",
"Text proto RoutingSearchParameters (possibly partial) that will "
"override the DefaultRoutingSearchParameters()");
const char* kTime = "Time";
const char* kCapacity = "Capacity";
const char *kTime = "Time";
const char *kCapacity = "Capacity";
const int64 kMaxNodesPerGroup = 10;
const int64 kSameVehicleCost = 1000;
int main(int argc, char** argv) {
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
CHECK_LT(0, FLAGS_vrp_orders) << "Specify an instance size greater than 0.";
CHECK_LT(0, FLAGS_vrp_vehicles) << "Specify a non-null vehicle fleet size.";
// VRP of size FLAGS_vrp_size.
// Nodes are indexed from 0 to FLAGS_vrp_orders, the starts and ends of
CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders))
<< "Specify an instance size greater than 0.";
CHECK_LT(0, absl::GetFlag(FLAGS_vrp_vehicles))
<< "Specify a non-null vehicle fleet size.";
// VRP of size absl::GetFlag(FLAGS_vrp_size).
// Nodes are indexed from 0 to absl::GetFlag(FLAGS_vrp_orders), the starts and
// ends of
// the routes are at node 0.
const RoutingIndexManager::NodeIndex kDepot(0);
RoutingIndexManager manager(FLAGS_vrp_orders + 1, FLAGS_vrp_vehicles, kDepot);
RoutingIndexManager manager(absl::GetFlag(FLAGS_vrp_orders) + 1,
absl::GetFlag(FLAGS_vrp_vehicles), kDepot);
RoutingModel routing(manager);
// Setting up locations.
const int64 kXMax = 100000;
const int64 kYMax = 100000;
const int64 kSpeed = 10;
LocationContainer locations(kSpeed, FLAGS_vrp_use_deterministic_random_seed);
for (int location = 0; location <= FLAGS_vrp_orders; ++location) {
LocationContainer locations(
kSpeed, absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed));
for (int location = 0; location <= absl::GetFlag(FLAGS_vrp_orders);
++location) {
locations.AddRandomLocation(kXMax, kYMax);
}
// Setting the cost function.
// Setting the cost function.
const int vehicle_cost =
routing.RegisterTransitCallback([&locations, &manager](int64 i, int64 j) {
return locations.ManhattanDistance(manager.IndexToNode(i),
manager.IndexToNode(j));
});
return locations.ManhattanDistance(manager.IndexToNode(i),
manager.IndexToNode(j));
});
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
// Adding capacity dimension constraints.
const int64 kVehicleCapacity = 40;
const int64 kNullCapacitySlack = 0;
RandomDemand demand(manager.num_nodes(), kDepot,
FLAGS_vrp_use_deterministic_random_seed);
absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed));
demand.Initialize();
routing.AddDimension(
routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) {
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kNullCapacitySlack, kVehicleCapacity,
/*fix_start_cumul_to_zero=*/true, kCapacity);
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/ true,
kCapacity);
// Adding time dimension constraints.
const int64 kTimePerDemandUnit = 300;
const int64 kHorizon = 24 * 3600;
ServiceTimePlusTransition time(
kTimePerDemandUnit,
[&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
return demand.Demand(i, j);
},
kTimePerDemandUnit, [&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
return demand.Demand(i, j);
},
[&locations](RoutingNodeIndex i, RoutingNodeIndex j) {
return locations.ManhattanTime(i, j);
});
return locations.ManhattanTime(i, j);
});
routing.AddDimension(
routing.RegisterTransitCallback([&time, &manager](int64 i, int64 j) {
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/false, kTime);
const RoutingDimension& time_dimension = routing.GetDimensionOrDie(kTime);
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/ false, kTime);
const RoutingDimension &time_dimension = routing.GetDimensionOrDie(kTime);
// Adding disjoint time windows.
Solver* solver = routing.solver();
ACMRandom randomizer(GetSeed(FLAGS_vrp_use_deterministic_random_seed));
Solver *solver = routing.solver();
ACMRandom randomizer(
GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)));
for (int order = 1; order < manager.num_nodes(); ++order) {
std::vector<int64> forbid_points(2 * FLAGS_vrp_windows, 0);
std::vector<int64> forbid_points(2 * absl::GetFlag(FLAGS_vrp_windows), 0);
for (int i = 0; i < forbid_points.size(); ++i) {
forbid_points[i] = randomizer.Uniform(kHorizon);
}
@@ -153,7 +159,7 @@ int main(int argc, char** argv) {
}
// Adding same vehicle constraint costs for consecutive nodes.
if (FLAGS_vrp_use_same_vehicle_costs) {
if (absl::GetFlag(FLAGS_vrp_use_same_vehicle_costs)) {
std::vector<int64> group;
for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot;
order < manager.num_nodes(); ++order) {
@@ -171,10 +177,11 @@ int main(int argc, char** argv) {
// Solve, returns a solution if any (owned by RoutingModel).
RoutingSearchParameters parameters = DefaultRoutingSearchParameters();
CHECK(google::protobuf::TextFormat::MergeFromString(
FLAGS_routing_search_parameters, &parameters));
const Assignment* solution = routing.SolveWithParameters(parameters);
absl::GetFlag(FLAGS_routing_search_parameters), &parameters));
const Assignment *solution = routing.SolveWithParameters(parameters);
if (solution != nullptr) {
DisplayPlan(manager, routing, *solution, FLAGS_vrp_use_same_vehicle_costs,
DisplayPlan(manager, routing, *solution,
absl::GetFlag(FLAGS_vrp_use_same_vehicle_costs),
kMaxNodesPerGroup, kSameVehicleCost,
routing.GetDimensionOrDie(kCapacity),
routing.GetDimensionOrDie(kTime));

View File

@@ -57,72 +57,78 @@ DEFINE_string(routing_search_parameters, "",
"Text proto RoutingSearchParameters (possibly partial) that will "
"override the DefaultRoutingSearchParameters()");
const char* kTime = "Time";
const char* kCapacity = "Capacity";
const char *kTime = "Time";
const char *kCapacity = "Capacity";
const int64 kMaxNodesPerGroup = 10;
const int64 kSameVehicleCost = 1000;
int main(int argc, char** argv) {
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
CHECK_LT(0, FLAGS_vrp_orders) << "Specify an instance size greater than 0.";
CHECK_LT(0, FLAGS_vrp_vehicles) << "Specify a non-null vehicle fleet size.";
// VRP of size FLAGS_vrp_size.
// Nodes are indexed from 0 to FLAGS_vrp_orders, the starts and ends of
CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders))
<< "Specify an instance size greater than 0.";
CHECK_LT(0, absl::GetFlag(FLAGS_vrp_vehicles))
<< "Specify a non-null vehicle fleet size.";
// VRP of size absl::GetFlag(FLAGS_vrp_size).
// Nodes are indexed from 0 to absl::GetFlag(FLAGS_vrp_orders), the starts and
// ends of
// the routes are at node 0.
const RoutingIndexManager::NodeIndex kDepot(0);
RoutingIndexManager manager(FLAGS_vrp_orders + 1, FLAGS_vrp_vehicles, kDepot);
RoutingIndexManager manager(absl::GetFlag(FLAGS_vrp_orders) + 1,
absl::GetFlag(FLAGS_vrp_vehicles), kDepot);
RoutingModel routing(manager);
// Setting up locations.
const int64 kXMax = 100000;
const int64 kYMax = 100000;
const int64 kSpeed = 10;
LocationContainer locations(kSpeed, FLAGS_vrp_use_deterministic_random_seed);
for (int location = 0; location <= FLAGS_vrp_orders; ++location) {
LocationContainer locations(
kSpeed, absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed));
for (int location = 0; location <= absl::GetFlag(FLAGS_vrp_orders);
++location) {
locations.AddRandomLocation(kXMax, kYMax);
}
// Setting the cost function.
// Setting the cost function.
const int vehicle_cost =
routing.RegisterTransitCallback([&locations, &manager](int64 i, int64 j) {
return locations.ManhattanDistance(manager.IndexToNode(i),
manager.IndexToNode(j));
});
return locations.ManhattanDistance(manager.IndexToNode(i),
manager.IndexToNode(j));
});
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
// Adding capacity dimension constraints.
const int64 kVehicleCapacity = 40;
const int64 kNullCapacitySlack = 0;
RandomDemand demand(manager.num_nodes(), kDepot,
FLAGS_vrp_use_deterministic_random_seed);
absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed));
demand.Initialize();
routing.AddDimension(
routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) {
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kNullCapacitySlack, kVehicleCapacity,
/*fix_start_cumul_to_zero=*/true, kCapacity);
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/ true,
kCapacity);
// Adding time dimension constraints.
const int64 kTimePerDemandUnit = 300;
const int64 kHorizon = 24 * 3600;
ServiceTimePlusTransition time(
kTimePerDemandUnit,
[&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
return demand.Demand(i, j);
},
kTimePerDemandUnit, [&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
return demand.Demand(i, j);
},
[&locations](RoutingNodeIndex i, RoutingNodeIndex j) {
return locations.ManhattanTime(i, j);
});
return locations.ManhattanTime(i, j);
});
routing.AddDimension(
routing.RegisterTransitCallback([&time, &manager](int64 i, int64 j) {
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/true, kTime);
const RoutingDimension& time_dimension = routing.GetDimensionOrDie(kTime);
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/ true, kTime);
const RoutingDimension &time_dimension = routing.GetDimensionOrDie(kTime);
// Adding time windows.
ACMRandom randomizer(GetSeed(FLAGS_vrp_use_deterministic_random_seed));
ACMRandom randomizer(
GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)));
const int64 kTWDuration = 5 * 3600;
for (int order = 1; order < manager.num_nodes(); ++order) {
const int64 start = randomizer.Uniform(kHorizon - kTWDuration);
@@ -139,7 +145,7 @@ int main(int argc, char** argv) {
}
// Adding same vehicle constraint costs for consecutive nodes.
if (FLAGS_vrp_use_same_vehicle_costs) {
if (absl::GetFlag(FLAGS_vrp_use_same_vehicle_costs)) {
std::vector<int64> group;
for (RoutingIndexManager::NodeIndex order = kFirstNodeAfterDepot;
order < manager.num_nodes(); ++order) {
@@ -157,10 +163,11 @@ int main(int argc, char** argv) {
// Solve, returns a solution if any (owned by RoutingModel).
RoutingSearchParameters parameters = DefaultRoutingSearchParameters();
CHECK(google::protobuf::TextFormat::MergeFromString(
FLAGS_routing_search_parameters, &parameters));
const Assignment* solution = routing.SolveWithParameters(parameters);
absl::GetFlag(FLAGS_routing_search_parameters), &parameters));
const Assignment *solution = routing.SolveWithParameters(parameters);
if (solution != nullptr) {
DisplayPlan(manager, routing, *solution, FLAGS_vrp_use_same_vehicle_costs,
DisplayPlan(manager, routing, *solution,
absl::GetFlag(FLAGS_vrp_use_same_vehicle_costs),
kMaxNodesPerGroup, kSameVehicleCost,
routing.GetDimensionOrDie(kCapacity),
routing.GetDimensionOrDie(kTime));

View File

@@ -35,7 +35,7 @@ int32 GetSeed(bool deterministic);
// Location container, contains positions of orders and can be used to obtain
// Manhattan distances/times between locations.
class LocationContainer {
public:
public:
LocationContainer(int64 speed, bool use_deterministic_seed);
void AddLocation(int64 x, int64 y) { locations_.push_back(Location(x, y)); }
void AddRandomLocation(int64 x_max, int64 y_max);
@@ -51,15 +51,15 @@ class LocationContainer {
RoutingIndexManager::NodeIndex node2) const;
int64 SameLocationFromIndex(int64 node1, int64 node2) const;
private:
private:
class Location {
public:
public:
Location();
Location(int64 x, int64 y);
int64 DistanceTo(const Location& location) const;
bool IsAtSameLocation(const Location& location) const;
int64 DistanceTo(const Location &location) const;
bool IsAtSameLocation(const Location &location) const;
private:
private:
static int64 Abs(int64 value);
int64 x_;
@@ -73,14 +73,14 @@ class LocationContainer {
// Random demand.
class RandomDemand {
public:
public:
RandomDemand(int size, RoutingIndexManager::NodeIndex depot,
bool use_deterministic_seed);
void Initialize();
int64 Demand(RoutingIndexManager::NodeIndex from,
RoutingIndexManager::NodeIndex to) const;
private:
private:
std::unique_ptr<int64[]> demand_;
const int size_;
const RoutingIndexManager::NodeIndex depot_;
@@ -89,14 +89,14 @@ class RandomDemand {
// Service time (proportional to demand) + transition time callback.
class ServiceTimePlusTransition {
public:
public:
ServiceTimePlusTransition(int64 time_per_demand_unit,
RoutingNodeEvaluator2 demand,
RoutingNodeEvaluator2 transition_time);
int64 Compute(RoutingIndexManager::NodeIndex from,
RoutingIndexManager::NodeIndex to) const;
private:
private:
const int64 time_per_demand_unit_;
RoutingNodeEvaluator2 demand_;
RoutingNodeEvaluator2 transition_time_;
@@ -104,29 +104,30 @@ class ServiceTimePlusTransition {
// Stop service time + transition time callback.
class StopServiceTimePlusTransition {
public:
public:
StopServiceTimePlusTransition(int64 stop_time,
const LocationContainer& location_container,
const LocationContainer &location_container,
RoutingNodeEvaluator2 transition_time);
int64 Compute(RoutingIndexManager::NodeIndex from,
RoutingIndexManager::NodeIndex to) const;
private:
private:
const int64 stop_time_;
const LocationContainer& location_container_;
const LocationContainer &location_container_;
RoutingNodeEvaluator2 demand_;
RoutingNodeEvaluator2 transition_time_;
};
// Route plan displayer.
// TODO(user): Move the display code to the routing library.
void DisplayPlan(
const operations_research::RoutingIndexManager& manager,
const operations_research::RoutingModel& routing,
const operations_research::Assignment& plan, bool use_same_vehicle_costs,
int64 max_nodes_per_group, int64 same_vehicle_cost,
const operations_research::RoutingDimension& capacity_dimension,
const operations_research::RoutingDimension& time_dimension);
void
DisplayPlan(const operations_research::RoutingIndexManager &manager,
const operations_research::RoutingModel &routing,
const operations_research::Assignment &plan,
bool use_same_vehicle_costs, int64 max_nodes_per_group,
int64 same_vehicle_cost,
const operations_research::RoutingDimension &capacity_dimension,
const operations_research::RoutingDimension &time_dimension);
using NodeIndex = RoutingIndexManager::NodeIndex;
@@ -186,12 +187,12 @@ LocationContainer::Location::Location() : x_(0), y_(0) {}
LocationContainer::Location::Location(int64 x, int64 y) : x_(x), y_(y) {}
int64 LocationContainer::Location::DistanceTo(const Location& location) const {
int64 LocationContainer::Location::DistanceTo(const Location &location) const {
return Abs(x_ - location.x_) + Abs(y_ - location.y_);
}
bool LocationContainer::Location::IsAtSameLocation(
const Location& location) const {
bool
LocationContainer::Location::IsAtSameLocation(const Location &location) const {
return x_ == location.x_ && y_ == location.y_;
}
@@ -201,8 +202,7 @@ int64 LocationContainer::Location::Abs(int64 value) {
RandomDemand::RandomDemand(int size, NodeIndex depot,
bool use_deterministic_seed)
: size_(size),
depot_(depot),
: size_(size), depot_(depot),
use_deterministic_seed_(use_deterministic_seed) {
CHECK_LT(0, size_);
}
@@ -229,8 +229,7 @@ int64 RandomDemand::Demand(NodeIndex from, NodeIndex /*to*/) const {
ServiceTimePlusTransition::ServiceTimePlusTransition(
int64 time_per_demand_unit, RoutingNodeEvaluator2 demand,
RoutingNodeEvaluator2 transition_time)
: time_per_demand_unit_(time_per_demand_unit),
demand_(std::move(demand)),
: time_per_demand_unit_(time_per_demand_unit), demand_(std::move(demand)),
transition_time_(std::move(transition_time)) {}
int64 ServiceTimePlusTransition::Compute(NodeIndex from, NodeIndex to) const {
@@ -238,10 +237,9 @@ int64 ServiceTimePlusTransition::Compute(NodeIndex from, NodeIndex to) const {
}
StopServiceTimePlusTransition::StopServiceTimePlusTransition(
int64 stop_time, const LocationContainer& location_container,
int64 stop_time, const LocationContainer &location_container,
RoutingNodeEvaluator2 transition_time)
: stop_time_(stop_time),
location_container_(location_container),
: stop_time_(stop_time), location_container_(location_container),
transition_time_(std::move(transition_time)) {}
int64 StopServiceTimePlusTransition::Compute(NodeIndex from,
@@ -251,19 +249,21 @@ int64 StopServiceTimePlusTransition::Compute(NodeIndex from,
: stop_time_ + transition_time_(from, to);
}
void DisplayPlan(
const RoutingIndexManager& manager, const RoutingModel& routing,
const operations_research::Assignment& plan, bool use_same_vehicle_costs,
int64 max_nodes_per_group, int64 same_vehicle_cost,
const operations_research::RoutingDimension& capacity_dimension,
const operations_research::RoutingDimension& time_dimension) {
void
DisplayPlan(const RoutingIndexManager &manager, const RoutingModel &routing,
const operations_research::Assignment &plan,
bool use_same_vehicle_costs, int64 max_nodes_per_group,
int64 same_vehicle_cost,
const operations_research::RoutingDimension &capacity_dimension,
const operations_research::RoutingDimension &time_dimension) {
// Display plan cost.
std::string plan_output = absl::StrFormat("Cost %d\n", plan.ObjectiveValue());
// Display dropped orders.
std::string dropped;
for (int64 order = 0; order < routing.Size(); ++order) {
if (routing.IsStart(order) || routing.IsEnd(order)) continue;
if (routing.IsStart(order) || routing.IsEnd(order))
continue;
if (plan.Value(routing.NextVar(order)) == order) {
if (dropped.empty()) {
absl::StrAppendFormat(&dropped, " %d",
@@ -283,7 +283,8 @@ void DisplayPlan(
int64 group_same_vehicle_cost = 0;
std::set<int> visited;
for (int64 order = 0; order < routing.Size(); ++order) {
if (routing.IsStart(order) || routing.IsEnd(order)) continue;
if (routing.IsStart(order) || routing.IsEnd(order))
continue;
++group_size;
visited.insert(plan.Value(routing.VehicleVar(order)));
if (group_size == max_nodes_per_group) {
@@ -309,11 +310,11 @@ void DisplayPlan(
plan_output += "Empty\n";
} else {
while (true) {
operations_research::IntVar* const load_var =
operations_research::IntVar *const load_var =
capacity_dimension.CumulVar(order);
operations_research::IntVar* const time_var =
operations_research::IntVar *const time_var =
time_dimension.CumulVar(order);
operations_research::IntVar* const slack_var =
operations_research::IntVar *const slack_var =
routing.IsEnd(order) ? nullptr : time_dimension.SlackVar(order);
if (slack_var != nullptr && plan.Contains(slack_var)) {
absl::StrAppendFormat(
@@ -327,7 +328,8 @@ void DisplayPlan(
plan.Value(load_var), plan.Min(time_var),
plan.Max(time_var));
}
if (routing.IsEnd(order)) break;
if (routing.IsEnd(order))
break;
plan_output += " -> ";
order = plan.Value(routing.NextVar(order));
}
@@ -336,6 +338,6 @@ void DisplayPlan(
}
LOG(INFO) << plan_output;
}
} // namespace operations_research
} // namespace operations_research
#endif // OR_TOOLS_EXAMPLES_CVRPTW_LIB_H_
#endif // OR_TOOLS_EXAMPLES_CVRPTW_LIB_H_

View File

@@ -64,22 +64,26 @@ DEFINE_string(routing_search_parameters, "",
"Text proto RoutingSearchParameters (possibly partial) that will "
"override the DefaultRoutingSearchParameters()");
const char* kTime = "Time";
const char* kCapacity = "Capacity";
const char *kTime = "Time";
const char *kCapacity = "Capacity";
int main(int argc, char** argv) {
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
CHECK_LT(0, FLAGS_vrp_orders) << "Specify an instance size greater than 0.";
CHECK_LT(0, FLAGS_vrp_vehicles) << "Specify a non-null vehicle fleet size.";
// VRP of size FLAGS_vrp_size.
// Nodes are indexed from 0 to FLAGS_vrp_orders, the starts and ends of
CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders))
<< "Specify an instance size greater than 0.";
CHECK_LT(0, absl::GetFlag(FLAGS_vrp_vehicles))
<< "Specify a non-null vehicle fleet size.";
// VRP of size absl::GetFlag(FLAGS_vrp_size).
// Nodes are indexed from 0 to absl::GetFlag(FLAGS_vrp_orders), the starts and
// ends of
// the routes are at node 0.
const RoutingIndexManager::NodeIndex kDepot(0);
RoutingIndexManager manager(FLAGS_vrp_orders + 1, FLAGS_vrp_vehicles, kDepot);
RoutingIndexManager manager(absl::GetFlag(FLAGS_vrp_orders) + 1,
absl::GetFlag(FLAGS_vrp_vehicles), kDepot);
RoutingModel routing(manager);
RoutingSearchParameters parameters = DefaultRoutingSearchParameters();
CHECK(google::protobuf::TextFormat::MergeFromString(
FLAGS_routing_search_parameters, &parameters));
absl::GetFlag(FLAGS_routing_search_parameters), &parameters));
parameters.set_first_solution_strategy(
FirstSolutionStrategy::PARALLEL_CHEAPEST_INSERTION);
@@ -87,52 +91,54 @@ int main(int argc, char** argv) {
const int64 kXMax = 100000;
const int64 kYMax = 100000;
const int64 kSpeed = 10;
LocationContainer locations(kSpeed, FLAGS_vrp_use_deterministic_random_seed);
for (int location = 0; location <= FLAGS_vrp_orders; ++location) {
LocationContainer locations(
kSpeed, absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed));
for (int location = 0; location <= absl::GetFlag(FLAGS_vrp_orders);
++location) {
locations.AddRandomLocation(kXMax, kYMax);
}
// Setting the cost function.
// Setting the cost function.
const int vehicle_cost =
routing.RegisterTransitCallback([&locations, &manager](int64 i, int64 j) {
return locations.ManhattanDistance(manager.IndexToNode(i),
manager.IndexToNode(j));
});
return locations.ManhattanDistance(manager.IndexToNode(i),
manager.IndexToNode(j));
});
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
// Adding capacity dimension constraints.
const int64 kVehicleCapacity = 40;
const int64 kNullCapacitySlack = 0;
RandomDemand demand(manager.num_nodes(), kDepot,
FLAGS_vrp_use_deterministic_random_seed);
absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed));
demand.Initialize();
routing.AddDimension(
routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) {
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kNullCapacitySlack, kVehicleCapacity,
/*fix_start_cumul_to_zero=*/true, kCapacity);
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/ true,
kCapacity);
// Adding time dimension constraints.
const int64 kTimePerDemandUnit = 300;
const int64 kHorizon = 24 * 3600;
ServiceTimePlusTransition time(
kTimePerDemandUnit,
[&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
return demand.Demand(i, j);
},
kTimePerDemandUnit, [&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
return demand.Demand(i, j);
},
[&locations](RoutingNodeIndex i, RoutingNodeIndex j) {
return locations.ManhattanTime(i, j);
});
return locations.ManhattanTime(i, j);
});
routing.AddDimension(
routing.RegisterTransitCallback([&time, &manager](int64 i, int64 j) {
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/false, kTime);
RoutingDimension* const time_dimension = routing.GetMutableDimension(kTime);
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/ false, kTime);
RoutingDimension *const time_dimension = routing.GetMutableDimension(kTime);
// Adding time windows.
ACMRandom randomizer(GetSeed(FLAGS_vrp_use_deterministic_random_seed));
ACMRandom randomizer(
GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)));
const int64 kTWDuration = 5 * 3600;
for (int order = 1; order < manager.num_nodes(); ++order) {
const int64 start = randomizer.Uniform(kHorizon - kTWDuration);
@@ -144,7 +150,7 @@ int main(int argc, char** argv) {
for (int i = 0; i < routing.Size(); ++i) {
routing.AddVariableMinimizedByFinalizer(time_dimension->CumulVar(i));
}
for (int j = 0; j < FLAGS_vrp_vehicles; ++j) {
for (int j = 0; j < absl::GetFlag(FLAGS_vrp_vehicles); ++j) {
routing.AddVariableMinimizedByFinalizer(
time_dimension->CumulVar(routing.Start(j)));
routing.AddVariableMinimizedByFinalizer(
@@ -165,15 +171,17 @@ int main(int argc, char** argv) {
service_times[node] = kTimePerDemandUnit * demand.Demand(index, index);
}
}
const std::vector<std::vector<int>> break_data = {
{/*start_min*/ 11, /*start_max*/ 13, /*duration*/ 2400},
{/*start_min*/ 10, /*start_max*/ 15, /*duration*/ 1800},
{/*start_min*/ 10, /*start_max*/ 15, /*duration*/ 1800}};
Solver* const solver = routing.solver();
for (int vehicle = 0; vehicle < FLAGS_vrp_vehicles; ++vehicle) {
std::vector<IntervalVar*> breaks;
const std::vector<std::vector<int> > break_data = {
{ /*start_min*/ 11, /*start_max*/ 13, /*duration*/ 2400 },
{ /*start_min*/ 10, /*start_max*/ 15, /*duration*/ 1800 },
{ /*start_min*/ 10, /*start_max*/ 15, /*duration*/ 1800 }
};
Solver *const solver = routing.solver();
for (int vehicle = 0; vehicle < absl::GetFlag(FLAGS_vrp_vehicles);
++vehicle) {
std::vector<IntervalVar *> breaks;
for (int i = 0; i < break_data.size(); ++i) {
IntervalVar* const break_interval = solver->MakeFixedDurationIntervalVar(
IntervalVar *const break_interval = solver->MakeFixedDurationIntervalVar(
break_data[i][0] * 3600, break_data[i][1] * 3600, break_data[i][2],
true, absl::StrCat("Break ", i, " on vehicle ", vehicle));
breaks.push_back(break_interval);
@@ -202,10 +210,10 @@ int main(int argc, char** argv) {
}
// Solve, returns a solution if any (owned by RoutingModel).
const Assignment* solution = routing.SolveWithParameters(parameters);
const Assignment *solution = routing.SolveWithParameters(parameters);
if (solution != nullptr) {
LOG(INFO) << "Breaks: ";
for (const auto& break_interval :
for (const auto &break_interval :
solution->IntervalVarContainer().elements()) {
if (break_interval.PerformedValue() == 1) {
LOG(INFO) << break_interval.Var()->name() << " "

View File

@@ -53,9 +53,9 @@ DEFINE_string(routing_search_parameters, "",
"Text proto RoutingSearchParameters (possibly partial) that will "
"override the DefaultRoutingSearchParameters()");
const char* kTime = "Time";
const char* kCapacity = "Capacity";
const char* kFuel = "Fuel";
const char *kTime = "Time";
const char *kCapacity = "Capacity";
const char *kFuel = "Fuel";
// Returns true if node is a refueling node (based on node / refuel node ratio).
bool IsRefuelNode(int64 node) {
@@ -63,66 +63,72 @@ bool IsRefuelNode(int64 node) {
return (node % kRefuelNodeRatio == 0);
}
int main(int argc, char** argv) {
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
CHECK_LT(0, FLAGS_vrp_orders) << "Specify an instance size greater than 0.";
CHECK_LT(0, FLAGS_vrp_vehicles) << "Specify a non-null vehicle fleet size.";
// VRP of size FLAGS_vrp_size.
// Nodes are indexed from 0 to FLAGS_vrp_orders, the starts and ends of
CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders))
<< "Specify an instance size greater than 0.";
CHECK_LT(0, absl::GetFlag(FLAGS_vrp_vehicles))
<< "Specify a non-null vehicle fleet size.";
// VRP of size absl::GetFlag(FLAGS_vrp_size).
// Nodes are indexed from 0 to absl::GetFlag(FLAGS_vrp_orders), the starts and
// ends of
// the routes are at node 0.
const RoutingIndexManager::NodeIndex kDepot(0);
RoutingIndexManager manager(FLAGS_vrp_orders + 1, FLAGS_vrp_vehicles, kDepot);
RoutingIndexManager manager(absl::GetFlag(FLAGS_vrp_orders) + 1,
absl::GetFlag(FLAGS_vrp_vehicles), kDepot);
RoutingModel routing(manager);
// Setting up locations.
const int64 kXMax = 100000;
const int64 kYMax = 100000;
const int64 kSpeed = 10;
LocationContainer locations(kSpeed, FLAGS_vrp_use_deterministic_random_seed);
for (int location = 0; location <= FLAGS_vrp_orders; ++location) {
LocationContainer locations(
kSpeed, absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed));
for (int location = 0; location <= absl::GetFlag(FLAGS_vrp_orders);
++location) {
locations.AddRandomLocation(kXMax, kYMax);
}
// Setting the cost function.
// Setting the cost function.
const int vehicle_cost =
routing.RegisterTransitCallback([&locations, &manager](int64 i, int64 j) {
return locations.ManhattanDistance(manager.IndexToNode(i),
manager.IndexToNode(j));
});
return locations.ManhattanDistance(manager.IndexToNode(i),
manager.IndexToNode(j));
});
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
// Adding capacity dimension constraints.
const int64 kVehicleCapacity = 40;
const int64 kNullCapacitySlack = 0;
RandomDemand demand(manager.num_nodes(), kDepot,
FLAGS_vrp_use_deterministic_random_seed);
absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed));
demand.Initialize();
routing.AddDimension(
routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) {
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kNullCapacitySlack, kVehicleCapacity,
/*fix_start_cumul_to_zero=*/true, kCapacity);
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/ true,
kCapacity);
// Adding time dimension constraints.
const int64 kTimePerDemandUnit = 300;
const int64 kHorizon = 24 * 3600;
ServiceTimePlusTransition time(
kTimePerDemandUnit,
[&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
return demand.Demand(i, j);
},
kTimePerDemandUnit, [&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
return demand.Demand(i, j);
},
[&locations](RoutingNodeIndex i, RoutingNodeIndex j) {
return locations.ManhattanTime(i, j);
});
return locations.ManhattanTime(i, j);
});
routing.AddDimension(
routing.RegisterTransitCallback([&time, &manager](int64 i, int64 j) {
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/true, kTime);
const RoutingDimension& time_dimension = routing.GetDimensionOrDie(kTime);
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/ true, kTime);
const RoutingDimension &time_dimension = routing.GetDimensionOrDie(kTime);
// Adding time windows.
ACMRandom randomizer(GetSeed(FLAGS_vrp_use_deterministic_random_seed));
ACMRandom randomizer(
GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)));
const int64 kTWDuration = 5 * 3600;
for (int order = 1; order < manager.num_nodes(); ++order) {
if (!IsRefuelNode(order)) {
@@ -137,11 +143,11 @@ int main(int argc, char** argv) {
const int64 kFuelCapacity = kXMax + kYMax;
routing.AddDimension(
routing.RegisterTransitCallback([&locations, &manager](int64 i, int64 j) {
return locations.NegManhattanDistance(manager.IndexToNode(i),
manager.IndexToNode(j));
}),
kFuelCapacity, kFuelCapacity, /*fix_start_cumul_to_zero=*/false, kFuel);
const RoutingDimension& fuel_dimension = routing.GetDimensionOrDie(kFuel);
return locations.NegManhattanDistance(manager.IndexToNode(i),
manager.IndexToNode(j));
}),
kFuelCapacity, kFuelCapacity, /*fix_start_cumul_to_zero=*/ false, kFuel);
const RoutingDimension &fuel_dimension = routing.GetDimensionOrDie(kFuel);
for (int order = 0; order < routing.Size(); ++order) {
// Only let slack free for refueling nodes.
if (!IsRefuelNode(order) || routing.IsStart(order)) {
@@ -163,11 +169,11 @@ int main(int argc, char** argv) {
// Solve, returns a solution if any (owned by RoutingModel).
RoutingSearchParameters parameters = DefaultRoutingSearchParameters();
CHECK(google::protobuf::TextFormat::MergeFromString(
FLAGS_routing_search_parameters, &parameters));
const Assignment* solution = routing.SolveWithParameters(parameters);
absl::GetFlag(FLAGS_routing_search_parameters), &parameters));
const Assignment *solution = routing.SolveWithParameters(parameters);
if (solution != nullptr) {
DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/false,
/*max_nodes_per_group=*/0, /*same_vehicle_cost=*/0,
DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/ false,
/*max_nodes_per_group=*/ 0, /*same_vehicle_cost=*/ 0,
routing.GetDimensionOrDie(kCapacity),
routing.GetDimensionOrDie(kTime));
} else {

View File

@@ -58,70 +58,76 @@ DEFINE_string(routing_search_parameters, "",
"Text proto RoutingSearchParameters (possibly partial) that will "
"override the DefaultRoutingSearchParameters()");
const char* kTime = "Time";
const char* kCapacity = "Capacity";
const char *kTime = "Time";
const char *kCapacity = "Capacity";
int main(int argc, char** argv) {
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
CHECK_LT(0, FLAGS_vrp_orders) << "Specify an instance size greater than 0.";
CHECK_LT(0, FLAGS_vrp_vehicles) << "Specify a non-null vehicle fleet size.";
// VRP of size FLAGS_vrp_size.
// Nodes are indexed from 0 to FLAGS_vrp_orders, the starts and ends of
CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders))
<< "Specify an instance size greater than 0.";
CHECK_LT(0, absl::GetFlag(FLAGS_vrp_vehicles))
<< "Specify a non-null vehicle fleet size.";
// VRP of size absl::GetFlag(FLAGS_vrp_size).
// Nodes are indexed from 0 to absl::GetFlag(FLAGS_vrp_orders), the starts and
// ends of
// the routes are at node 0.
const RoutingIndexManager::NodeIndex kDepot(0);
RoutingIndexManager manager(FLAGS_vrp_orders + 1, FLAGS_vrp_vehicles, kDepot);
RoutingIndexManager manager(absl::GetFlag(FLAGS_vrp_orders) + 1,
absl::GetFlag(FLAGS_vrp_vehicles), kDepot);
RoutingModel routing(manager);
// Setting up locations.
const int64 kXMax = 100000;
const int64 kYMax = 100000;
const int64 kSpeed = 10;
LocationContainer locations(kSpeed, FLAGS_vrp_use_deterministic_random_seed);
for (int location = 0; location <= FLAGS_vrp_orders; ++location) {
LocationContainer locations(
kSpeed, absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed));
for (int location = 0; location <= absl::GetFlag(FLAGS_vrp_orders);
++location) {
locations.AddRandomLocation(kXMax, kYMax);
}
// Setting the cost function.
// Setting the cost function.
const int vehicle_cost =
routing.RegisterTransitCallback([&locations, &manager](int64 i, int64 j) {
return locations.ManhattanDistance(manager.IndexToNode(i),
manager.IndexToNode(j));
});
return locations.ManhattanDistance(manager.IndexToNode(i),
manager.IndexToNode(j));
});
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
// Adding capacity dimension constraints.
const int64 kVehicleCapacity = 40;
const int64 kNullCapacitySlack = 0;
RandomDemand demand(manager.num_nodes(), kDepot,
FLAGS_vrp_use_deterministic_random_seed);
absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed));
demand.Initialize();
routing.AddDimension(
routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) {
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kNullCapacitySlack, kVehicleCapacity,
/*fix_start_cumul_to_zero=*/true, kCapacity);
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/ true,
kCapacity);
// Adding time dimension constraints.
const int64 kTimePerDemandUnit = 300;
const int64 kHorizon = 24 * 3600;
ServiceTimePlusTransition time(
kTimePerDemandUnit,
[&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
return demand.Demand(i, j);
},
kTimePerDemandUnit, [&demand](RoutingNodeIndex i, RoutingNodeIndex j) {
return demand.Demand(i, j);
},
[&locations](RoutingNodeIndex i, RoutingNodeIndex j) {
return locations.ManhattanTime(i, j);
});
return locations.ManhattanTime(i, j);
});
routing.AddDimension(
routing.RegisterTransitCallback([&time, &manager](int64 i, int64 j) {
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/false, kTime);
const RoutingDimension& time_dimension = routing.GetDimensionOrDie(kTime);
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/ false, kTime);
const RoutingDimension &time_dimension = routing.GetDimensionOrDie(kTime);
// Adding time windows.
ACMRandom randomizer(GetSeed(FLAGS_vrp_use_deterministic_random_seed));
ACMRandom randomizer(
GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)));
const int64 kTWDuration = 5 * 3600;
for (int order = 1; order < manager.num_nodes(); ++order) {
const int64 start = randomizer.Uniform(kHorizon - kTWDuration);
@@ -130,15 +136,15 @@ int main(int argc, char** argv) {
// Adding resource constraints at the depot (start and end location of
// routes).
std::vector<IntVar*> start_end_times;
for (int i = 0; i < FLAGS_vrp_vehicles; ++i) {
std::vector<IntVar *> start_end_times;
for (int i = 0; i < absl::GetFlag(FLAGS_vrp_vehicles); ++i) {
start_end_times.push_back(time_dimension.CumulVar(routing.End(i)));
start_end_times.push_back(time_dimension.CumulVar(routing.Start(i)));
}
// Build corresponding time intervals.
const int64 kVehicleSetup = 180;
Solver* const solver = routing.solver();
std::vector<IntervalVar*> intervals;
Solver *const solver = routing.solver();
std::vector<IntervalVar *> intervals;
solver->MakeFixedDurationIntervalVarArray(start_end_times, kVehicleSetup,
"depot_interval", &intervals);
// Constrain the number of maximum simultaneous intervals at depot.
@@ -163,11 +169,11 @@ int main(int argc, char** argv) {
// Solve, returns a solution if any (owned by RoutingModel).
RoutingSearchParameters parameters = DefaultRoutingSearchParameters();
CHECK(google::protobuf::TextFormat::MergeFromString(
FLAGS_routing_search_parameters, &parameters));
const Assignment* solution = routing.SolveWithParameters(parameters);
absl::GetFlag(FLAGS_routing_search_parameters), &parameters));
const Assignment *solution = routing.SolveWithParameters(parameters);
if (solution != nullptr) {
DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/false,
/*max_nodes_per_group=*/0, /*same_vehicle_cost=*/0,
DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/ false,
/*max_nodes_per_group=*/ 0, /*same_vehicle_cost=*/ 0,
routing.GetDimensionOrDie(kCapacity),
routing.GetDimensionOrDie(kTime));
} else {

View File

@@ -58,52 +58,58 @@ DEFINE_string(routing_search_parameters, "",
"Text proto RoutingSearchParameters (possibly partial) that will "
"override the DefaultRoutingSearchParameters()");
const char* kTime = "Time";
const char* kCapacity = "Capacity";
const char *kTime = "Time";
const char *kCapacity = "Capacity";
int main(int argc, char** argv) {
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
CHECK_LT(0, FLAGS_vrp_stops) << "Specify an instance size greater than 0.";
CHECK_LT(0, FLAGS_vrp_orders_per_stop)
CHECK_LT(0, absl::GetFlag(FLAGS_vrp_stops))
<< "Specify an instance size greater than 0.";
CHECK_LT(0, FLAGS_vrp_vehicles) << "Specify a non-null vehicle fleet size.";
const int vrp_orders = FLAGS_vrp_stops * FLAGS_vrp_orders_per_stop;
CHECK_LT(0, absl::GetFlag(FLAGS_vrp_orders_per_stop))
<< "Specify an instance size greater than 0.";
CHECK_LT(0, absl::GetFlag(FLAGS_vrp_vehicles))
<< "Specify a non-null vehicle fleet size.";
const int vrp_orders =
absl::GetFlag(FLAGS_vrp_stops) * absl::GetFlag(FLAGS_vrp_orders_per_stop);
// Nodes are indexed from 0 to vrp_orders, the starts and ends of the routes
// are at node 0.
const RoutingIndexManager::NodeIndex kDepot(0);
RoutingIndexManager manager(vrp_orders + 1, FLAGS_vrp_vehicles, kDepot);
RoutingIndexManager manager(vrp_orders + 1, absl::GetFlag(FLAGS_vrp_vehicles),
kDepot);
RoutingModel routing(manager);
// Setting up locations.
const int64 kXMax = 100000;
const int64 kYMax = 100000;
const int64 kSpeed = 10;
LocationContainer locations(kSpeed, FLAGS_vrp_use_deterministic_random_seed);
for (int stop = 0; stop <= FLAGS_vrp_stops; ++stop) {
const int num_orders = stop == 0 ? 1 : FLAGS_vrp_orders_per_stop;
LocationContainer locations(
kSpeed, absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed));
for (int stop = 0; stop <= absl::GetFlag(FLAGS_vrp_stops); ++stop) {
const int num_orders =
stop == 0 ? 1 : absl::GetFlag(FLAGS_vrp_orders_per_stop);
locations.AddRandomLocation(kXMax, kYMax, num_orders);
}
// Setting the cost function.
// Setting the cost function.
const int vehicle_cost =
routing.RegisterTransitCallback([&locations, &manager](int64 i, int64 j) {
return locations.ManhattanDistance(manager.IndexToNode(i),
manager.IndexToNode(j));
});
return locations.ManhattanDistance(manager.IndexToNode(i),
manager.IndexToNode(j));
});
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
// Adding capacity dimension constraints.
const int64 kVehicleCapacity = 40;
const int64 kNullCapacitySlack = 0;
RandomDemand demand(manager.num_nodes(), kDepot,
FLAGS_vrp_use_deterministic_random_seed);
absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed));
demand.Initialize();
routing.AddDimension(
routing.RegisterTransitCallback([&demand, &manager](int64 i, int64 j) {
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kNullCapacitySlack, kVehicleCapacity,
/*fix_start_cumul_to_zero=*/true, kCapacity);
return demand.Demand(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kNullCapacitySlack, kVehicleCapacity, /*fix_start_cumul_to_zero=*/ true,
kCapacity);
// Adding time dimension constraints.
const int64 kStopTime = 300;
@@ -111,55 +117,55 @@ int main(int argc, char** argv) {
StopServiceTimePlusTransition time(
kStopTime, locations,
[&locations](RoutingNodeIndex i, RoutingNodeIndex j) {
return locations.ManhattanTime(i, j);
});
return locations.ManhattanTime(i, j);
});
routing.AddDimension(
routing.RegisterTransitCallback([&time, &manager](int64 i, int64 j) {
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/false, kTime);
const RoutingDimension& time_dimension = routing.GetDimensionOrDie(kTime);
return time.Compute(manager.IndexToNode(i), manager.IndexToNode(j));
}),
kHorizon, kHorizon, /*fix_start_cumul_to_zero=*/ false, kTime);
const RoutingDimension &time_dimension = routing.GetDimensionOrDie(kTime);
// Adding time windows, for the sake of simplicty same for each stop.
ACMRandom randomizer(GetSeed(FLAGS_vrp_use_deterministic_random_seed));
ACMRandom randomizer(
GetSeed(absl::GetFlag(FLAGS_vrp_use_deterministic_random_seed)));
const int64 kTWDuration = 5 * 3600;
for (int stop = 0; stop < FLAGS_vrp_stops; ++stop) {
for (int stop = 0; stop < absl::GetFlag(FLAGS_vrp_stops); ++stop) {
const int64 start = randomizer.Uniform(kHorizon - kTWDuration);
for (int stop_order = 0; stop_order < FLAGS_vrp_orders_per_stop;
++stop_order) {
const int order = stop * FLAGS_vrp_orders_per_stop + stop_order + 1;
for (int stop_order = 0;
stop_order < absl::GetFlag(FLAGS_vrp_orders_per_stop); ++stop_order) {
const int order =
stop * absl::GetFlag(FLAGS_vrp_orders_per_stop) + stop_order + 1;
time_dimension.CumulVar(order)->SetRange(start, start + kTWDuration);
}
}
// Adding resource constraints at order locations.
Solver* const solver = routing.solver();
std::vector<IntervalVar*> intervals;
for (int stop = 0; stop < FLAGS_vrp_stops; ++stop) {
std::vector<IntervalVar*> stop_intervals;
for (int stop_order = 0; stop_order < FLAGS_vrp_orders_per_stop;
++stop_order) {
const int order = stop * FLAGS_vrp_orders_per_stop + stop_order + 1;
IntervalVar* const interval = solver->MakeFixedDurationIntervalVar(
Solver *const solver = routing.solver();
std::vector<IntervalVar *> intervals;
for (int stop = 0; stop < absl::GetFlag(FLAGS_vrp_stops); ++stop) {
std::vector<IntervalVar *> stop_intervals;
for (int stop_order = 0;
stop_order < absl::GetFlag(FLAGS_vrp_orders_per_stop); ++stop_order) {
const int order =
stop * absl::GetFlag(FLAGS_vrp_orders_per_stop) + stop_order + 1;
IntervalVar *const interval = solver->MakeFixedDurationIntervalVar(
0, kHorizon, kStopTime, true, absl::StrCat("Order", order));
intervals.push_back(interval);
stop_intervals.push_back(interval);
// Link order and interval.
IntVar* const order_start = time_dimension.CumulVar(order);
IntVar *const order_start = time_dimension.CumulVar(order);
solver->AddConstraint(
solver->MakeIsEqualCt(interval->SafeStartExpr(0), order_start,
interval->PerformedExpr()->Var()));
// Make interval performed iff corresponding order has service time.
// An order has no service time iff it is at the same location as the
// next order on the route.
IntVar* const is_null_duration =
solver
->MakeElement(
[&locations, order](int64 index) {
return locations.SameLocationFromIndex(order, index);
},
routing.NextVar(order))
->Var();
// Make interval performed iff corresponding order has service time.
// An order has no service time iff it is at the same location as the
// next order on the route.
IntVar *const is_null_duration =
solver->MakeElement([&locations, order](int64 index) {
return locations.SameLocationFromIndex(order, index);
},
routing.NextVar(order))->Var();
solver->AddConstraint(
solver->MakeNonEquality(interval->PerformedExpr(), is_null_duration));
routing.AddIntervalToAssignment(interval);
@@ -190,15 +196,15 @@ int main(int argc, char** argv) {
// Solve, returns a solution if any (owned by RoutingModel).
RoutingSearchParameters parameters = DefaultRoutingSearchParameters();
CHECK(google::protobuf::TextFormat::MergeFromString(
FLAGS_routing_search_parameters, &parameters));
const Assignment* solution = routing.SolveWithParameters(parameters);
absl::GetFlag(FLAGS_routing_search_parameters), &parameters));
const Assignment *solution = routing.SolveWithParameters(parameters);
if (solution != nullptr) {
DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/false,
/*max_nodes_per_group=*/0, /*same_vehicle_cost=*/0,
DisplayPlan(manager, routing, *solution, /*use_same_vehicle_costs=*/ false,
/*max_nodes_per_group=*/ 0, /*same_vehicle_cost=*/ 0,
routing.GetDimensionOrDie(kCapacity),
routing.GetDimensionOrDie(kTime));
LOG(INFO) << "Stop intervals:";
for (IntervalVar* const interval : intervals) {
for (IntervalVar *const interval : intervals) {
if (solution->PerformedValue(interval)) {
LOG(INFO) << interval->name() << ": " << solution->StartValue(interval);
}

View File

@@ -47,8 +47,8 @@ typedef ForwardStarStaticGraph GraphType;
template <typename GraphType>
CostValue BuildAndSolveHungarianInstance(
const LinearSumAssignment<GraphType>& assignment) {
const GraphType& graph = assignment.Graph();
const LinearSumAssignment<GraphType> &assignment) {
const GraphType &graph = assignment.Graph();
typedef std::vector<double> HungarianRow;
typedef std::vector<HungarianRow> HungarianProblem;
HungarianProblem hungarian_cost;
@@ -106,7 +106,7 @@ CostValue BuildAndSolveHungarianInstance(
}
template <typename GraphType>
void DisplayAssignment(const LinearSumAssignment<GraphType>& assignment) {
void DisplayAssignment(const LinearSumAssignment<GraphType> &assignment) {
for (typename LinearSumAssignment<GraphType>::BipartiteLeftNodeIterator
node_it(assignment);
node_it.Ok(); node_it.Next()) {
@@ -119,18 +119,18 @@ void DisplayAssignment(const LinearSumAssignment<GraphType>& assignment) {
}
template <typename GraphType>
int SolveDimacsAssignment(int argc, char* argv[]) {
int SolveDimacsAssignment(int argc, char *argv[]) {
std::string error_message;
// Handle on the graph we will need to delete because the
// LinearSumAssignment object does not take ownership of it.
GraphType* graph = nullptr;
GraphType *graph = nullptr;
DimacsAssignmentParser<GraphType> parser(argv[1]);
LinearSumAssignment<GraphType>* assignment =
LinearSumAssignment<GraphType> *assignment =
parser.Parse(&error_message, &graph);
if (assignment == nullptr) {
LOG(FATAL) << error_message;
}
if (!FLAGS_assignment_problem_output_file.empty()) {
if (!absl::GetFlag(FLAGS_assignment_problem_output_file).empty()) {
// The following tail array management stuff is done in a generic
// way so we can plug in different types of graphs for which the
// TailArrayManager template can be instantiated, even though we
@@ -139,12 +139,13 @@ int SolveDimacsAssignment(int argc, char* argv[]) {
// this file and making no other changes to the code.
TailArrayManager<GraphType> tail_array_manager(graph);
PrintDimacsAssignmentProblem<GraphType>(
*assignment, tail_array_manager, FLAGS_assignment_problem_output_file);
*assignment, tail_array_manager,
absl::GetFlag(FLAGS_assignment_problem_output_file));
tail_array_manager.ReleaseTailArrayIfForwardGraph();
}
CostValue hungarian_cost = 0.0;
bool hungarian_solved = false;
if (FLAGS_assignment_compare_hungarian) {
if (absl::GetFlag(FLAGS_assignment_compare_hungarian)) {
hungarian_cost = BuildAndSolveHungarianInstance(*assignment);
hungarian_solved = true;
}
@@ -169,16 +170,16 @@ int SolveDimacsAssignment(int argc, char* argv[]) {
delete graph;
return EXIT_SUCCESS;
}
} // namespace operations_research
} // namespace operations_research
static const char* const kUsageTemplate = "usage: %s <filename>";
static const char *const kUsageTemplate = "usage: %s <filename>";
using ::operations_research::ForwardStarGraph;
using ::operations_research::ForwardStarStaticGraph;
using ::operations_research::SolveDimacsAssignment;
using ::operations_research::StarGraph;
int main(int argc, char* argv[]) {
int main(int argc, char *argv[]) {
std::string usage;
if (argc < 1) {
usage = absl::StrFormat(kUsageTemplate, "solve_dimacs_assignment");
@@ -192,9 +193,9 @@ int main(int argc, char* argv[]) {
LOG(FATAL) << usage;
}
if (FLAGS_assignment_static_graph) {
if (absl::GetFlag(FLAGS_assignment_static_graph)) {
return SolveDimacsAssignment<ForwardStarStaticGraph>(argc, argv);
} else if (FLAGS_assignment_reverse_arcs) {
} else if (absl::GetFlag(FLAGS_assignment_reverse_arcs)) {
return SolveDimacsAssignment<StarGraph>(argc, argv);
} else {
return SolveDimacsAssignment<ForwardStarGraph>(argc, argv);

View File

@@ -41,9 +41,8 @@
#include "ortools/util/bitset.h"
DEFINE_int32(symbols_per_card, 8, "Number of symbols per card.");
DEFINE_int32(ls_seed, 1,
"Seed for the random number generator (used by "
"the Local Neighborhood Search).");
DEFINE_int32(ls_seed, 1, "Seed for the random number generator (used by "
"the Local Neighborhood Search).");
DEFINE_bool(use_filter, true, "Use filter in the local search to prune moves.");
DEFINE_int32(num_swaps, 4,
"If num_swap > 0, the search for an optimal "
@@ -61,14 +60,13 @@ namespace operations_research {
// sum_i(card1_symbol_vars[i]*card2_symbol_vars[i]) == count_var.
// with all card_symbol_vars[i] being boolean variables.
class SymbolsSharedByTwoCardsConstraint : public Constraint {
public:
public:
// This constructor does not take any ownership on its arguments.
SymbolsSharedByTwoCardsConstraint(
Solver* const solver, const std::vector<IntVar*>& card1_symbol_vars,
const std::vector<IntVar*>& card2_symbol_vars,
IntVar* const num_symbols_in_common_var)
: Constraint(solver),
card1_symbol_vars_(card1_symbol_vars),
Solver *const solver, const std::vector<IntVar *> &card1_symbol_vars,
const std::vector<IntVar *> &card2_symbol_vars,
IntVar *const num_symbols_in_common_var)
: Constraint(solver), card1_symbol_vars_(card1_symbol_vars),
card2_symbol_vars_(card2_symbol_vars),
num_symbols_(card1_symbol_vars.size()),
num_symbols_in_common_var_(num_symbols_in_common_var) {
@@ -96,7 +94,7 @@ class SymbolsSharedByTwoCardsConstraint : public Constraint {
// such, InitialPropagate will be called after all normal demons
// and constraints have reached a fixed point. Note
// that ownership of the 'global_demon' belongs to the solver.
Demon* const global_demon =
Demon *const global_demon =
solver()->MakeDelayedConstraintInitialPropagateCallback(this);
// Attach to all variables.
for (int i = 0; i < num_symbols_; ++i) {
@@ -177,11 +175,11 @@ class SymbolsSharedByTwoCardsConstraint : public Constraint {
}
}
private:
std::vector<IntVar*> card1_symbol_vars_;
std::vector<IntVar*> card2_symbol_vars_;
private:
std::vector<IntVar *> card1_symbol_vars_;
std::vector<IntVar *> card2_symbol_vars_;
const int num_symbols_;
IntVar* const num_symbols_in_common_var_;
IntVar *const num_symbols_in_common_var_;
};
// Creates two integer variables: one that counts the number of
@@ -189,11 +187,11 @@ class SymbolsSharedByTwoCardsConstraint : public Constraint {
// difference between the first var and 1 (i.e. the violation of the
// objective). Returns the latter (both vars are owned by the Solver
// anyway).
IntVar* CreateViolationVar(Solver* const solver,
const std::vector<IntVar*>& card1_symbol_vars,
const std::vector<IntVar*>& card2_symbol_vars,
IntVar *CreateViolationVar(Solver *const solver,
const std::vector<IntVar *> &card1_symbol_vars,
const std::vector<IntVar *> &card2_symbol_vars,
int num_symbols_per_card) {
IntVar* const num_symbols_in_common_var =
IntVar *const num_symbols_in_common_var =
solver->MakeIntVar(0, num_symbols_per_card);
// RevAlloc transfers the ownership of the constraint to the solver.
solver->AddConstraint(solver->RevAlloc(new SymbolsSharedByTwoCardsConstraint(
@@ -233,13 +231,11 @@ IntVar* CreateViolationVar(Solver* const solver,
// parent class below, which contains some shared code to store a
// compact representation of which symbols appeal on each cards.
class DobbleOperator : public IntVarLocalSearchOperator {
public:
DobbleOperator(const std::vector<IntVar*>& card_symbol_vars, int num_cards,
public:
DobbleOperator(const std::vector<IntVar *> &card_symbol_vars, int num_cards,
int num_symbols, int num_symbols_per_card)
: IntVarLocalSearchOperator(card_symbol_vars),
num_cards_(num_cards),
num_symbols_(num_symbols),
num_symbols_per_card_(num_symbols_per_card),
: IntVarLocalSearchOperator(card_symbol_vars), num_cards_(num_cards),
num_symbols_(num_symbols), num_symbols_per_card_(num_symbols_per_card),
symbols_per_card_(num_cards) {
CHECK_GT(num_cards, 0);
CHECK_GT(num_symbols, 0);
@@ -251,7 +247,7 @@ class DobbleOperator : public IntVarLocalSearchOperator {
~DobbleOperator() override {}
protected:
protected:
// OnStart() simply stores the current symbols per card in
// symbols_per_card_, and defers further initialization to the
// subclass's InitNeighborhoodSearch() method.
@@ -298,14 +294,12 @@ class DobbleOperator : public IntVarLocalSearchOperator {
// symbol to a card that already had it); see the DobbleFilter class
// below to see how we filter those out.
class SwapSymbols : public DobbleOperator {
public:
SwapSymbols(const std::vector<IntVar*>& card_symbol_vars, int num_cards,
public:
SwapSymbols(const std::vector<IntVar *> &card_symbol_vars, int num_cards,
int num_symbols, int num_symbols_per_card)
: DobbleOperator(card_symbol_vars, num_cards, num_symbols,
num_symbols_per_card),
current_card1_(-1),
current_card2_(-1),
current_symbol1_(-1),
current_card1_(-1), current_card2_(-1), current_symbol1_(-1),
current_symbol2_(-1) {}
~SwapSymbols() override {}
@@ -323,7 +317,7 @@ class SwapSymbols : public DobbleOperator {
return true;
}
private:
private:
// Reinit the exploration loop.
void InitNeighborhoodSearch() override {
current_card1_ = 0;
@@ -368,20 +362,19 @@ class SwapSymbols : public DobbleOperator {
// randomized "infinite" version instead of an iterative, exhaustive
// one.
class SwapSymbolsOnCardPairs : public DobbleOperator {
public:
SwapSymbolsOnCardPairs(const std::vector<IntVar*>& card_symbol_vars,
public:
SwapSymbolsOnCardPairs(const std::vector<IntVar *> &card_symbol_vars,
int num_cards, int num_symbols,
int num_symbols_per_card, int max_num_swaps)
: DobbleOperator(card_symbol_vars, num_cards, num_symbols,
num_symbols_per_card),
rand_(FLAGS_ls_seed),
max_num_swaps_(max_num_swaps) {
rand_(absl::GetFlag(FLAGS_ls_seed)), max_num_swaps_(max_num_swaps) {
CHECK_GE(max_num_swaps, 2);
}
~SwapSymbolsOnCardPairs() override {}
protected:
protected:
bool MakeOneNeighbor() override {
const int num_swaps =
absl::Uniform<int32_t>(rand_, 0, max_num_swaps_ - 1) + 2;
@@ -401,7 +394,7 @@ class SwapSymbolsOnCardPairs : public DobbleOperator {
void InitNeighborhoodSearch() override {}
private:
private:
std::mt19937 rand_;
const int max_num_swaps_;
};
@@ -434,20 +427,17 @@ class SwapSymbolsOnCardPairs : public DobbleOperator {
// effectively limits the number of cards to 63, and thus the number
// of symbols per card to 8.
class DobbleFilter : public IntVarLocalSearchFilter {
public:
DobbleFilter(const std::vector<IntVar*>& card_symbol_vars, int num_cards,
public:
DobbleFilter(const std::vector<IntVar *> &card_symbol_vars, int num_cards,
int num_symbols, int num_symbols_per_card)
: IntVarLocalSearchFilter(card_symbol_vars),
num_cards_(num_cards),
num_symbols_(num_symbols),
num_symbols_per_card_(num_symbols_per_card),
temporary_bitset_(0),
symbol_bitmask_per_card_(num_cards, 0),
: IntVarLocalSearchFilter(card_symbol_vars), num_cards_(num_cards),
num_symbols_(num_symbols), num_symbols_per_card_(num_symbols_per_card),
temporary_bitset_(0), symbol_bitmask_per_card_(num_cards, 0),
violation_costs_(num_cards_, std::vector<int>(num_cards_, 0)) {}
// We build the current bitmap and the matrix of violation cost
// between any two cards.
void OnSynchronize(const Assignment* delta) override {
void OnSynchronize(const Assignment *delta) override {
symbol_bitmask_per_card_.assign(num_cards_, 0);
for (int card = 0; card < num_cards_; ++card) {
for (int symbol = 0; symbol < num_symbols_; ++symbol) {
@@ -468,9 +458,9 @@ class DobbleFilter : public IntVarLocalSearchFilter {
// The LocalSearchFilter::Accept() API also takes a deltadelta,
// which is the difference between the current delta and the last
// delta that was given to Accept() -- but we don't use it here.
bool Accept(const Assignment* delta, const Assignment* unused_deltadelta,
bool Accept(const Assignment *delta, const Assignment *unused_deltadelta,
int64 objective_min, int64 objective_max) override {
const Assignment::IntContainer& solution_delta = delta->IntVarContainer();
const Assignment::IntContainer &solution_delta = delta->IntVarContainer();
const int solution_delta_size = solution_delta.Size();
// The input const Assignment* delta given to Accept() may
@@ -528,7 +518,7 @@ class DobbleFilter : public IntVarLocalSearchFilter {
return cost_delta < 0;
}
private:
private:
// Undo information after an evaluation.
struct UndoChange {
UndoChange(int c, uint64 b) : card(c), bitset(b) {}
@@ -543,14 +533,14 @@ class DobbleFilter : public IntVarLocalSearchFilter {
// For each touched card, compare against all others to compute the
// delta in term of cost. We use an bitset to avoid counting twice
// between two cards appearing in the local search move.
int ComputeNewCost(const std::vector<int>& touched_cards) {
int ComputeNewCost(const std::vector<int> &touched_cards) {
ClearBitset();
int cost_delta = 0;
for (int i = 0; i < touched_cards.size(); ++i) {
const int touched = touched_cards[i];
SetBit64(&temporary_bitset_, touched);
const uint64 card_bitset = symbol_bitmask_per_card_[touched];
const std::vector<int>& row_cost = violation_costs_[touched];
const std::vector<int> &row_cost = violation_costs_[touched];
for (int other_card = 0; other_card < num_cards_; ++other_card) {
if (!IsBitSet64(&temporary_bitset_, other_card)) {
cost_delta += ViolationCost(
@@ -563,8 +553,8 @@ class DobbleFilter : public IntVarLocalSearchFilter {
}
// Collects all card indices appearing in the local search move.
void ComputeTouchedCards(const Assignment::IntContainer& solution_delta,
std::vector<int>* const touched_cards) {
void ComputeTouchedCards(const Assignment::IntContainer &solution_delta,
std::vector<int> *const touched_cards) {
ClearBitset();
const int solution_delta_size = solution_delta.Size();
const int kUnassigned = -1;
@@ -640,8 +630,8 @@ void SolveDobble(int num_cards, int num_symbols, int num_symbols_per_card) {
// Creates the solver.
Solver solver("dobble");
// Creates the matrix of boolean variables (cards * symbols).
std::vector<std::vector<IntVar*> > card_symbol_vars(num_cards);
std::vector<IntVar*> all_card_symbol_vars;
std::vector<std::vector<IntVar *> > card_symbol_vars(num_cards);
std::vector<IntVar *> all_card_symbol_vars;
for (int card_index = 0; card_index < num_cards; ++card_index) {
solver.MakeBoolVarArray(num_symbols,
absl::StrFormat("card_%i_", card_index),
@@ -653,7 +643,7 @@ void SolveDobble(int num_cards, int num_symbols, int num_symbols_per_card) {
}
// Creates cardinality intersection variables and remember the
// violation variables.
std::vector<IntVar*> violation_vars;
std::vector<IntVar *> violation_vars;
for (int card1 = 0; card1 < num_cards; ++card1) {
for (int card2 = 0; card2 < num_cards; ++card2) {
if (card1 != card2) {
@@ -664,7 +654,7 @@ void SolveDobble(int num_cards, int num_symbols, int num_symbols_per_card) {
}
}
// Create the objective variable.
IntVar* const objective_var = solver.MakeSum(violation_vars)->Var();
IntVar *const objective_var = solver.MakeSum(violation_vars)->Var();
// Add constraint: there must be exactly num_symbols_per_card
// symbols per card.
@@ -680,7 +670,7 @@ void SolveDobble(int num_cards, int num_symbols, int num_symbols_per_card) {
// is a (non-trivial) consequence of the other constraints and of
// the model. But adding it makes the search go faster.
for (int symbol_index = 0; symbol_index < num_symbols; ++symbol_index) {
std::vector<IntVar*> tmp;
std::vector<IntVar *> tmp;
for (int card_index = 0; card_index < num_cards; ++card_index) {
tmp.push_back(card_symbol_vars[card_index][symbol_index]);
}
@@ -689,33 +679,35 @@ void SolveDobble(int num_cards, int num_symbols, int num_symbols_per_card) {
// Search.
LOG(INFO) << "Solving with Local Search";
LOG(INFO) << " - time limit = " << FLAGS_time_limit_in_ms << " ms";
LOG(INFO) << " - time limit = " << absl::GetFlag(FLAGS_time_limit_in_ms)
<< " ms";
// Start a DecisionBuilder phase to find a first solution, using the
// strategy "Pick some random, yet unassigned card symbol variable
// and set its value to 1".
DecisionBuilder* const build_db = solver.MakePhase(
all_card_symbol_vars, Solver::CHOOSE_RANDOM, // Solver::IntVarStrategy
Solver::ASSIGN_MAX_VALUE); // Solver::IntValueStrategy
DecisionBuilder *const build_db = solver.MakePhase(
all_card_symbol_vars, Solver::CHOOSE_RANDOM, // Solver::IntVarStrategy
Solver::ASSIGN_MAX_VALUE); // Solver::IntValueStrategy
// Creates local search operators.
std::vector<LocalSearchOperator*> operators;
LocalSearchOperator* const switch_operator = solver.RevAlloc(new SwapSymbols(
std::vector<LocalSearchOperator *> operators;
LocalSearchOperator *const switch_operator = solver.RevAlloc(new SwapSymbols(
all_card_symbol_vars, num_cards, num_symbols, num_symbols_per_card));
operators.push_back(switch_operator);
LOG(INFO) << " - add switch operator";
if (FLAGS_num_swaps > 0) {
LocalSearchOperator* const swaps_operator = solver.RevAlloc(
new SwapSymbolsOnCardPairs(all_card_symbol_vars, num_cards, num_symbols,
num_symbols_per_card, FLAGS_num_swaps));
if (absl::GetFlag(FLAGS_num_swaps) > 0) {
LocalSearchOperator *const swaps_operator =
solver.RevAlloc(new SwapSymbolsOnCardPairs(
all_card_symbol_vars, num_cards, num_symbols, num_symbols_per_card,
absl::GetFlag(FLAGS_num_swaps)));
operators.push_back(swaps_operator);
LOG(INFO) << " - add swaps operator with at most " << FLAGS_num_swaps
<< " swaps";
LOG(INFO) << " - add swaps operator with at most "
<< absl::GetFlag(FLAGS_num_swaps) << " swaps";
}
// Creates filter.
std::vector<LocalSearchFilter*> filters;
if (FLAGS_use_filter) {
std::vector<LocalSearchFilter *> filters;
if (absl::GetFlag(FLAGS_use_filter)) {
filters.push_back(solver.RevAlloc(new DobbleFilter(
all_card_symbol_vars, num_cards, num_symbols, num_symbols_per_card)));
}
@@ -723,42 +715,42 @@ void SolveDobble(int num_cards, int num_symbols, int num_symbols_per_card) {
// Main decision builder that regroups the first solution decision
// builder and the combination of local search operators and
// filters.
LocalSearchFilterManager* filter_manager =
LocalSearchFilterManager *filter_manager =
solver.RevAlloc(new LocalSearchFilterManager(filters));
DecisionBuilder* const final_db = solver.MakeLocalSearchPhase(
DecisionBuilder *const final_db = solver.MakeLocalSearchPhase(
all_card_symbol_vars, build_db,
solver.MakeLocalSearchPhaseParameters(
objective_var, solver.ConcatenateOperators(operators, true),
nullptr, // Sub decision builder, not needed here.
nullptr, // Limit the search for improving move, we will stop
// the exploration of the local search at the first
// improving solution (first accept).
nullptr, // Sub decision builder, not needed here.
nullptr, // Limit the search for improving move, we will stop
// the exploration of the local search at the first
// improving solution (first accept).
filter_manager));
std::vector<SearchMonitor*> monitors;
std::vector<SearchMonitor *> monitors;
// Optimize var search monitor.
OptimizeVar* const optimize = solver.MakeMinimize(objective_var, 1);
OptimizeVar *const optimize = solver.MakeMinimize(objective_var, 1);
monitors.push_back(optimize);
// Search log.
SearchMonitor* const log = solver.MakeSearchLog(100000, optimize);
SearchMonitor *const log = solver.MakeSearchLog(100000, optimize);
monitors.push_back(log);
// Search limit.
SearchLimit* const time_limit =
solver.MakeLimit(FLAGS_time_limit_in_ms, kint64max, kint64max, kint64max);
SearchLimit *const time_limit = solver.MakeLimit(
absl::GetFlag(FLAGS_time_limit_in_ms), kint64max, kint64max, kint64max);
monitors.push_back(time_limit);
// And solve!
solver.Solve(final_db, monitors);
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
// These constants comes directly from the dobble game.
// There are actually 55 cards, but we can create up to 57 cards.
const int kSymbolsPerCard = FLAGS_symbols_per_card;
const int kSymbolsPerCard = absl::GetFlag(FLAGS_symbols_per_card);
const int kCards = kSymbolsPerCard * (kSymbolsPerCard - 1) + 1;
const int kSymbols = kCards;
operations_research::SolveDobble(kCards, kSymbols, kSymbolsPerCard);

View File

@@ -30,10 +30,10 @@ namespace operations_research {
// Prints the instance of the Frequency Assignment Problem.
class FapModelPrinter {
public:
FapModelPrinter(const std::map<int, FapVariable>& variables,
const std::vector<FapConstraint>& constraints,
const std::string& objective, const std::vector<int>& values);
public:
FapModelPrinter(const std::map<int, FapVariable> &variables,
const std::vector<FapConstraint> &constraints,
const std::string &objective, const std::vector<int> &values);
~FapModelPrinter();
void PrintFapObjective();
@@ -41,7 +41,7 @@ class FapModelPrinter {
void PrintFapConstraints();
void PrintFapValues();
private:
private:
const std::map<int, FapVariable> variables_;
const std::vector<FapConstraint> constraints_;
const std::string objective_;
@@ -49,20 +49,18 @@ class FapModelPrinter {
DISALLOW_COPY_AND_ASSIGN(FapModelPrinter);
};
FapModelPrinter::FapModelPrinter(const std::map<int, FapVariable>& variables,
const std::vector<FapConstraint>& constraints,
const std::string& objective,
const std::vector<int>& values)
: variables_(variables),
constraints_(constraints),
objective_(objective),
FapModelPrinter::FapModelPrinter(const std::map<int, FapVariable> &variables,
const std::vector<FapConstraint> &constraints,
const std::string &objective,
const std::vector<int> &values)
: variables_(variables), constraints_(constraints), objective_(objective),
values_(values) {}
FapModelPrinter::~FapModelPrinter() {}
void FapModelPrinter::PrintFapVariables() {
LOG(INFO) << "Variable File:";
for (const auto& it : variables_) {
for (const auto &it : variables_) {
std::string domain = "{";
for (const int value : it.second.domain) {
absl::StrAppendFormat(&domain, "%d ", value);
@@ -87,7 +85,7 @@ void FapModelPrinter::PrintFapVariables() {
void FapModelPrinter::PrintFapConstraints() {
LOG(INFO) << "Constraint File:";
for (const FapConstraint& ct : constraints_) {
for (const FapConstraint &ct : constraints_) {
std::string hard = " ";
if (ct.hard) {
hard = " hard";
@@ -114,5 +112,5 @@ void FapModelPrinter::PrintFapValues() {
LOG(INFO) << domain;
}
} // namespace operations_research
#endif // OR_TOOLS_EXAMPLES_FAP_MODEL_PRINTER_H_
} // namespace operations_research
#endif // OR_TOOLS_EXAMPLES_FAP_MODEL_PRINTER_H_

View File

@@ -34,20 +34,15 @@ namespace operations_research {
// Takes a filename and a buffer and fills the lines buffer
// with the lines of the file corresponding to the filename.
void ParseFileByLines(const std::string& filename,
std::vector<std::string>* lines);
void ParseFileByLines(const std::string &filename,
std::vector<std::string> *lines);
// The FapVariable struct represents a radio link of the
// frequency assignment problem.
struct FapVariable {
FapVariable()
: domain_index(-1),
domain_size(0),
domain(),
degree(0),
initial_position(-1),
mobility_index(-1),
mobility_cost(-1),
: domain_index(-1), domain_size(0), domain(), degree(0),
initial_position(-1), mobility_index(-1), mobility_cost(-1),
hard(false) {}
~FapVariable() {}
@@ -84,15 +79,8 @@ struct FapVariable {
// radio links of the frequency assignment problem.
struct FapConstraint {
FapConstraint()
: variable1(-1),
variable2(-1),
impact(0),
type(""),
operation(""),
value(-1),
weight_index(-1),
weight_cost(-1),
hard(false) {}
: variable1(-1), variable2(-1), impact(0), type(""), operation(""),
value(-1), weight_index(-1), weight_cost(-1), hard(false) {}
~FapConstraint() {}
// Fields:
@@ -147,15 +135,15 @@ struct FapComponent {
// This file describes all the variables in the instance.
// Each line corresponds to one variable.
class VariableParser {
public:
explicit VariableParser(const std::string& data_directory);
public:
explicit VariableParser(const std::string &data_directory);
~VariableParser();
const std::map<int, FapVariable>& variables() const { return variables_; }
const std::map<int, FapVariable> &variables() const { return variables_; }
void Parse();
private:
private:
const std::string filename_;
// A map is used because in the model, the variables have ids which may not
// be consecutive, may be very sparse and don't have a specific upper-bound.
@@ -169,15 +157,15 @@ class VariableParser {
// This file describes the domains used by the variables of the problem.
// Each line describes one domain.
class DomainParser {
public:
explicit DomainParser(const std::string& data_directory);
public:
explicit DomainParser(const std::string &data_directory);
~DomainParser();
const std::map<int, std::vector<int> >& domains() const { return domains_; }
const std::map<int, std::vector<int> > &domains() const { return domains_; }
void Parse();
private:
private:
const std::string filename_;
// A map is used because in the model, the ids of the different available
// domains may be random values, since they are used as names. The key of the
@@ -191,15 +179,15 @@ class DomainParser {
// This file describes the constraints of the instance.
// Each line defines a binary constraint.
class ConstraintParser {
public:
explicit ConstraintParser(const std::string& data_directory);
public:
explicit ConstraintParser(const std::string &data_directory);
~ConstraintParser();
const std::vector<FapConstraint>& constraints() const { return constraints_; }
const std::vector<FapConstraint> &constraints() const { return constraints_; }
void Parse();
private:
private:
const std::string filename_;
std::vector<FapConstraint> constraints_;
@@ -211,19 +199,19 @@ class ConstraintParser {
// It may also contain 8 coefficients: 4 for different constraint violation
// costs and 4 for different variable mobility costs.
class ParametersParser {
public:
explicit ParametersParser(const std::string& data_directory);
public:
explicit ParametersParser(const std::string &data_directory);
~ParametersParser();
std::string objective() const { return objective_; }
const std::vector<int>& constraint_weights() const {
const std::vector<int> &constraint_weights() const {
return constraint_weights_;
}
const std::vector<int>& variable_weights() const { return variable_weights_; }
const std::vector<int> &variable_weights() const { return variable_weights_; }
void Parse();
private:
private:
const std::string filename_;
static const int constraint_coefficient_no_ = 4;
static const int variable_coefficient_no_ = 4;
@@ -234,33 +222,33 @@ class ParametersParser {
};
namespace {
int strtoint32(const std::string& word) {
int strtoint32(const std::string &word) {
int result;
CHECK(absl::SimpleAtoi(word, &result));
return result;
}
} // namespace
} // namespace
// Function that finds the disjoint sub-graphs of the graph of the instance.
void FindComponents(const std::vector<FapConstraint>& constraints,
const std::map<int, FapVariable>& variables,
void FindComponents(const std::vector<FapConstraint> &constraints,
const std::map<int, FapVariable> &variables,
const int maximum_variable_id,
absl::flat_hash_map<int, FapComponent>* components);
absl::flat_hash_map<int, FapComponent> *components);
// Function that computes the impact of a constraint.
int EvaluateConstraintImpact(const std::map<int, FapVariable>& variables,
int EvaluateConstraintImpact(const std::map<int, FapVariable> &variables,
const int max_weight_cost,
const FapConstraint constraint);
// Function that parses an instance of frequency assignment problem.
void ParseInstance(const std::string& data_directory, bool find_components,
std::map<int, FapVariable>* variables,
std::vector<FapConstraint>* constraints,
std::string* objective, std::vector<int>* frequencies,
absl::flat_hash_map<int, FapComponent>* components);
void ParseInstance(const std::string &data_directory, bool find_components,
std::map<int, FapVariable> *variables,
std::vector<FapConstraint> *constraints,
std::string *objective, std::vector<int> *frequencies,
absl::flat_hash_map<int, FapComponent> *components);
void ParseFileByLines(const std::string& filename,
std::vector<std::string>* lines) {
void ParseFileByLines(const std::string &filename,
std::vector<std::string> *lines) {
CHECK(lines != nullptr);
std::string result;
CHECK_OK(file::GetContents(filename, &result, file::Defaults()));
@@ -268,7 +256,7 @@ void ParseFileByLines(const std::string& filename,
}
// VariableParser Implementation
VariableParser::VariableParser(const std::string& data_directory)
VariableParser::VariableParser(const std::string &data_directory)
: filename_(data_directory + "/var.txt") {}
VariableParser::~VariableParser() {}
@@ -276,7 +264,7 @@ VariableParser::~VariableParser() {}
void VariableParser::Parse() {
std::vector<std::string> lines;
ParseFileByLines(filename_, &lines);
for (const std::string& line : lines) {
for (const std::string &line : lines) {
std::vector<std::string> tokens =
absl::StrSplit(line, ' ', absl::SkipEmpty());
if (tokens.empty()) {
@@ -295,7 +283,7 @@ void VariableParser::Parse() {
}
// DomainParser Implementation
DomainParser::DomainParser(const std::string& data_directory)
DomainParser::DomainParser(const std::string &data_directory)
: filename_(data_directory + "/dom.txt") {}
DomainParser::~DomainParser() {}
@@ -303,7 +291,7 @@ DomainParser::~DomainParser() {}
void DomainParser::Parse() {
std::vector<std::string> lines;
ParseFileByLines(filename_, &lines);
for (const std::string& line : lines) {
for (const std::string &line : lines) {
std::vector<std::string> tokens =
absl::StrSplit(line, ' ', absl::SkipEmpty());
if (tokens.empty()) {
@@ -326,7 +314,7 @@ void DomainParser::Parse() {
}
// ConstraintParser Implementation
ConstraintParser::ConstraintParser(const std::string& data_directory)
ConstraintParser::ConstraintParser(const std::string &data_directory)
: filename_(data_directory + "/ctr.txt") {}
ConstraintParser::~ConstraintParser() {}
@@ -334,7 +322,7 @@ ConstraintParser::~ConstraintParser() {}
void ConstraintParser::Parse() {
std::vector<std::string> lines;
ParseFileByLines(filename_, &lines);
for (const std::string& line : lines) {
for (const std::string &line : lines) {
std::vector<std::string> tokens =
absl::StrSplit(line, ' ', absl::SkipEmpty());
if (tokens.empty()) {
@@ -361,9 +349,8 @@ const int ParametersParser::constraint_coefficient_no_;
const int ParametersParser::variable_coefficient_no_;
const int ParametersParser::coefficient_no_;
ParametersParser::ParametersParser(const std::string& data_directory)
: filename_(data_directory + "/cst.txt"),
objective_(""),
ParametersParser::ParametersParser(const std::string &data_directory)
: filename_(data_directory + "/cst.txt"), objective_(""),
constraint_weights_(constraint_coefficient_no_, 0),
variable_weights_(variable_coefficient_no_, 0) {}
@@ -380,7 +367,7 @@ void ParametersParser::Parse() {
std::vector<std::string> lines;
ParseFileByLines(filename_, &lines);
for (const std::string& line : lines) {
for (const std::string &line : lines) {
if (objective) {
largest_token =
largest_token || (line.find("largest") != std::string::npos);
@@ -426,17 +413,17 @@ void ParametersParser::Parse() {
}
// TODO(user): Make FindComponents linear instead of quadratic.
void FindComponents(const std::vector<FapConstraint>& constraints,
const std::map<int, FapVariable>& variables,
void FindComponents(const std::vector<FapConstraint> &constraints,
const std::map<int, FapVariable> &variables,
const int maximum_variable_id,
absl::flat_hash_map<int, FapComponent>* components) {
absl::flat_hash_map<int, FapComponent> *components) {
std::vector<int> in_component(maximum_variable_id + 1, -1);
int constraint_index = 0;
for (const FapConstraint& constraint : constraints) {
for (const FapConstraint &constraint : constraints) {
const int variable_id1 = constraint.variable1;
const int variable_id2 = constraint.variable2;
const FapVariable& variable1 = gtl::FindOrDie(variables, variable_id1);
const FapVariable& variable2 = gtl::FindOrDie(variables, variable_id2);
const FapVariable &variable1 = gtl::FindOrDie(variables, variable_id1);
const FapVariable &variable2 = gtl::FindOrDie(variables, variable_id2);
CHECK_LT(variable_id1, in_component.size());
CHECK_LT(variable_id2, in_component.size());
if (in_component[variable_id1] < 0 && in_component[variable_id2] < 0) {
@@ -482,24 +469,22 @@ void FindComponents(const std::vector<FapConstraint>& constraints,
CHECK(gtl::ContainsKey(*components, max_component_index));
if (min_component_index != max_component_index) {
// Update the component_index of maximum indexed component's variables.
for (const auto& variable :
for (const auto &variable :
(*components)[max_component_index].variables) {
int variable_id = variable.first;
in_component[variable_id] = min_component_index;
}
// Insert all the variables of the maximum indexed component to the
// variables of the minimum indexed component.
((*components)[min_component_index])
.variables.insert(
((*components)[max_component_index]).variables.begin(),
((*components)[max_component_index]).variables.end());
((*components)[min_component_index]).variables
.insert(((*components)[max_component_index]).variables.begin(),
((*components)[max_component_index]).variables.end());
// Insert all the constraints of the maximum indexed component to the
// constraints of the minimum indexed component.
((*components)[min_component_index])
.constraints.insert(
((*components)[min_component_index]).constraints.end(),
((*components)[max_component_index]).constraints.begin(),
((*components)[max_component_index]).constraints.end());
((*components)[min_component_index]).constraints
.insert(((*components)[min_component_index]).constraints.end(),
((*components)[max_component_index]).constraints.begin(),
((*components)[max_component_index]).constraints.end());
(*components)[min_component_index].constraints.push_back(constraint);
// Delete the maximum indexed component from the components set.
components->erase(max_component_index);
@@ -512,12 +497,12 @@ void FindComponents(const std::vector<FapConstraint>& constraints,
}
}
int EvaluateConstraintImpact(const std::map<int, FapVariable>& variables,
int EvaluateConstraintImpact(const std::map<int, FapVariable> &variables,
const int max_weight_cost,
const FapConstraint constraint) {
const FapVariable& variable1 =
const FapVariable &variable1 =
gtl::FindOrDie(variables, constraint.variable1);
const FapVariable& variable2 =
const FapVariable &variable2 =
gtl::FindOrDie(variables, constraint.variable2);
const int degree1 = variable1.degree;
const int degree2 = variable2.degree;
@@ -535,11 +520,11 @@ int EvaluateConstraintImpact(const std::map<int, FapVariable>& variables,
return max_degree + min_degree + operator_impact + hardness_impact;
}
void ParseInstance(const std::string& data_directory, bool find_components,
std::map<int, FapVariable>* variables,
std::vector<FapConstraint>* constraints,
std::string* objective, std::vector<int>* frequencies,
absl::flat_hash_map<int, FapComponent>* components) {
void ParseInstance(const std::string &data_directory, bool find_components,
std::map<int, FapVariable> *variables,
std::vector<FapConstraint> *constraints,
std::string *objective, std::vector<int> *frequencies,
absl::flat_hash_map<int, FapComponent> *components) {
CHECK(variables != nullptr);
CHECK(constraints != nullptr);
CHECK(objective != nullptr);
@@ -564,7 +549,7 @@ void ParseInstance(const std::string& data_directory, bool find_components,
(cst.constraint_weights()).begin(), (cst.constraint_weights()).end());
// Make the variables of the instance.
for (auto& it : *variables) {
for (auto &it : *variables) {
it.second.domain = gtl::FindOrDie(dom.domains(), it.second.domain_index);
it.second.domain_size = it.second.domain.size();
@@ -579,7 +564,7 @@ void ParseInstance(const std::string& data_directory, bool find_components,
}
}
// Make the constraints of the instance.
for (FapConstraint& ct : *constraints) {
for (FapConstraint &ct : *constraints) {
if ((ct.weight_index == -1) || (ct.weight_index == 0)) {
ct.weight_cost = -1;
ct.hard = true;
@@ -599,18 +584,18 @@ void ParseInstance(const std::string& data_directory, bool find_components,
CHECK(components != nullptr);
FindComponents(*constraints, *variables, maximum_variable_id, components);
// Evaluate each components's constraints impacts.
for (auto& component : *components) {
for (auto& constraint : component.second.constraints) {
for (auto &component : *components) {
for (auto &constraint : component.second.constraints) {
constraint.impact = EvaluateConstraintImpact(
*variables, maximum_weight_cost, constraint);
}
}
} else {
for (FapConstraint& constraint : *constraints) {
for (FapConstraint &constraint : *constraints) {
constraint.impact =
EvaluateConstraintImpact(*variables, maximum_weight_cost, constraint);
}
}
}
} // namespace operations_research
#endif // OR_TOOLS_EXAMPLES_FAP_PARSER_H_
} // namespace operations_research
#endif // OR_TOOLS_EXAMPLES_FAP_PARSER_H_

View File

@@ -33,48 +33,48 @@ namespace operations_research {
// Checks if the solution given from the Solver satisfies all
// the hard binary constraints specified in the ctr.txt.
bool CheckConstraintSatisfaction(
const std::vector<FapConstraint>& data_constraints,
const std::vector<int>& variables,
const std::map<int, int>& index_from_key);
const std::vector<FapConstraint> &data_constraints,
const std::vector<int> &variables,
const std::map<int, int> &index_from_key);
// Checks if the solution given from the Solver has not modified the values of
// the variables that were initially assigned and denoted as hard in var.txt.
bool CheckVariablePosition(const std::map<int, FapVariable>& data_variables,
const std::vector<int>& variables,
const std::map<int, int>& index_from_key);
bool CheckVariablePosition(const std::map<int, FapVariable> &data_variables,
const std::vector<int> &variables,
const std::map<int, int> &index_from_key);
// Counts the number of different values in the variable vector.
int NumberOfAssignedValues(const std::vector<int>& variables);
int NumberOfAssignedValues(const std::vector<int> &variables);
// Prints the duration of the solving process.
void PrintElapsedTime(const int64 time1, const int64 time2);
// Prints the solution found by the Hard Solver for feasible instances.
void PrintResultsHard(SolutionCollector* const collector,
const std::vector<IntVar*>& variables,
IntVar* const objective_var,
const std::map<int, FapVariable>& data_variables,
const std::vector<FapConstraint>& data_constraints,
const std::map<int, int>& index_from_key,
const std::vector<int>& key_from_index);
void PrintResultsHard(SolutionCollector *const collector,
const std::vector<IntVar *> &variables,
IntVar *const objective_var,
const std::map<int, FapVariable> &data_variables,
const std::vector<FapConstraint> &data_constraints,
const std::map<int, int> &index_from_key,
const std::vector<int> &key_from_index);
// Prints the solution found by the Soft Solver for unfeasible instances.
void PrintResultsSoft(SolutionCollector* const collector,
const std::vector<IntVar*>& variables,
IntVar* const total_cost,
const std::map<int, FapVariable>& hard_variables,
const std::vector<FapConstraint>& hard_constraints,
const std::map<int, FapVariable>& soft_variables,
const std::vector<FapConstraint>& soft_constraints,
const std::map<int, int>& index_from_key,
const std::vector<int>& key_from_index);
void PrintResultsSoft(SolutionCollector *const collector,
const std::vector<IntVar *> &variables,
IntVar *const total_cost,
const std::map<int, FapVariable> &hard_variables,
const std::vector<FapConstraint> &hard_constraints,
const std::map<int, FapVariable> &soft_variables,
const std::vector<FapConstraint> &soft_constraints,
const std::map<int, int> &index_from_key,
const std::vector<int> &key_from_index);
bool CheckConstraintSatisfaction(
const std::vector<FapConstraint>& data_constraints,
const std::vector<int>& variables,
const std::map<int, int>& index_from_key) {
bool
CheckConstraintSatisfaction(const std::vector<FapConstraint> &data_constraints,
const std::vector<int> &variables,
const std::map<int, int> &index_from_key) {
bool status = true;
for (const FapConstraint& ct : data_constraints) {
for (const FapConstraint &ct : data_constraints) {
const int index1 = gtl::FindOrDie(index_from_key, ct.variable1);
const int index2 = gtl::FindOrDie(index_from_key, ct.variable2);
CHECK_LT(index1, variables.size());
@@ -100,11 +100,11 @@ bool CheckConstraintSatisfaction(
return status;
}
bool CheckVariablePosition(const std::map<int, FapVariable>& data_variables,
const std::vector<int>& variables,
const std::map<int, int>& index_from_key) {
bool CheckVariablePosition(const std::map<int, FapVariable> &data_variables,
const std::vector<int> &variables,
const std::map<int, int> &index_from_key) {
bool status = true;
for (const auto& it : data_variables) {
for (const auto &it : data_variables) {
const int index = gtl::FindOrDie(index_from_key, it.first);
CHECK_LT(index, variables.size());
const int var = variables[index];
@@ -120,7 +120,7 @@ bool CheckVariablePosition(const std::map<int, FapVariable>& data_variables,
return status;
}
int NumberOfAssignedValues(const std::vector<int>& variables) {
int NumberOfAssignedValues(const std::vector<int> &variables) {
std::set<int> assigned(variables.begin(), variables.end());
return static_cast<int>(assigned.size());
}
@@ -131,18 +131,18 @@ void PrintElapsedTime(const int64 time1, const int64 time2) {
<< " seconds.";
}
void PrintResultsHard(SolutionCollector* const collector,
const std::vector<IntVar*>& variables,
IntVar* const objective_var,
const std::map<int, FapVariable>& data_variables,
const std::vector<FapConstraint>& data_constraints,
const std::map<int, int>& index_from_key,
const std::vector<int>& key_from_index) {
void PrintResultsHard(SolutionCollector *const collector,
const std::vector<IntVar *> &variables,
IntVar *const objective_var,
const std::map<int, FapVariable> &data_variables,
const std::vector<FapConstraint> &data_constraints,
const std::map<int, int> &index_from_key,
const std::vector<int> &key_from_index) {
LOG(INFO) << "Printing...";
LOG(INFO) << "Number of Solutions: " << collector->solution_count();
for (int solution_index = 0; solution_index < collector->solution_count();
++solution_index) {
Assignment* const solution = collector->solution(solution_index);
Assignment *const solution = collector->solution(solution_index);
std::vector<int> results(variables.size());
LOG(INFO) << "------------------------------------------------------------";
LOG(INFO) << "Solution " << solution_index + 1;
@@ -164,27 +164,27 @@ void PrintResultsHard(SolutionCollector* const collector,
}
LOG(INFO) << "Values used: " << NumberOfAssignedValues(results);
LOG(INFO) << "Maximum value used: "
<< *std::max_element(results.begin(), results.end());
LOG(INFO) << "Maximum value used: " << *std::max_element(results.begin(),
results.end());
LOG(INFO) << " Failures: " << collector->failures(solution_index);
}
LOG(INFO) << " ============================================================";
}
void PrintResultsSoft(SolutionCollector* const collector,
const std::vector<IntVar*>& variables,
IntVar* const total_cost,
const std::map<int, FapVariable>& hard_variables,
const std::vector<FapConstraint>& hard_constraints,
const std::map<int, FapVariable>& soft_variables,
const std::vector<FapConstraint>& soft_constraints,
const std::map<int, int>& index_from_key,
const std::vector<int>& key_from_index) {
void PrintResultsSoft(SolutionCollector *const collector,
const std::vector<IntVar *> &variables,
IntVar *const total_cost,
const std::map<int, FapVariable> &hard_variables,
const std::vector<FapConstraint> &hard_constraints,
const std::map<int, FapVariable> &soft_variables,
const std::vector<FapConstraint> &soft_constraints,
const std::map<int, int> &index_from_key,
const std::vector<int> &key_from_index) {
LOG(INFO) << "Printing...";
LOG(INFO) << "Number of Solutions: " << collector->solution_count();
for (int solution_index = 0; solution_index < collector->solution_count();
++solution_index) {
Assignment* const solution = collector->solution(solution_index);
Assignment *const solution = collector->solution(solution_index);
std::vector<int> results(variables.size());
LOG(INFO) << "------------------------------------------------------------";
LOG(INFO) << "Solution";
@@ -216,12 +216,12 @@ void PrintResultsSoft(SolutionCollector* const collector,
}
LOG(INFO) << "Values used: " << NumberOfAssignedValues(results);
LOG(INFO) << "Maximum value used: "
<< *std::max_element(results.begin(), results.end());
LOG(INFO) << "Maximum value used: " << *std::max_element(results.begin(),
results.end());
LOG(INFO) << " Failures: " << collector->failures(solution_index);
}
LOG(INFO) << " ============================================================";
}
} // namespace operations_research
#endif // OR_TOOLS_EXAMPLES_FAP_UTILITIES_H_
} // namespace operations_research
#endif // OR_TOOLS_EXAMPLES_FAP_UTILITIES_H_

View File

@@ -27,10 +27,10 @@ void MinCostFlowOn4x4Matrix() {
LOG(INFO) << "Min Cost Flow on 4x4 Matrix";
const int kNumSources = 4;
const int kNumTargets = 4;
const CostValue kCost[kNumSources][kNumTargets] = {{90, 75, 75, 80},
{35, 85, 55, 65},
{125, 95, 90, 105},
{45, 110, 95, 115}};
const CostValue kCost[kNumSources][kNumTargets] = { { 90, 75, 75, 80 },
{ 35, 85, 55, 65 },
{ 125, 95, 90, 105 },
{ 45, 110, 95, 115 } };
const CostValue kExpectedCost = 275;
StarGraph graph(kNumSources + kNumTargets, kNumSources * kNumTargets);
MinCostFlow min_cost_flow(&graph);
@@ -59,10 +59,10 @@ void MaxFeasibleFlow() {
LOG(INFO) << "Max Feasible Flow";
const int kNumNodes = 6;
const int kNumArcs = 9;
const NodeIndex kTail[kNumArcs] = {0, 0, 0, 0, 1, 2, 3, 3, 4};
const NodeIndex kHead[kNumArcs] = {1, 2, 3, 4, 3, 4, 4, 5, 5};
const FlowQuantity kCapacity[kNumArcs] = {5, 8, 5, 3, 4, 5, 6, 6, 4};
const FlowQuantity kExpectedFlow[kNumArcs] = {1, 1, 5, 3, 1, 1, 0, 6, 4};
const NodeIndex kTail[kNumArcs] = { 0, 0, 0, 0, 1, 2, 3, 3, 4 };
const NodeIndex kHead[kNumArcs] = { 1, 2, 3, 4, 3, 4, 4, 5, 5 };
const FlowQuantity kCapacity[kNumArcs] = { 5, 8, 5, 3, 4, 5, 6, 6, 4 };
const FlowQuantity kExpectedFlow[kNumArcs] = { 1, 1, 5, 3, 1, 1, 0, 6, 4 };
const FlowQuantity kExpectedTotalFlow = 10;
StarGraph graph(kNumNodes, kNumArcs);
MaxFlow max_flow(&graph, 0, kNumNodes - 1);
@@ -78,9 +78,9 @@ void MaxFeasibleFlow() {
CHECK_EQ(kExpectedFlow[i], max_flow.Flow(i)) << " i = " << i;
}
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
operations_research::MinCostFlowOn4x4Matrix();
operations_research::MaxFeasibleFlow();

View File

@@ -89,42 +89,40 @@ namespace operations_research {
// Decision on the relative order that the two variables of a constraint
// will have. It takes as parameters the components of the constraint.
class OrderingDecision : public Decision {
public:
OrderingDecision(IntVar* const variable1, IntVar* const variable2, int value,
public:
OrderingDecision(IntVar *const variable1, IntVar *const variable2, int value,
std::string operation)
: variable1_(variable1),
variable2_(variable2),
value_(value),
: variable1_(variable1), variable2_(variable2), value_(value),
operator_(std::move(operation)) {}
~OrderingDecision() override {}
// Apply will be called first when the decision is executed.
void Apply(Solver* const s) override {
void Apply(Solver *const s) override {
// variable1 < variable2
MakeDecision(s, variable1_, variable2_);
}
// Refute will be called after a backtrack.
void Refute(Solver* const s) override {
void Refute(Solver *const s) override {
// variable1 > variable2
MakeDecision(s, variable2_, variable1_);
}
private:
void MakeDecision(Solver* s, IntVar* variable1, IntVar* variable2) {
private:
void MakeDecision(Solver *s, IntVar *variable1, IntVar *variable2) {
if (operator_ == ">") {
IntExpr* difference = (s->MakeDifference(variable2, variable1));
IntExpr *difference = (s->MakeDifference(variable2, variable1));
s->AddConstraint(s->MakeGreater(difference, value_));
} else if (operator_ == "=") {
IntExpr* difference = (s->MakeDifference(variable2, variable1));
IntExpr *difference = (s->MakeDifference(variable2, variable1));
s->AddConstraint(s->MakeEquality(difference, value_));
} else {
LOG(FATAL) << "No right operator specified.";
}
}
IntVar* const variable1_;
IntVar* const variable2_;
IntVar *const variable1_;
IntVar *const variable2_;
const int value_;
const std::string operator_;
@@ -134,26 +132,26 @@ class OrderingDecision : public Decision {
// Decision on whether a soft constraint will be added to a model
// or if it will be violated.
class ConstraintDecision : public Decision {
public:
explicit ConstraintDecision(IntVar* const constraint_violation)
public:
explicit ConstraintDecision(IntVar *const constraint_violation)
: constraint_violation_(constraint_violation) {}
~ConstraintDecision() override {}
// Apply will be called first when the decision is executed.
void Apply(Solver* const s) override {
void Apply(Solver *const s) override {
// The constraint with which the builder is dealing, will be satisfied.
constraint_violation_->SetValue(0);
}
// Refute will be called after a backtrack.
void Refute(Solver* const s) override {
void Refute(Solver *const s) override {
// The constraint with which the builder is dealing, will not be satisfied.
constraint_violation_->SetValue(1);
}
private:
IntVar* const constraint_violation_;
private:
IntVar *const constraint_violation_;
DISALLOW_COPY_AND_ASSIGN(ConstraintDecision);
};
@@ -163,23 +161,23 @@ class ConstraintDecision : public Decision {
// solving becomes much more efficient since we are branching on the
// disjunction implied by the absolute value expression.
class OrderingBuilder : public DecisionBuilder {
public:
enum Order { LESS = -1, EQUAL = 0, GREATER = 1 };
public:
enum Order {
LESS = -1,
EQUAL = 0,
GREATER = 1
};
OrderingBuilder(const std::map<int, FapVariable>& data_variables,
const std::vector<FapConstraint>& data_constraints,
const std::vector<IntVar*>& variables,
const std::vector<IntVar*>& violated_constraints,
const std::map<int, int>& index_from_key)
: data_variables_(data_variables),
data_constraints_(data_constraints),
variables_(variables),
violated_constraints_(violated_constraints),
index_from_key_(index_from_key),
size_(data_constraints.size()),
iter_(0),
checked_iter_(0) {
for (const auto& it : data_variables_) {
OrderingBuilder(const std::map<int, FapVariable> &data_variables,
const std::vector<FapConstraint> &data_constraints,
const std::vector<IntVar *> &variables,
const std::vector<IntVar *> &violated_constraints,
const std::map<int, int> &index_from_key)
: data_variables_(data_variables), data_constraints_(data_constraints),
variables_(variables), violated_constraints_(violated_constraints),
index_from_key_(index_from_key), size_(data_constraints.size()),
iter_(0), checked_iter_(0) {
for (const auto &it : data_variables_) {
int first_element = (it.second.domain)[0];
minimum_value_available_.push_back(first_element);
variable_state_.push_back(EQUAL);
@@ -190,13 +188,13 @@ class OrderingBuilder : public DecisionBuilder {
~OrderingBuilder() override {}
Decision* Next(Solver* const s) override {
Decision *Next(Solver *const s) override {
if (iter_ < size_) {
FapConstraint constraint = data_constraints_[iter_];
const int index1 = gtl::FindOrDie(index_from_key_, constraint.variable1);
const int index2 = gtl::FindOrDie(index_from_key_, constraint.variable2);
IntVar* variable1 = variables_[index1];
IntVar* variable2 = variables_[index2];
IntVar *variable1 = variables_[index1];
IntVar *variable2 = variables_[index2];
// checked_iter is equal to 0 means that whether the constraint is to be
// added or dropped hasn't been checked.
@@ -204,7 +202,7 @@ class OrderingBuilder : public DecisionBuilder {
// of the constraint is to be done.
if (!checked_iter_ && !constraint.hard) {
// New Soft Constraint: Check if it will be added or dropped.
ConstraintDecision* constraint_decision =
ConstraintDecision *constraint_decision =
new ConstraintDecision(violated_constraints_[iter_]);
s->SaveAndAdd(&checked_iter_, 1);
@@ -215,7 +213,7 @@ class OrderingBuilder : public DecisionBuilder {
if (violated_constraints_[iter_]->Bound() &&
violated_constraints_[iter_]->Value() == 0) {
// If the constraint is added, do the ordering of its variables.
OrderingDecision* ordering_decision;
OrderingDecision *ordering_decision;
Order hint = Hint(constraint);
if (hint == LESS || hint == EQUAL) {
ordering_decision = new OrderingDecision(
@@ -239,7 +237,7 @@ class OrderingBuilder : public DecisionBuilder {
}
}
private:
private:
Order Variable1LessVariable2(const int variable1, const int variable2,
const int value) {
minimum_value_available_[variable2] =
@@ -268,7 +266,7 @@ class OrderingBuilder : public DecisionBuilder {
// variable2. This ordering is more efficient if used with the
// Solver::ASSIGN_MIN_VALUE value selection strategy.
// It returns 1 if variable1 > variable2 or -1 if variable1 < variable2.
Order Hint(const FapConstraint& constraint) {
Order Hint(const FapConstraint &constraint) {
const int id1 = constraint.variable1;
const int id2 = constraint.variable2;
const int variable1 = gtl::FindOrDie(index_from_key_, id1);
@@ -306,8 +304,8 @@ class OrderingBuilder : public DecisionBuilder {
// Passed as arguments from the function that creates the Decision Builder.
const std::map<int, FapVariable> data_variables_;
const std::vector<FapConstraint> data_constraints_;
const std::vector<IntVar*> variables_;
const std::vector<IntVar*> violated_constraints_;
const std::vector<IntVar *> variables_;
const std::vector<IntVar *> violated_constraints_;
const std::map<int, int> index_from_key_;
// Used by Next() for monitoring decisions.
const int size_;
@@ -330,12 +328,12 @@ bool ConstraintImpactComparator(FapConstraint constraint1,
}
int64 ValueEvaluator(
absl::flat_hash_map<int64, std::pair<int64, int64>>* value_evaluator_map,
absl::flat_hash_map<int64, std::pair<int64, int64> > *value_evaluator_map,
int64 variable_index, int64 value) {
CHECK(value_evaluator_map != nullptr);
// Evaluate the choice. Smaller ranking denotes a better choice.
int64 ranking = -1;
for (const auto& it : *value_evaluator_map) {
for (const auto &it : *value_evaluator_map) {
if ((it.first != variable_index) && (it.second.first == value)) {
ranking = -2;
break;
@@ -343,7 +341,7 @@ int64 ValueEvaluator(
}
// Update the history of assigned values and their rankings of each variable.
absl::flat_hash_map<int64, std::pair<int64, int64>>::iterator it;
absl::flat_hash_map<int64, std::pair<int64, int64> >::iterator it;
int64 new_value = value;
int64 new_ranking = ranking;
if ((it = value_evaluator_map->find(variable_index)) !=
@@ -367,8 +365,8 @@ int64 ValueEvaluator(
// The variables which participate in more constraints and have the
// smaller domain should be in higher priority for assignment.
int64 VariableEvaluator(const std::vector<int>& key_from_index,
const std::map<int, FapVariable>& data_variables,
int64 VariableEvaluator(const std::vector<int> &key_from_index,
const std::map<int, FapVariable> &data_variables,
int64 variable_index) {
FapVariable variable =
gtl::FindOrDie(data_variables, key_from_index[variable_index]);
@@ -377,10 +375,11 @@ int64 VariableEvaluator(const std::vector<int>& key_from_index,
}
// Creates the variables of the solver from the parsed data.
void CreateModelVariables(const std::map<int, FapVariable>& data_variables,
Solver* solver, std::vector<IntVar*>* model_variables,
std::map<int, int>* index_from_key,
std::vector<int>* key_from_index) {
void CreateModelVariables(const std::map<int, FapVariable> &data_variables,
Solver *solver,
std::vector<IntVar *> *model_variables,
std::map<int, int> *index_from_key,
std::vector<int> *key_from_index) {
CHECK(solver != nullptr);
CHECK(model_variables != nullptr);
CHECK(index_from_key != nullptr);
@@ -391,7 +390,7 @@ void CreateModelVariables(const std::map<int, FapVariable>& data_variables,
key_from_index->resize(number_of_variables);
int index = 0;
for (const auto& it : data_variables) {
for (const auto &it : data_variables) {
CHECK_LT(index, model_variables->size());
(*model_variables)[index] = solver->MakeIntVar(it.second.domain);
gtl::InsertOrUpdate(index_from_key, it.first, index);
@@ -407,20 +406,20 @@ void CreateModelVariables(const std::map<int, FapVariable>& data_variables,
}
// Creates the constraints of the instance from the parsed data.
void CreateModelConstraints(const std::vector<FapConstraint>& data_constraints,
const std::vector<IntVar*>& variables,
const std::map<int, int>& index_from_key,
Solver* solver) {
void CreateModelConstraints(const std::vector<FapConstraint> &data_constraints,
const std::vector<IntVar *> &variables,
const std::map<int, int> &index_from_key,
Solver *solver) {
CHECK(solver != nullptr);
for (const FapConstraint& ct : data_constraints) {
for (const FapConstraint &ct : data_constraints) {
const int index1 = gtl::FindOrDie(index_from_key, ct.variable1);
const int index2 = gtl::FindOrDie(index_from_key, ct.variable2);
CHECK_LT(index1, variables.size());
CHECK_LT(index2, variables.size());
IntVar* var1 = variables[index1];
IntVar* var2 = variables[index2];
IntVar* absolute_difference =
IntVar *var1 = variables[index1];
IntVar *var2 = variables[index2];
IntVar *absolute_difference =
solver->MakeAbs(solver->MakeDifference(var1, var2))->Var();
if (ct.operation == ">") {
solver->AddConstraint(solver->MakeGreater(absolute_difference, ct.value));
@@ -436,67 +435,69 @@ void CreateModelConstraints(const std::vector<FapConstraint>& data_constraints,
// According to the value of a command line flag, chooses the strategy which
// determines the selection of the variable to be assigned next.
void ChooseVariableStrategy(Solver::IntVarStrategy* variable_strategy) {
void ChooseVariableStrategy(Solver::IntVarStrategy *variable_strategy) {
CHECK(variable_strategy != nullptr);
switch (FLAGS_choose_next_variable_strategy) {
case 1: {
*variable_strategy = Solver::CHOOSE_FIRST_UNBOUND;
LOG(INFO) << "Using Solver::CHOOSE_FIRST_UNBOUND "
"for variable selection strategy.";
break;
}
case 2: {
*variable_strategy = Solver::CHOOSE_MIN_SIZE_LOWEST_MIN;
LOG(INFO) << "Using Solver::CHOOSE_MIN_SIZE_LOWEST_MIN "
"for variable selection strategy.";
break;
}
case 3: {
*variable_strategy = Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX;
LOG(INFO) << "Using Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX "
"for variable selection strategy.";
break;
}
case 4: {
*variable_strategy = Solver::CHOOSE_RANDOM;
LOG(INFO) << "Using Solver::CHOOSE_RANDOM "
"for variable selection strategy.";
break;
}
default: {
LOG(FATAL) << "Should not be here";
return;
}
switch (absl::GetFlag(FLAGS_choose_next_variable_strategy)) {
case 1: {
*variable_strategy = Solver::CHOOSE_FIRST_UNBOUND;
LOG(INFO) << "Using Solver::CHOOSE_FIRST_UNBOUND "
"for variable selection strategy.";
break;
}
case 2: {
*variable_strategy = Solver::CHOOSE_MIN_SIZE_LOWEST_MIN;
LOG(INFO) << "Using Solver::CHOOSE_MIN_SIZE_LOWEST_MIN "
"for variable selection strategy.";
break;
}
case 3: {
*variable_strategy = Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX;
LOG(INFO) << "Using Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX "
"for variable selection strategy.";
break;
}
case 4: {
*variable_strategy = Solver::CHOOSE_RANDOM;
LOG(INFO) << "Using Solver::CHOOSE_RANDOM "
"for variable selection strategy.";
break;
}
default: {
LOG(FATAL) << "Should not be here";
return;
}
}
}
// According to the values of some command line flags, adds some monitors
// for the search of the Solver.
void CreateAdditionalMonitors(OptimizeVar* const objective, Solver* solver,
std::vector<SearchMonitor*>* monitors) {
void CreateAdditionalMonitors(OptimizeVar *const objective, Solver *solver,
std::vector<SearchMonitor *> *monitors) {
CHECK(solver != nullptr);
CHECK(monitors != nullptr);
// Search Log
if (FLAGS_log_search) {
SearchMonitor* const log = solver->MakeSearchLog(100000, objective);
if (absl::GetFlag(FLAGS_log_search)) {
SearchMonitor *const log = solver->MakeSearchLog(100000, objective);
monitors->push_back(log);
}
// Time Limit
if (FLAGS_time_limit_in_ms != 0) {
LOG(INFO) << "Adding time limit of " << FLAGS_time_limit_in_ms << " ms.";
SearchLimit* const limit = solver->MakeLimit(
FLAGS_time_limit_in_ms, kint64max, kint64max, kint64max);
if (absl::GetFlag(FLAGS_time_limit_in_ms) != 0) {
LOG(INFO) << "Adding time limit of "
<< absl::GetFlag(FLAGS_time_limit_in_ms) << " ms.";
SearchLimit *const limit = solver->MakeLimit(
absl::GetFlag(FLAGS_time_limit_in_ms), kint64max, kint64max, kint64max);
monitors->push_back(limit);
}
// Search Restart
SearchMonitor* const restart =
FLAGS_restart != -1
? (FLAGS_luby ? solver->MakeLubyRestart(FLAGS_restart)
: solver->MakeConstantRestart(FLAGS_restart))
SearchMonitor *const restart =
absl::GetFlag(FLAGS_restart) != -1
? (absl::GetFlag(FLAGS_luby)
? solver->MakeLubyRestart(absl::GetFlag(FLAGS_restart))
: solver->MakeConstantRestart(absl::GetFlag(FLAGS_restart)))
: nullptr;
if (restart) {
monitors->push_back(restart);
@@ -507,15 +508,15 @@ void CreateAdditionalMonitors(OptimizeVar* const objective, Solver* solver,
// instances of the problem with objective either the minimization of
// the largest frequency assigned or the minimization of the number
// of frequencies used to the solution.
void HardFapSolver(const std::map<int, FapVariable>& data_variables,
const std::vector<FapConstraint>& data_constraints,
const std::string& data_objective,
const std::vector<int>& values) {
void HardFapSolver(const std::map<int, FapVariable> &data_variables,
const std::vector<FapConstraint> &data_constraints,
const std::string &data_objective,
const std::vector<int> &values) {
Solver solver("HardFapSolver");
std::vector<SearchMonitor*> monitors;
std::vector<SearchMonitor *> monitors;
// Create Model Variables.
std::vector<IntVar*> variables;
std::vector<IntVar *> variables;
std::map<int, int> index_from_key;
std::vector<int> key_from_index;
CreateModelVariables(data_variables, &solver, &variables, &index_from_key,
@@ -529,15 +530,15 @@ void HardFapSolver(const std::map<int, FapVariable>& data_variables,
std::sort(ordered_constraints.begin(), ordered_constraints.end(),
ConstraintImpactComparator);
std::vector<IntVar*> violated_constraints;
std::vector<IntVar *> violated_constraints;
solver.MakeIntVarArray(ordered_constraints.size(), 0, 0,
&violated_constraints);
// Objective:
// Either minimize the largest assigned frequency or
// minimize the number of different frequencies assigned.
IntVar* objective_var;
OptimizeVar* objective;
IntVar *objective_var;
OptimizeVar *objective;
if (data_objective == "Minimize the largest assigned value.") {
LOG(INFO) << "Minimize the largest assigned value.";
// The objective_var is set to hold the maximum value assigned
@@ -547,11 +548,11 @@ void HardFapSolver(const std::map<int, FapVariable>& data_variables,
} else if (data_objective == "Minimize the number of assigned values.") {
LOG(INFO) << "Minimize the number of assigned values.";
std::vector<IntVar*> cardinality;
std::vector<IntVar *> cardinality;
solver.MakeIntVarArray(static_cast<int>(values.size()), 0,
static_cast<int>(variables.size()), &cardinality);
solver.AddConstraint(solver.MakeDistribute(variables, values, cardinality));
std::vector<IntVar*> value_not_assigned;
std::vector<IntVar *> value_not_assigned;
for (int val = 0; val < values.size(); ++val) {
value_not_assigned.push_back(
solver.MakeIsEqualCstVar(cardinality[val], 0));
@@ -568,7 +569,7 @@ void HardFapSolver(const std::map<int, FapVariable>& data_variables,
monitors.push_back(objective);
// Ordering Builder
OrderingBuilder* ob = solver.RevAlloc(
OrderingBuilder *ob = solver.RevAlloc(
new OrderingBuilder(data_variables, ordered_constraints, variables,
violated_constraints, index_from_key));
@@ -577,14 +578,15 @@ void HardFapSolver(const std::map<int, FapVariable>& data_variables,
Solver::IntVarStrategy variable_strategy;
ChooseVariableStrategy(&variable_strategy);
// Choose the value selection strategy.
DecisionBuilder* db;
absl::flat_hash_map<int64, std::pair<int64, int64>> history;
if (FLAGS_value_evaluator == "value_evaluator") {
DecisionBuilder *db;
absl::flat_hash_map<int64, std::pair<int64, int64> > history;
if (absl::GetFlag(FLAGS_value_evaluator) == "value_evaluator") {
LOG(INFO) << "Using ValueEvaluator for value selection strategy.";
Solver::IndexEvaluator2 index_evaluator2 = [&history](int64 var,
int64 value) {
Solver::IndexEvaluator2 index_evaluator2 =
[&history](int64 var, int64 value) {
return ValueEvaluator(&history, var, value);
};
}
;
LOG(INFO) << "Using ValueEvaluator for value selection strategy.";
db = solver.MakePhase(variables, variable_strategy, index_evaluator2);
} else {
@@ -593,13 +595,13 @@ void HardFapSolver(const std::map<int, FapVariable>& data_variables,
Solver::ASSIGN_MIN_VALUE);
}
DecisionBuilder* final_db = solver.Compose(ob, db);
DecisionBuilder *final_db = solver.Compose(ob, db);
// Create Additional Monitors.
CreateAdditionalMonitors(objective, &solver, &monitors);
// Collector
SolutionCollector* const collector = solver.MakeLastSolutionCollector();
SolutionCollector *const collector = solver.MakeLastSolutionCollector();
collector->Add(variables);
collector->Add(objective_var);
monitors.push_back(collector);
@@ -611,21 +613,21 @@ void HardFapSolver(const std::map<int, FapVariable>& data_variables,
const int64 time2 = solver.wall_time();
// Display Time.
if (FLAGS_display_time) {
if (absl::GetFlag(FLAGS_display_time)) {
PrintElapsedTime(time1, time2);
}
// Display Results.
if (FLAGS_display_results) {
if (absl::GetFlag(FLAGS_display_results)) {
PrintResultsHard(collector, variables, objective_var, data_variables,
data_constraints, index_from_key, key_from_index);
}
}
// Splits variables of the instance to hard and soft.
void SplitVariablesHardSoft(const std::map<int, FapVariable>& data_variables,
std::map<int, FapVariable>* hard_variables,
std::map<int, FapVariable>* soft_variables) {
for (const auto& it : data_variables) {
void SplitVariablesHardSoft(const std::map<int, FapVariable> &data_variables,
std::map<int, FapVariable> *hard_variables,
std::map<int, FapVariable> *soft_variables) {
for (const auto &it : data_variables) {
if (it.second.initial_position != -1) {
if (it.second.hard) {
CHECK_LT(it.second.mobility_cost, 0);
@@ -639,10 +641,10 @@ void SplitVariablesHardSoft(const std::map<int, FapVariable>& data_variables,
}
// Splits constraints of the instance to hard and soft.
void SplitConstraintHardSoft(const std::vector<FapConstraint>& data_constraints,
std::vector<FapConstraint>* hard_constraints,
std::vector<FapConstraint>* soft_constraints) {
for (const FapConstraint& ct : data_constraints) {
void SplitConstraintHardSoft(const std::vector<FapConstraint> &data_constraints,
std::vector<FapConstraint> *hard_constraints,
std::vector<FapConstraint> *soft_constraints) {
for (const FapConstraint &ct : data_constraints) {
if (ct.hard) {
CHECK_LT(ct.weight_cost, 0);
hard_constraints->push_back(ct);
@@ -655,17 +657,17 @@ void SplitConstraintHardSoft(const std::vector<FapConstraint>& data_constraints,
// Penalize the modification of the initial position of soft variable of
// the instance.
void PenalizeVariablesViolation(
const std::map<int, FapVariable>& soft_variables,
const std::map<int, int>& index_from_key,
const std::vector<IntVar*>& variables, std::vector<IntVar*>* cost,
Solver* solver) {
for (const auto& it : soft_variables) {
void
PenalizeVariablesViolation(const std::map<int, FapVariable> &soft_variables,
const std::map<int, int> &index_from_key,
const std::vector<IntVar *> &variables,
std::vector<IntVar *> *cost, Solver *solver) {
for (const auto &it : soft_variables) {
const int index = gtl::FindOrDie(index_from_key, it.first);
CHECK_LT(index, variables.size());
IntVar* const displaced = solver->MakeIsDifferentCstVar(
IntVar *const displaced = solver->MakeIsDifferentCstVar(
variables[index], it.second.initial_position);
IntVar* const weight =
IntVar *const weight =
solver->MakeProd(displaced, it.second.mobility_cost)->Var();
cost->push_back(weight);
}
@@ -673,34 +675,31 @@ void PenalizeVariablesViolation(
// Penalize the violation of soft constraints of the instance.
void PenalizeConstraintsViolation(
const std::vector<FapConstraint>& constraints,
const std::vector<FapConstraint>& soft_constraints,
const std::map<int, int>& index_from_key,
const std::vector<IntVar*>& variables, std::vector<IntVar*>* cost,
std::vector<IntVar*>* violated_constraints, Solver* solver) {
const std::vector<FapConstraint> &constraints,
const std::vector<FapConstraint> &soft_constraints,
const std::map<int, int> &index_from_key,
const std::vector<IntVar *> &variables, std::vector<IntVar *> *cost,
std::vector<IntVar *> *violated_constraints, Solver *solver) {
int violated_constraints_index = 0;
for (const FapConstraint& ct : constraints) {
for (const FapConstraint &ct : constraints) {
CHECK_LT(violated_constraints_index, violated_constraints->size());
if (!ct.hard) {
// The violated_constraints_index will stop at the first soft constraint.
break;
}
IntVar* const hard_violation = solver->MakeIntVar(0, 0);
IntVar *const hard_violation = solver->MakeIntVar(0, 0);
(*violated_constraints)[violated_constraints_index] = hard_violation;
violated_constraints_index++;
}
for (const FapConstraint& ct : soft_constraints) {
for (const FapConstraint &ct : soft_constraints) {
const int index1 = gtl::FindOrDie(index_from_key, ct.variable1);
const int index2 = gtl::FindOrDie(index_from_key, ct.variable2);
CHECK_LT(index1, variables.size());
CHECK_LT(index2, variables.size());
IntVar* const absolute_difference =
solver
->MakeAbs(
solver->MakeDifference(variables[index1], variables[index2]))
->Var();
IntVar* violation = nullptr;
IntVar *const absolute_difference = solver->MakeAbs(solver->MakeDifference(
variables[index1], variables[index2]))->Var();
IntVar *violation = nullptr;
if (ct.operation == ">") {
violation = solver->MakeIsLessCstVar(absolute_difference, ct.value);
} else if (ct.operation == "=") {
@@ -708,7 +707,7 @@ void PenalizeConstraintsViolation(
} else {
LOG(FATAL) << "Invalid operator detected.";
}
IntVar* const weight = solver->MakeProd(violation, ct.weight_cost)->Var();
IntVar *const weight = solver->MakeProd(violation, ct.weight_cost)->Var();
cost->push_back(weight);
CHECK_LT(violated_constraints_index, violated_constraints->size());
(*violated_constraints)[violated_constraints_index] = violation;
@@ -720,12 +719,12 @@ void PenalizeConstraintsViolation(
// The Soft Solver is dealing with the optimization of unfeasible instances
// and aims to minimize the total cost of violated constraints. Returning value
// equal to 0 denotes that the instance is feasible.
int SoftFapSolver(const std::map<int, FapVariable>& data_variables,
const std::vector<FapConstraint>& data_constraints,
const std::string& data_objective,
const std::vector<int>& values) {
int SoftFapSolver(const std::map<int, FapVariable> &data_variables,
const std::vector<FapConstraint> &data_constraints,
const std::string &data_objective,
const std::vector<int> &values) {
Solver solver("SoftFapSolver");
std::vector<SearchMonitor*> monitors;
std::vector<SearchMonitor *> monitors;
// Split variables to hard and soft.
std::map<int, FapVariable> hard_variables;
@@ -743,7 +742,7 @@ int SoftFapSolver(const std::map<int, FapVariable>& data_variables,
&soft_constraints);
// Create Model Variables.
std::vector<IntVar*> variables;
std::vector<IntVar *> variables;
std::map<int, int> index_from_key;
std::vector<int> key_from_index;
CreateModelVariables(data_variables, &solver, &variables, &index_from_key,
@@ -753,9 +752,9 @@ int SoftFapSolver(const std::map<int, FapVariable>& data_variables,
CreateModelConstraints(hard_constraints, variables, index_from_key, &solver);
// Penalize variable and constraint violations.
std::vector<IntVar*> cost;
std::vector<IntVar*> violated_constraints(ordered_constraints.size(),
nullptr);
std::vector<IntVar *> cost;
std::vector<IntVar *> violated_constraints(ordered_constraints.size(),
nullptr);
PenalizeVariablesViolation(soft_variables, index_from_key, variables, &cost,
&solver);
PenalizeConstraintsViolation(ordered_constraints, soft_constraints,
@@ -764,25 +763,26 @@ int SoftFapSolver(const std::map<int, FapVariable>& data_variables,
// Objective
// Minimize the sum of violation penalties.
IntVar* objective_var = solver.MakeSum(cost)->Var();
OptimizeVar* objective = solver.MakeMinimize(objective_var, 1);
IntVar *objective_var = solver.MakeSum(cost)->Var();
OptimizeVar *objective = solver.MakeMinimize(objective_var, 1);
monitors.push_back(objective);
// Ordering Builder
OrderingBuilder* ob = solver.RevAlloc(
OrderingBuilder *ob = solver.RevAlloc(
new OrderingBuilder(data_variables, ordered_constraints, variables,
violated_constraints, index_from_key));
// Decision Builder Configuration
// Choose the next variable selection strategy.
DecisionBuilder* db;
if (FLAGS_variable_evaluator == "variable_evaluator") {
DecisionBuilder *db;
if (absl::GetFlag(FLAGS_variable_evaluator) == "variable_evaluator") {
LOG(INFO) << "Using VariableEvaluator for variable selection strategy and "
"Solver::ASSIGN_MIN_VALUE for value selection strategy.";
Solver::IndexEvaluator1 var_evaluator = [&key_from_index,
&data_variables](int64 index) {
Solver::IndexEvaluator1 var_evaluator =
[&key_from_index, &data_variables](int64 index) {
return VariableEvaluator(key_from_index, data_variables, index);
};
}
;
db = solver.MakePhase(variables, var_evaluator, Solver::ASSIGN_MIN_VALUE);
} else {
LOG(INFO) << "Using Solver::CHOOSE_FIRST_UNBOUND for variable selection "
@@ -791,13 +791,13 @@ int SoftFapSolver(const std::map<int, FapVariable>& data_variables,
db = solver.MakePhase(variables, Solver::CHOOSE_FIRST_UNBOUND,
Solver::ASSIGN_MIN_VALUE);
}
DecisionBuilder* final_db = solver.Compose(ob, db);
DecisionBuilder *final_db = solver.Compose(ob, db);
// Create Additional Monitors.
CreateAdditionalMonitors(objective, &solver, &monitors);
// Collector
SolutionCollector* const collector = solver.MakeLastSolutionCollector();
SolutionCollector *const collector = solver.MakeLastSolutionCollector();
collector->Add(variables);
collector->Add(objective_var);
monitors.push_back(collector);
@@ -811,11 +811,11 @@ int SoftFapSolver(const std::map<int, FapVariable>& data_variables,
int violation_sum =
collector->Value(collector->solution_count() - 1, objective_var);
// Display Time.
if (FLAGS_display_time) {
if (absl::GetFlag(FLAGS_display_time)) {
PrintElapsedTime(time1, time2);
}
// Display Results.
if (FLAGS_display_results) {
if (absl::GetFlag(FLAGS_display_results)) {
PrintResultsSoft(collector, variables, objective_var, hard_variables,
hard_constraints, soft_variables, soft_constraints,
index_from_key, key_from_index);
@@ -824,9 +824,9 @@ int SoftFapSolver(const std::map<int, FapVariable>& data_variables,
return violation_sum;
}
void SolveProblem(const std::map<int, FapVariable>& variables,
const std::vector<FapConstraint>& constraints,
const std::string& objective, const std::vector<int>& values,
void SolveProblem(const std::map<int, FapVariable> &variables,
const std::vector<FapConstraint> &constraints,
const std::string &objective, const std::vector<int> &values,
bool soft) {
// Print Instance!
FapModelPrinter model_printer(variables, constraints, objective, values);
@@ -850,35 +850,37 @@ void SolveProblem(const std::map<int, FapVariable>& variables,
}
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
CHECK(!FLAGS_directory.empty()) << "Requires --directory=<directory name>";
CHECK(!absl::GetFlag(FLAGS_directory).empty())
<< "Requires --directory=<directory name>";
LOG(INFO) << "Solving instance in directory " << FLAGS_directory;
LOG(INFO) << "Solving instance in directory "
<< absl::GetFlag(FLAGS_directory);
// Parse!
std::map<int, operations_research::FapVariable> variables;
std::vector<operations_research::FapConstraint> constraints;
std::string objective;
std::vector<int> values;
absl::flat_hash_map<int, operations_research::FapComponent> components;
operations_research::ParseInstance(FLAGS_directory, FLAGS_find_components,
&variables, &constraints, &objective,
&values, &components);
if (!FLAGS_find_components) {
operations_research::ParseInstance(
absl::GetFlag(FLAGS_directory), absl::GetFlag(FLAGS_find_components),
&variables, &constraints, &objective, &values, &components);
if (!absl::GetFlag(FLAGS_find_components)) {
operations_research::SolveProblem(variables, constraints, objective, values,
FLAGS_soft);
absl::GetFlag(FLAGS_soft));
} else {
int component_id = 1;
LOG(INFO) << "Number of components in the RLFAP graph "
<< components.size();
for (const auto& component : components) {
for (const auto &component : components) {
LOG(INFO) << "Solving Component " << component_id;
operations_research::SolveProblem(component.second.variables,
component.second.constraints, objective,
values, FLAGS_soft);
values, absl::GetFlag(FLAGS_soft));
component_id++;
}
}

View File

@@ -39,9 +39,11 @@ DEFINE_int32(
"Size of the problem. If equal to 0, will test several increasing sizes.");
DEFINE_string(params, "", "Sat parameters.");
static const int kBestSolutions[] = {0, 1, 3, 6, 11, 17, 25, 34, 44, 55, 72, 85,
// just for the optimistics ones, the rest:
106, 127, 151, 177, 199, 216, 246};
static const int kBestSolutions[] = {
0, 1, 3, 6, 11, 17, 25, 34, 44, 55, 72, 85,
// just for the optimistics ones, the rest:
106, 127, 151, 177, 199, 216, 246
};
static const int kKnownSolutions = 19;
@@ -63,7 +65,10 @@ void GolombRuler(int size) {
for (int i = 0; i < size; ++i) {
for (int j = i + 1; j < size; ++j) {
const IntVar diff = cp_model.NewIntVar(domain);
cp_model.AddEquality(LinearExpr::Sum({diff, ticks[i]}), ticks[j]);
cp_model.AddEquality(LinearExpr::Sum({
diff, ticks[i]
}),
ticks[j]);
diffs.push_back(diff);
}
}
@@ -86,10 +91,10 @@ void GolombRuler(int size) {
SatParameters parameters;
parameters.set_search_branching(SatParameters::FIXED_SEARCH);
// Parse the --params flag.
if (!FLAGS_params.empty()) {
CHECK(google::protobuf::TextFormat::MergeFromString(FLAGS_params,
&parameters))
<< FLAGS_params;
if (!absl::GetFlag(FLAGS_params).empty()) {
CHECK(google::protobuf::TextFormat::MergeFromString(
absl::GetFlag(FLAGS_params), &parameters))
<< absl::GetFlag(FLAGS_params);
}
model.Add(NewSatParameters(parameters));
const CpSolverResponse response = SolveCpModel(cp_model.Build(), &model);
@@ -102,7 +107,7 @@ void GolombRuler(int size) {
if (size - 1 < kKnownSolutions) {
CHECK_EQ(result, kBestSolutions[size - 1]);
}
if (FLAGS_print) {
if (absl::GetFlag(FLAGS_print)) {
for (int i = 0; i < size; ++i) {
const int64 tick = SolutionIntegerValue(response, ticks[i]);
printf("%d ", static_cast<int>(tick));
@@ -112,13 +117,13 @@ void GolombRuler(int size) {
}
}
} // namespace sat
} // namespace operations_research
} // namespace sat
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_size != 0) {
operations_research::sat::GolombRuler(FLAGS_size);
if (absl::GetFlag(FLAGS_size) != 0) {
operations_research::sat::GolombRuler(absl::GetFlag(FLAGS_size));
} else {
for (int n = 1; n < 11; ++n) {
operations_research::sat::GolombRuler(n);

View File

@@ -18,7 +18,7 @@
#include "ortools/linear_solver/linear_solver.h"
namespace operations_research {
void RunIntegerProgrammingExample(const std::string& solver_id) {
void RunIntegerProgrammingExample(const std::string &solver_id) {
LOG(INFO) << "---- Integer programming example with " << solver_id << " ----";
MPSolver::OptimizationProblemType problem_type;
@@ -36,22 +36,22 @@ void RunIntegerProgrammingExample(const std::string& solver_id) {
const double infinity = solver.infinity();
// x and y are integer non-negative variables.
MPVariable* const x = solver.MakeIntVar(0.0, infinity, "x");
MPVariable* const y = solver.MakeIntVar(0.0, infinity, "y");
MPVariable *const x = solver.MakeIntVar(0.0, infinity, "x");
MPVariable *const y = solver.MakeIntVar(0.0, infinity, "y");
// Maximize x + 10 * y.
MPObjective* const objective = solver.MutableObjective();
MPObjective *const objective = solver.MutableObjective();
objective->SetCoefficient(x, 1);
objective->SetCoefficient(y, 10);
objective->SetMaximization();
// x + 7 * y <= 17.5.
MPConstraint* const c0 = solver.MakeRowConstraint(-infinity, 17.5);
MPConstraint *const c0 = solver.MakeRowConstraint(-infinity, 17.5);
c0->SetCoefficient(x, 1);
c0->SetCoefficient(y, 7);
// x <= 3.5
MPConstraint* const c1 = solver.MakeRowConstraint(-infinity, 3.5);
MPConstraint *const c1 = solver.MakeRowConstraint(-infinity, 3.5);
c1->SetCoefficient(x, 1);
c1->SetCoefficient(y, 0);
@@ -83,12 +83,12 @@ void RunAllExamples() {
RunIntegerProgrammingExample("GLPK");
RunIntegerProgrammingExample("CPLEX");
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
google::InitGoogleLogging(argv[0]);
absl::SetFlag(&FLAGS_logtostderr, true);
absl::SetFlag(&FLAGS_log_prefix, false);
absl::SetFlag(&absl::GetFlag(FLAGS_logtostderr), true);
absl::SetFlag(&absl::GetFlag(FLAGS_log_prefix), false);
gflags::ParseCommandLineFlags(&argc, &argv, true);
operations_research::RunAllExamples();
return 0;

View File

@@ -46,11 +46,11 @@ namespace operations_research {
namespace sat {
// Compute a valid horizon from a problem.
int64 ComputeHorizon(const JsspInputProblem& problem) {
int64 ComputeHorizon(const JsspInputProblem &problem) {
int64 sum_of_durations = 0;
int64 max_latest_end = 0;
int64 max_earliest_start = 0;
for (const Job& job : problem.jobs()) {
for (const Job &job : problem.jobs()) {
if (job.has_latest_end()) {
max_latest_end = std::max(max_latest_end, job.latest_end().value());
} else {
@@ -60,7 +60,7 @@ int64 ComputeHorizon(const JsspInputProblem& problem) {
max_earliest_start =
std::max(max_earliest_start, job.earliest_start().value());
}
for (const Task& task : job.tasks()) {
for (const Task &task : job.tasks()) {
int64 max_duration = 0;
for (int64 d : task.duration()) {
max_duration = std::max(max_duration, d);
@@ -71,9 +71,10 @@ int64 ComputeHorizon(const JsspInputProblem& problem) {
const int num_jobs = problem.jobs_size();
int64 sum_of_transitions = 0;
for (const Machine& machine : problem.machines()) {
if (!machine.has_transition_time_matrix()) continue;
const TransitionTimeMatrix& matrix = machine.transition_time_matrix();
for (const Machine &machine : problem.machines()) {
if (!machine.has_transition_time_matrix())
continue;
const TransitionTimeMatrix &matrix = machine.transition_time_matrix();
for (int i = 0; i < num_jobs; ++i) {
int64 max_transition = 0;
for (int j = 0; j < num_jobs; ++j) {
@@ -89,8 +90,8 @@ int64 ComputeHorizon(const JsspInputProblem& problem) {
}
// Solve a JobShop scheduling problem using SAT.
void Solve(const JsspInputProblem& problem) {
if (FLAGS_display_model) {
void Solve(const JsspInputProblem &problem) {
if (absl::GetFlag(FLAGS_display_model)) {
LOG(INFO) << problem.DebugString();
}
@@ -107,11 +108,11 @@ void Solve(const JsspInputProblem& problem) {
const IntVar makespan = cp_model.NewIntVar(all_horizon);
std::vector<std::vector<IntervalVar>> machine_to_intervals(num_machines);
std::vector<std::vector<int>> machine_to_jobs(num_machines);
std::vector<std::vector<IntVar>> machine_to_starts(num_machines);
std::vector<std::vector<IntVar>> machine_to_ends(num_machines);
std::vector<std::vector<BoolVar>> machine_to_presences(num_machines);
std::vector<std::vector<IntervalVar> > machine_to_intervals(num_machines);
std::vector<std::vector<int> > machine_to_jobs(num_machines);
std::vector<std::vector<IntVar> > machine_to_starts(num_machines);
std::vector<std::vector<IntVar> > machine_to_ends(num_machines);
std::vector<std::vector<BoolVar> > machine_to_presences(num_machines);
std::vector<IntVar> job_starts(num_jobs);
std::vector<IntVar> job_ends(num_jobs);
std::vector<IntVar> task_starts;
@@ -120,7 +121,7 @@ void Solve(const JsspInputProblem& problem) {
std::vector<int64> objective_coeffs;
for (int j = 0; j < num_jobs; ++j) {
const Job& job = problem.jobs(j);
const Job &job = problem.jobs(j);
IntVar previous_end;
const int64 hard_start =
job.has_earliest_start() ? job.earliest_start().value() : 0L;
@@ -128,7 +129,7 @@ void Solve(const JsspInputProblem& problem) {
job.has_latest_end() ? job.latest_end().value() : horizon;
for (int t = 0; t < job.tasks_size(); ++t) {
const Task& task = job.tasks(t);
const Task &task = job.tasks(t);
const int num_alternatives = task.machine_size();
CHECK_EQ(num_alternatives, task.duration_size());
@@ -177,19 +178,19 @@ void Solve(const JsspInputProblem& problem) {
for (int a = 0; a < num_alternatives; ++a) {
const BoolVar presence = cp_model.NewBoolVar();
const IntVar local_start =
FLAGS_use_optional_variables
absl::GetFlag(FLAGS_use_optional_variables)
? cp_model.NewIntVar(Domain(hard_start, hard_end))
: start;
const IntVar local_duration = cp_model.NewConstant(task.duration(a));
const IntVar local_end =
FLAGS_use_optional_variables
absl::GetFlag(FLAGS_use_optional_variables)
? cp_model.NewIntVar(Domain(hard_start, hard_end))
: end;
const IntervalVar local_interval = cp_model.NewOptionalIntervalVar(
local_start, local_duration, local_end, presence);
// Link local and global variables.
if (FLAGS_use_optional_variables) {
if (absl::GetFlag(FLAGS_use_optional_variables)) {
cp_model.AddEquality(start, local_start).OnlyEnforceIf(presence);
cp_model.AddEquality(end, local_end).OnlyEnforceIf(presence);
@@ -237,8 +238,9 @@ void Solve(const JsspInputProblem& problem) {
cp_model.AddEquality(shifted_var,
LinearExpr(previous_end).AddConstant(-due_date));
const IntVar lateness_var = cp_model.NewIntVar(all_horizon);
cp_model.AddMaxEquality(lateness_var,
{cp_model.NewConstant(0), shifted_var});
cp_model.AddMaxEquality(lateness_var, {
cp_model.NewConstant(0), shifted_var
});
objective_vars.push_back(lateness_var);
objective_coeffs.push_back(lateness_penalty);
}
@@ -250,11 +252,14 @@ void Solve(const JsspInputProblem& problem) {
if (due_date > 0) {
const IntVar shifted_var =
cp_model.NewIntVar(Domain(due_date - horizon, due_date));
cp_model.AddEquality(LinearExpr::Sum({shifted_var, previous_end}),
cp_model.AddEquality(LinearExpr::Sum({
shifted_var, previous_end
}),
due_date);
const IntVar earliness_var = cp_model.NewIntVar(all_horizon);
cp_model.AddMaxEquality(earliness_var,
{cp_model.NewConstant(0), shifted_var});
cp_model.AddMaxEquality(earliness_var, {
cp_model.NewConstant(0), shifted_var
});
objective_vars.push_back(earliness_var);
objective_coeffs.push_back(earliness_penalty);
}
@@ -266,7 +271,7 @@ void Solve(const JsspInputProblem& problem) {
cp_model.AddNoOverlap(machine_to_intervals[m]);
if (problem.machines(m).has_transition_time_matrix()) {
const TransitionTimeMatrix& transitions =
const TransitionTimeMatrix &transitions =
problem.machines(m).transition_time_matrix();
const int num_intervals = machine_to_intervals[m].size();
@@ -292,9 +297,8 @@ void Solve(const JsspInputProblem& problem) {
const IntVar end = machine_to_ends[m][i];
circuit.AddArc(i + 1, j + 1, lit);
// Push the new start with an extra transition.
cp_model
.AddLessOrEqual(LinearExpr(end).AddConstant(transition), start)
.OnlyEnforceIf(lit);
cp_model.AddLessOrEqual(LinearExpr(end).AddConstant(transition),
start).OnlyEnforceIf(lit);
}
}
}
@@ -302,7 +306,7 @@ void Solve(const JsspInputProblem& problem) {
}
// Add job precedences.
for (const JobPrecedence& precedence : problem.precedences()) {
for (const JobPrecedence &precedence : problem.precedences()) {
const IntVar start = job_starts[precedence.second_job_index()];
const IntVar end = job_ends[precedence.first_job_index()];
cp_model.AddLessOrEqual(LinearExpr(end).AddConstant(precedence.min_delay()),
@@ -329,14 +333,14 @@ void Solve(const JsspInputProblem& problem) {
LOG(INFO) << "#jobs:" << num_jobs;
LOG(INFO) << "horizon:" << horizon;
if (FLAGS_display_sat_model) {
if (absl::GetFlag(FLAGS_display_sat_model)) {
LOG(INFO) << cp_model.Proto().DebugString();
}
LOG(INFO) << CpModelStats(cp_model.Proto());
Model model;
model.Add(NewSatParameters(FLAGS_params));
model.Add(NewSatParameters(absl::GetFlag(FLAGS_params)));
const CpSolverResponse response = SolveCpModel(cp_model.Build(), &model);
LOG(INFO) << CpSolverResponseStats(response);
@@ -376,18 +380,18 @@ void Solve(const JsspInputProblem& problem) {
CHECK_LE(response.objective_value(), final_cost + tolerance);
}
} // namespace sat
} // namespace operations_research
} // namespace sat
} // namespace operations_research
int main(int argc, char** argv) {
absl::SetFlag(&FLAGS_logtostderr, true);
int main(int argc, char **argv) {
absl::SetFlag(&absl::GetFlag(FLAGS_logtostderr), true);
gflags::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_input.empty()) {
if (absl::GetFlag(FLAGS_input).empty()) {
LOG(FATAL) << "Please supply a data file with --input=";
}
operations_research::data::jssp::JsspParser parser;
CHECK(parser.ParseFile(FLAGS_input));
CHECK(parser.ParseFile(absl::GetFlag(FLAGS_input)));
operations_research::sat::Solve(parser.problem());
return EXIT_SUCCESS;
}

View File

@@ -25,10 +25,10 @@ void AssignmentOn4x4Matrix() {
LOG(INFO) << "Assignment on 4x4 Matrix";
const int kNumSources = 4;
const int kNumTargets = 4;
const CostValue kCost[kNumSources][kNumTargets] = {{90, 76, 75, 80},
{35, 85, 55, 65},
{125, 95, 90, 105},
{45, 110, 95, 115}};
const CostValue kCost[kNumSources][kNumTargets] = { { 90, 76, 75, 80 },
{ 35, 85, 55, 65 },
{ 125, 95, 90, 105 },
{ 45, 110, 95, 115 } };
const CostValue kExpectedCost =
kCost[0][3] + kCost[1][2] + kCost[2][1] + kCost[3][0];
ForwardStarGraph graph(kNumSources + kNumTargets, kNumSources * kNumTargets);
@@ -46,8 +46,12 @@ void AssignmentOn4x4Matrix() {
void AnotherAssignment() {
LOG(INFO) << "Another assignment on 4x4 matrix";
std::vector<std::vector<int>> matrice(
{{8, 7, 9, 9}, {5, 2, 7, 8}, {6, 1, 4, 9}, {2, 3, 2, 6}});
std::vector<std::vector<int> > matrice({
{ 8, 7, 9, 9 }
, { 5, 2, 7, 8 }
, { 6, 1, 4, 9 }
, { 2, 3, 2, 6 }
});
const int kSize = matrice.size();
ForwardStarGraph graph(2 * kSize, kSize * kSize);
LinearSumAssignment<ForwardStarGraph> assignement(graph, kSize);
@@ -63,9 +67,9 @@ void AnotherAssignment() {
LOG(INFO) << "Cost : " << assignement.GetCost();
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
operations_research::AssignmentOn4x4Matrix();
operations_research::AnotherAssignment();

View File

@@ -19,7 +19,7 @@
#include "ortools/linear_solver/linear_solver.pb.h"
namespace operations_research {
void RunLinearProgrammingExample(const std::string& solver_id) {
void RunLinearProgrammingExample(const std::string &solver_id) {
LOG(INFO) << "---- Linear programming example with " << solver_id << " ----";
MPSolver::OptimizationProblemType problem_type;
if (!MPSolver::ParseSolverType(solver_id, &problem_type)) {
@@ -36,31 +36,31 @@ void RunLinearProgrammingExample(const std::string& solver_id) {
const double infinity = solver.infinity();
// x1, x2 and x3 are continuous non-negative variables.
MPVariable* const x1 = solver.MakeNumVar(0.0, infinity, "x1");
MPVariable* const x2 = solver.MakeNumVar(0.0, infinity, "x2");
MPVariable* const x3 = solver.MakeNumVar(0.0, infinity, "x3");
MPVariable *const x1 = solver.MakeNumVar(0.0, infinity, "x1");
MPVariable *const x2 = solver.MakeNumVar(0.0, infinity, "x2");
MPVariable *const x3 = solver.MakeNumVar(0.0, infinity, "x3");
// Maximize 10 * x1 + 6 * x2 + 4 * x3.
MPObjective* const objective = solver.MutableObjective();
MPObjective *const objective = solver.MutableObjective();
objective->SetCoefficient(x1, 10);
objective->SetCoefficient(x2, 6);
objective->SetCoefficient(x3, 4);
objective->SetMaximization();
// x1 + x2 + x3 <= 100.
MPConstraint* const c0 = solver.MakeRowConstraint(-infinity, 100.0);
MPConstraint *const c0 = solver.MakeRowConstraint(-infinity, 100.0);
c0->SetCoefficient(x1, 1);
c0->SetCoefficient(x2, 1);
c0->SetCoefficient(x3, 1);
// 10 * x1 + 4 * x2 + 5 * x3 <= 600.
MPConstraint* const c1 = solver.MakeRowConstraint(-infinity, 600.0);
MPConstraint *const c1 = solver.MakeRowConstraint(-infinity, 600.0);
c1->SetCoefficient(x1, 10);
c1->SetCoefficient(x2, 4);
c1->SetCoefficient(x3, 5);
// 2 * x1 + 2 * x2 + 6 * x3 <= 300.
MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 300.0);
MPConstraint *const c2 = solver.MakeRowConstraint(-infinity, 300.0);
c2->SetCoefficient(x1, 2);
c2->SetCoefficient(x2, 2);
c2->SetCoefficient(x3, 6);
@@ -109,12 +109,12 @@ void RunAllExamples() {
RunLinearProgrammingExample("GLPK_LP");
RunLinearProgrammingExample("XPRESS_LP");
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
google::InitGoogleLogging(argv[0]);
absl::SetFlag(&FLAGS_logtostderr, true);
absl::SetFlag(&FLAGS_log_prefix, false);
absl::SetFlag(&absl::GetFlag(FLAGS_logtostderr), true);
absl::SetFlag(&absl::GetFlag(FLAGS_log_prefix), false);
gflags::ParseCommandLineFlags(&argc, &argv, true);
operations_research::RunAllExamples();
return EXIT_SUCCESS;

View File

@@ -20,17 +20,17 @@
namespace operations_research {
void BuildLinearProgrammingMaxExample(MPSolver::OptimizationProblemType type) {
const double kObjCoef[] = {10.0, 6.0, 4.0};
const std::string kVarName[] = {"x1", "x2", "x3"};
const double kObjCoef[] = { 10.0, 6.0, 4.0 };
const std::string kVarName[] = { "x1", "x2", "x3" };
const int numVars = 3;
const int kNumConstraints = 3;
const std::string kConstraintName[] = {"c1", "c2", "c3"};
const double kConstraintCoef1[] = {1.0, 1.0, 1.0};
const double kConstraintCoef2[] = {10.0, 4.0, 5.0};
const double kConstraintCoef3[] = {2.0, 2.0, 6.0};
const double* kConstraintCoef[] = {kConstraintCoef1, kConstraintCoef2,
kConstraintCoef3};
const double kConstraintUb[] = {100.0, 600.0, 300.0};
const std::string kConstraintName[] = { "c1", "c2", "c3" };
const double kConstraintCoef1[] = { 1.0, 1.0, 1.0 };
const double kConstraintCoef2[] = { 10.0, 4.0, 5.0 };
const double kConstraintCoef3[] = { 2.0, 2.0, 6.0 };
const double *kConstraintCoef[] = { kConstraintCoef1, kConstraintCoef2,
kConstraintCoef3 };
const double kConstraintUb[] = { 100.0, 600.0, 300.0 };
const double infinity = MPSolver::infinity();
MPModelProto model_proto;
@@ -38,20 +38,20 @@ void BuildLinearProgrammingMaxExample(MPSolver::OptimizationProblemType type) {
// Create variables and objective function
for (int j = 0; j < numVars; ++j) {
MPVariableProto* x = model_proto.add_variable();
x->set_name(kVarName[j]); // Could be skipped (optional).
MPVariableProto *x = model_proto.add_variable();
x->set_name(kVarName[j]); // Could be skipped (optional).
x->set_lower_bound(0.0);
x->set_upper_bound(infinity); // Could be skipped (default value).
x->set_is_integer(false); // Could be skipped (default value).
x->set_upper_bound(infinity); // Could be skipped (default value).
x->set_is_integer(false); // Could be skipped (default value).
x->set_objective_coefficient(kObjCoef[j]);
}
model_proto.set_maximize(true);
// Create constraints
for (int i = 0; i < kNumConstraints; ++i) {
MPConstraintProto* constraint_proto = model_proto.add_constraint();
constraint_proto->set_name(kConstraintName[i]); // Could be skipped.
constraint_proto->set_lower_bound(-infinity); // Could be skipped.
MPConstraintProto *constraint_proto = model_proto.add_constraint();
constraint_proto->set_name(kConstraintName[i]); // Could be skipped.
constraint_proto->set_lower_bound(-infinity); // Could be skipped.
constraint_proto->set_upper_bound(kConstraintUb[i]);
for (int j = 0; j < numVars; ++j) {
// These two lines may be skipped when the coefficient is zero.
@@ -66,12 +66,12 @@ void BuildLinearProgrammingMaxExample(MPSolver::OptimizationProblemType type) {
if (type == MPSolver::GLOP_LINEAR_PROGRAMMING) {
model_request.set_solver_type(MPModelRequest::GLOP_LINEAR_PROGRAMMING);
}
#endif // USE_GLOP
#endif // USE_GLOP
#if defined(USE_CLP)
if (type == MPSolver::CLP_LINEAR_PROGRAMMING) {
model_request.set_solver_type(MPModelRequest::CLP_LINEAR_PROGRAMMING);
}
#endif // USE_CLP
#endif // USE_CLP
MPSolutionResponse solution_response;
MPSolver::SolveWithProto(model_request, &solution_response);
@@ -90,15 +90,15 @@ void RunAllExamples() {
#if defined(USE_GLOP)
LOG(INFO) << "----- Running Max Example with GLOP -----";
BuildLinearProgrammingMaxExample(MPSolver::GLOP_LINEAR_PROGRAMMING);
#endif // USE_GLOP
#endif // USE_GLOP
#if defined(USE_CLP)
LOG(INFO) << "----- Running Max Example with Coin LP -----";
BuildLinearProgrammingMaxExample(MPSolver::CLP_LINEAR_PROGRAMMING);
#endif // USE_CLP
#endif // USE_CLP
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
operations_research::RunAllExamples();
return EXIT_SUCCESS;

View File

@@ -28,8 +28,8 @@ namespace sat {
void MagicSquare(int size) {
CpModelBuilder builder;
std::vector<std::vector<IntVar>> square(size);
std::vector<std::vector<IntVar>> transposed(size);
std::vector<std::vector<IntVar> > square(size);
std::vector<std::vector<IntVar> > transposed(size);
std::vector<IntVar> diag1;
std::vector<IntVar> diag2;
std::vector<IntVar> all_variables;
@@ -70,7 +70,7 @@ void MagicSquare(int size) {
builder.AddEquality(LinearExpr::Sum(diag2), sum);
Model model;
model.Add(NewSatParameters(FLAGS_params));
model.Add(NewSatParameters(absl::GetFlag(FLAGS_params)));
const CpSolverResponse response = SolveCpModel(builder.Build(), &model);
@@ -89,12 +89,12 @@ void MagicSquare(int size) {
LOG(INFO) << CpSolverResponseStats(response);
}
} // namespace sat
} // namespace operations_research
} // namespace sat
} // namespace operations_research
int main(int argc, char **argv) {
absl::SetFlag(&FLAGS_logtostderr, true);
absl::SetFlag(&absl::GetFlag(FLAGS_logtostderr), true);
gflags::ParseCommandLineFlags(&argc, &argv, true);
operations_research::sat::MagicSquare(FLAGS_size);
operations_research::sat::MagicSquare(absl::GetFlag(FLAGS_size));
return EXIT_SUCCESS;
}

View File

@@ -22,12 +22,13 @@ void SolveMaxFlow() {
// Can't use std::tuple<NodeIndex, NodeIndex, FlowQuantity>
// Initialization list is not working on std:tuple cf. N4387
// Arc are stored as {{begin_node, end_node}, capacity}
std::vector<std::pair<std::pair<NodeIndex, NodeIndex>, FlowQuantity>> arcs = {
{{0, 1}, 20}, {{0, 2}, 30}, {{0, 3}, 10}, {{1, 2}, 40}, {{1, 4}, 30},
{{2, 3}, 10}, {{2, 4}, 20}, {{3, 2}, 5}, {{3, 4}, 20}};
std::vector<std::pair<std::pair<NodeIndex, NodeIndex>, FlowQuantity> > arcs =
{ { { 0, 1 }, 20 }, { { 0, 2 }, 30 }, { { 0, 3 }, 10 }, { { 1, 2 }, 40 },
{ { 1, 4 }, 30 }, { { 2, 3 }, 10 }, { { 2, 4 }, 20 }, { { 3, 2 }, 5 },
{ { 3, 4 }, 20 } };
StarGraph graph(num_nodes, arcs.size());
MaxFlow max_flow(&graph, 0, num_nodes - 1);
for (const auto& it : arcs) {
for (const auto &it : arcs) {
ArcIndex arc = graph.AddArc(it.first.first, it.first.second);
max_flow.SetArcCapacity(arc, it.second);
}
@@ -49,11 +50,11 @@ void SolveMaxFlow() {
<< max_flow.Flow(i) << " / " << max_flow.Capacity(i);
}
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
google::InitGoogleLogging(argv[0]);
FLAGS_logtostderr = 1;
absl::GetFlag(FLAGS_logtostderr) = 1;
operations_research::SolveMaxFlow();
return EXIT_SUCCESS;
}

View File

@@ -24,17 +24,19 @@ struct Arc {
void SolveMinCostFlow() {
// Define supply of each node.
const std::vector<std::pair<NodeIndex, FlowQuantity>> supplies = {
{0, 20}, {1, 0}, {2, 0}, {3, -5}, {4, -15}};
const std::vector<std::pair<NodeIndex, FlowQuantity> > supplies = {
{ 0, 20 }, { 1, 0 }, { 2, 0 }, { 3, -5 }, { 4, -15 }
};
// Define each arc
// Can't use std::tuple<NodeIndex, NodeIndex, FlowQuantity>
// Initialization list is not working on std:tuple cf. N4387
// Arc are stored as {{begin_node, end_node}, capacity}
const std::vector<Arc> arcs = {
{{0, 1}, 15, 4}, {{0, 2}, 8, 4}, {{1, 2}, 20, 2},
{{1, 3}, 4, 2}, {{1, 4}, 10, 6}, {{2, 3}, 15, 1},
{{2, 4}, 4, 3}, {{3, 4}, 20, 2}, {{4, 2}, 5, 3}};
const std::vector<Arc> arcs = { { { 0, 1 }, 15, 4 }, { { 0, 2 }, 8, 4 },
{ { 1, 2 }, 20, 2 }, { { 1, 3 }, 4, 2 },
{ { 1, 4 }, 10, 6 }, { { 2, 3 }, 15, 1 },
{ { 2, 4 }, 4, 3 }, { { 3, 4 }, 20, 2 },
{ { 4, 2 }, 5, 3 } };
StarGraph graph(supplies.size(), arcs.size());
MinCostFlow min_cost_flow(&graph);
@@ -65,11 +67,11 @@ void SolveMinCostFlow() {
<< " / " << min_cost_flow.UnitCost(i);
}
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char **argv) {
google::InitGoogleLogging(argv[0]);
FLAGS_logtostderr = 1;
absl::GetFlag(FLAGS_logtostderr) = 1;
operations_research::SolveMinCostFlow();
return EXIT_SUCCESS;
}

View File

@@ -44,10 +44,9 @@ DEFINE_bool(mps_display_full_path, true,
"Displays the full path of the input file in the result line.");
DEFINE_string(input, "", "File pattern for problems to be optimized.");
DEFINE_string(params_file, "", "Path to a GlopParameters file in text format.");
DEFINE_string(params, "",
"GlopParameters in text format. If --params_file was "
"also specified, the --params will be merged onto "
"them (i.e. in case of conflicts, --params wins)");
DEFINE_string(params, "", "GlopParameters in text format. If --params_file was "
"also specified, the --params will be merged onto "
"them (i.e. in case of conflicts, --params wins)");
using google::protobuf::TextFormat;
using operations_research::FullProtocolMessageAsString;
@@ -62,22 +61,22 @@ using operations_research::glop::ProblemStatus;
using operations_research::glop::ToDouble;
// Parse glop parameters from the flags --params_file and --params.
void ReadGlopParameters(GlopParameters* parameters) {
if (!FLAGS_params_file.empty()) {
void ReadGlopParameters(GlopParameters *parameters) {
if (!absl::GetFlag(FLAGS_params_file).empty()) {
std::string params;
CHECK(TextFormat::ParseFromString(params, parameters)) << params;
}
if (!FLAGS_params.empty()) {
CHECK(TextFormat::MergeFromString(FLAGS_params, parameters))
<< FLAGS_params;
if (!absl::GetFlag(FLAGS_params).empty()) {
CHECK(TextFormat::MergeFromString(absl::GetFlag(FLAGS_params), parameters))
<< absl::GetFlag(FLAGS_params);
}
if (FLAGS_mps_verbose_result) {
if (absl::GetFlag(FLAGS_mps_verbose_result)) {
printf("GlopParameters {\n%s}\n",
FullProtocolMessageAsString(*parameters, 1).c_str());
}
}
int main(int argc, char* argv[]) {
int main(int argc, char *argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
GlopParameters parameters;
@@ -86,9 +85,9 @@ int main(int argc, char* argv[]) {
LinearProgram linear_program;
std::vector<std::string> file_list;
// Replace this with your favorite match function.
file_list.push_back(FLAGS_input);
file_list.push_back(absl::GetFlag(FLAGS_input));
for (int i = 0; i < file_list.size(); ++i) {
const std::string& file_name = file_list[i];
const std::string &file_name = file_list[i];
MPSReader mps_reader;
operations_research::MPModelProto model_proto;
if (absl::EndsWith(file_name, ".mps") ||
@@ -103,7 +102,7 @@ int main(int argc, char* argv[]) {
ReadFileToProto(file_name, &model_proto);
MPModelProtoToLinearProgram(model_proto, &linear_program);
}
if (FLAGS_mps_dump_problem) {
if (absl::GetFlag(FLAGS_mps_dump_problem)) {
printf("%s", linear_program.Dump().c_str());
}
@@ -115,19 +114,19 @@ int main(int argc, char* argv[]) {
std::string status_string;
double objective_value;
double solving_time_in_sec = 0;
if (FLAGS_mps_solve) {
if (absl::GetFlag(FLAGS_mps_solve)) {
ScopedWallTime timer(&solving_time_in_sec);
solve_status = solver.Solve(linear_program);
status_string = GetProblemStatusString(solve_status);
objective_value = ToDouble(solver.GetObjectiveValue());
}
if (FLAGS_mps_terse_result) {
if (FLAGS_mps_display_full_path) {
if (absl::GetFlag(FLAGS_mps_terse_result)) {
if (absl::GetFlag(FLAGS_mps_display_full_path)) {
printf("%s,", file_name.c_str());
}
printf("%s,", linear_program.name().c_str());
if (FLAGS_mps_solve) {
if (absl::GetFlag(FLAGS_mps_solve)) {
printf("%15.15e,%s,%-6.4g,", objective_value, status_string.c_str(),
solving_time_in_sec);
}
@@ -135,12 +134,12 @@ int main(int argc, char* argv[]) {
linear_program.GetNonZeroStats().c_str());
}
if (FLAGS_mps_verbose_result) {
if (FLAGS_mps_display_full_path) {
if (absl::GetFlag(FLAGS_mps_verbose_result)) {
if (absl::GetFlag(FLAGS_mps_display_full_path)) {
printf("%-45s: %s\n", "File path", file_name.c_str());
}
printf("%-45s: %s\n", "Problem name", linear_program.name().c_str());
if (FLAGS_mps_solve) {
if (absl::GetFlag(FLAGS_mps_solve)) {
printf("%-45s: %15.15e\n", "Objective value", objective_value);
printf("%-45s: %s\n", "Problem status", status_string.c_str());
printf("%-45s: %-6.4g\n", "Solving time", solving_time_in_sec);

View File

@@ -37,19 +37,19 @@ static const int kVolumeMin = 1156;
static const int kVolumeMax = 1600;
// Data for a single bin problem
static const int kItemsWeights[] = {1008, 2087, 5522, 5250, 5720,
4998, 275, 3145, 12580, 382};
static const int kItemsVolumes[] = {281, 307, 206, 111, 275,
79, 23, 65, 261, 40};
static const int kItemsWeights[] = { 1008, 2087, 5522, 5250, 5720, 4998, 275,
3145, 12580, 382 };
static const int kItemsVolumes[] = { 281, 307, 206, 111, 275, 79, 23, 65, 261,
40 };
static const int kNumItems = 10;
void MultiKnapsackSat(int scaling, const std::string& params) {
void MultiKnapsackSat(int scaling, const std::string &params) {
CpModelBuilder builder;
const int num_items = scaling * kNumItems;
const int num_bins = scaling;
std::vector<std::vector<BoolVar>> items_in_bins(num_bins);
std::vector<std::vector<BoolVar> > items_in_bins(num_bins);
for (int b = 0; b < num_bins; ++b) {
for (int i = 0; i < num_items; ++i) {
items_in_bins[b].push_back(builder.NewBoolVar());
@@ -74,13 +74,16 @@ void MultiKnapsackSat(int scaling, const std::string& params) {
// Constraints per bins.
std::vector<IntVar> bin_weights;
for (int b = 0; b < num_bins; ++b) {
IntVar bin_weight = builder.NewIntVar({kWeightMin, kWeightMax});
IntVar bin_weight = builder.NewIntVar({
kWeightMin, kWeightMax
});
bin_weights.push_back(bin_weight);
builder.AddEquality(LinearExpr::BooleanScalProd(items_in_bins[b], weights),
bin_weight);
builder.AddLinearConstraint(
LinearExpr::BooleanScalProd(items_in_bins[b], volumes),
{kVolumeMin, kVolumeMax});
LinearExpr::BooleanScalProd(items_in_bins[b], volumes), {
kVolumeMin, kVolumeMax
});
}
// Each item is selected at most one time.
@@ -102,12 +105,13 @@ void MultiKnapsackSat(int scaling, const std::string& params) {
LOG(INFO) << CpSolverResponseStats(response);
}
} // namespace sat
} // namespace operations_research
} // namespace sat
} // namespace operations_research
int main(int argc, char** argv) {
absl::SetFlag(&FLAGS_logtostderr, true);
int main(int argc, char **argv) {
absl::SetFlag(&absl::GetFlag(FLAGS_logtostderr), true);
gflags::ParseCommandLineFlags(&argc, &argv, true);
operations_research::sat::MultiKnapsackSat(FLAGS_size, FLAGS_params);
operations_research::sat::MultiKnapsackSat(absl::GetFlag(FLAGS_size),
absl::GetFlag(FLAGS_params));
return EXIT_SUCCESS;
}

View File

@@ -45,9 +45,8 @@
#include "ortools/util/time_limit.h"
// ----- Data Generator -----
DEFINE_int32(clients, 0,
"Number of network clients nodes. If equal to zero, "
"then all backbones nodes are also client nodes.");
DEFINE_int32(clients, 0, "Number of network clients nodes. If equal to zero, "
"then all backbones nodes are also client nodes.");
DEFINE_int32(backbones, 0, "Number of backbone nodes");
DEFINE_int32(demands, 0, "Number of network demands.");
DEFINE_int32(traffic_min, 0, "Min traffic of a demand.");
@@ -91,7 +90,7 @@ static const int64 kDisconnectedDistance = -1LL;
// (capacity(i->j) == capacity(j->i)).
// Demands are not symmetrical.
class NetworkRoutingData {
public:
public:
NetworkRoutingData()
: name_(""), num_nodes_(-1), max_capacity_(-1), fixed_charge_cost_(-1) {}
@@ -132,7 +131,7 @@ class NetworkRoutingData {
void set_max_capacity(int max_capacity) { max_capacity_ = max_capacity; }
void set_fixed_charge_cost(int cost) { fixed_charge_cost_ = cost; }
private:
private:
std::string name_;
int num_nodes_;
int max_capacity_;
@@ -155,7 +154,7 @@ class NetworkRoutingData {
// Each arc has a capacity of 'max_capacity'. Using an arc incurs a
// fixed cost of 'fixed_charge_cost'.
class NetworkRoutingDataBuilder {
public:
public:
NetworkRoutingDataBuilder() : random_(0) {}
void BuildModelFromParameters(int num_clients, int num_backbones,
@@ -192,7 +191,7 @@ class NetworkRoutingDataBuilder {
max_backbone_degree, max_capacity, fixed_charge_cost, seed, data);
}
private:
private:
void InitData(int size, int seed) {
network_.clear();
network_.resize(size);
@@ -320,7 +319,7 @@ class NetworkRoutingDataBuilder {
: random_.Uniform(num_clients) + num_backbones;
}
std::vector<std::vector<bool>> network_;
std::vector<std::vector<bool> > network_;
std::vector<int> degrees_;
MTRandom random_;
};
@@ -329,18 +328,17 @@ class NetworkRoutingDataBuilder {
// Useful data struct to hold demands.
struct Demand {
public:
public:
Demand(int the_source, int the_destination, int the_traffic)
: source(the_source),
destination(the_destination),
traffic(the_traffic) {}
: source(the_source), destination(the_destination), traffic(the_traffic) {
}
int source;
int destination;
int traffic;
};
class NetworkRoutingSolver {
public:
public:
typedef std::unordered_set<int> OnePath;
NetworkRoutingSolver() : num_nodes_(-1) {}
@@ -364,8 +362,9 @@ class NetworkRoutingSolver {
tmp_vars.push_back(node_vars[i]);
tmp_vars.push_back(node_vars[i + 1]);
tmp_vars.push_back(arc_vars[i]);
TableConstraint table = cp_model.AddAllowedAssignments(
{node_vars[i], node_vars[i + 1], arc_vars[i]});
TableConstraint table = cp_model.AddAllowedAssignments({
node_vars[i], node_vars[i + 1], arc_vars[i]
});
for (const auto &tuple : arcs_data_) {
table.AddTuple(tuple);
}
@@ -382,7 +381,7 @@ class NetworkRoutingSolver {
std::atomic<bool> stopped(false);
model.GetOrCreate<TimeLimit>()->RegisterExternalBooleanAsLimit(&stopped);
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse &r) {
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse & r) {
const int path_id = all_paths_[demand_index].size();
all_paths_[demand_index].resize(path_id + 1);
for (int arc_index = 0; arc_index < max_length - 1; ++arc_index) {
@@ -423,7 +422,9 @@ class NetworkRoutingSolver {
}
void AddArcData(int64 source, int64 destination, int arc_id) {
arcs_data_.push_back({source, destination, arc_id});
arcs_data_.push_back({
source, destination, arc_id
});
}
void InitArcInfo(const NetworkRoutingData &data) {
@@ -444,7 +445,7 @@ class NetworkRoutingSolver {
arc_capacity_.push_back(capacity);
capacity_[i][j] = capacity;
capacity_[j][i] = capacity;
if (FLAGS_print_model) {
if (absl::GetFlag(FLAGS_print_model)) {
LOG(INFO) << "Arc " << i << " <-> " << j << " with capacity "
<< capacity;
}
@@ -478,10 +479,11 @@ class NetworkRoutingSolver {
for (int demand_index = 0; demand_index < num_demands; ++demand_index) {
paths.clear();
const Demand &demand = demands_array_[demand_index];
CHECK(DijkstraShortestPath(
num_nodes_, demand.source, demand.destination,
[this](int x, int y) { return HasArc(x, y); }, kDisconnectedDistance,
&paths));
CHECK(DijkstraShortestPath(num_nodes_, demand.source, demand.destination,
[this](int x, int y) {
return HasArc(x, y);
},
kDisconnectedDistance, &paths));
all_min_path_lengths_.push_back(paths.size() - 1);
}
@@ -540,7 +542,7 @@ class NetworkRoutingSolver {
if (capacity_[i][j] > 0) {
return 1;
} else {
return kDisconnectedDistance; // disconnected distance.
return kDisconnectedDistance; // disconnected distance.
}
}
@@ -553,7 +555,7 @@ class NetworkRoutingSolver {
// ----- Build Model -----
CpModelBuilder cp_model;
std::vector<std::vector<IntVar>> path_vars(num_demands);
std::vector<std::vector<IntVar> > path_vars(num_demands);
// Node - Graph Constraint.
for (int demand_index = 0; demand_index < num_demands; ++demand_index) {
@@ -591,7 +593,12 @@ class NetworkRoutingSolver {
const int64 capacity = arc_capacity_[arc_index];
IntVar scaled_traffic =
cp_model.NewIntVar(Domain(0, sum_of_traffic * 1000));
cp_model.AddEquality(LinearExpr::ScalProd({traffic_var}, {1000}),
cp_model.AddEquality(LinearExpr::ScalProd({
traffic_var
},
{
1000
}),
scaled_traffic);
IntVar normalized_traffic =
cp_model.NewIntVar(Domain(0, sum_of_traffic * 1000 / capacity));
@@ -602,7 +609,7 @@ class NetworkRoutingSolver {
normalized_traffic_vars[arc_index] = normalized_traffic;
const BoolVar comfort = cp_model.NewBoolVar();
const int64 safe_capacity =
static_cast<int64>(capacity * FLAGS_comfort_zone);
static_cast<int64>(capacity * absl::GetFlag(FLAGS_comfort_zone));
cp_model.AddGreaterThan(traffic_var, safe_capacity)
.OnlyEnforceIf(comfort);
cp_model.AddLessOrEqual(traffic_var, safe_capacity)
@@ -622,11 +629,11 @@ class NetworkRoutingSolver {
cp_model.Minimize(objective_expr);
Model model;
if (!FLAGS_params.empty()) {
model.Add(NewSatParameters(FLAGS_params));
if (!absl::GetFlag(FLAGS_params).empty()) {
model.Add(NewSatParameters(absl::GetFlag(FLAGS_params)));
}
int num_solutions = 0;
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse &r) {
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse & r) {
LOG(INFO) << "Solution " << num_solutions;
const double objective_value = r.objective_value();
const double percent = SolutionIntegerValue(r, max_usage_cost) / 10.0;
@@ -648,32 +655,37 @@ class NetworkRoutingSolver {
return response.objective_value();
}
private:
private:
int count_arcs() const { return arcs_data_.size() / 2; }
std::vector<std::vector<int64>> arcs_data_;
std::vector<std::vector<int64> > arcs_data_;
std::vector<int> arc_capacity_;
std::vector<Demand> demands_array_;
int num_nodes_;
std::vector<int64> all_min_path_lengths_;
std::vector<std::vector<int>> capacity_;
std::vector<std::vector<OnePath>> all_paths_;
std::vector<std::vector<int> > capacity_;
std::vector<std::vector<OnePath> > all_paths_;
};
} // namespace sat
} // namespace operations_research
} // namespace sat
} // namespace operations_research
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
operations_research::sat::NetworkRoutingData data;
operations_research::sat::NetworkRoutingDataBuilder builder;
builder.BuildModelFromParameters(
FLAGS_clients, FLAGS_backbones, FLAGS_demands, FLAGS_traffic_min,
FLAGS_traffic_max, FLAGS_min_client_degree, FLAGS_max_client_degree,
FLAGS_min_backbone_degree, FLAGS_max_backbone_degree, FLAGS_max_capacity,
FLAGS_fixed_charge_cost, FLAGS_seed, &data);
absl::GetFlag(FLAGS_clients), absl::GetFlag(FLAGS_backbones),
absl::GetFlag(FLAGS_demands), absl::GetFlag(FLAGS_traffic_min),
absl::GetFlag(FLAGS_traffic_max), absl::GetFlag(FLAGS_min_client_degree),
absl::GetFlag(FLAGS_max_client_degree),
absl::GetFlag(FLAGS_min_backbone_degree),
absl::GetFlag(FLAGS_max_backbone_degree),
absl::GetFlag(FLAGS_max_capacity), absl::GetFlag(FLAGS_fixed_charge_cost),
absl::GetFlag(FLAGS_seed), &data);
operations_research::sat::NetworkRoutingSolver solver;
solver.Init(data, FLAGS_extra_hops, FLAGS_max_paths);
solver.Init(data, absl::GetFlag(FLAGS_extra_hops),
absl::GetFlag(FLAGS_max_paths));
LOG(INFO) << "Final cost = " << solver.Solve();
return EXIT_SUCCESS;
}

View File

@@ -37,20 +37,20 @@ DEFINE_int32(
DEFINE_bool(use_symmetry, false, "Use Symmetry Breaking methods");
DECLARE_bool(cp_disable_solve);
static const int kNumSolutions[] = {
1, 0, 0, 2, 10, 4, 40, 92, 352, 724, 2680, 14200, 73712, 365596, 2279184};
static const int kNumSolutions[] = { 1, 0, 0, 2, 10, 4, 40, 92, 352, 724, 2680,
14200, 73712, 365596, 2279184 };
static const int kKnownSolutions = 15;
static const int kNumUniqueSolutions[] = {
1, 0, 0, 1, 2, 1, 6, 12, 46, 92,
341, 1787, 9233, 45752, 285053, 1846955, 11977939, 83263591, 621012754};
static const int kNumUniqueSolutions[] = { 1, 0, 0, 1, 2, 1, 6, 12, 46, 92, 341,
1787, 9233, 45752, 285053, 1846955,
11977939, 83263591, 621012754 };
static const int kKnownUniqueSolutions = 19;
namespace operations_research {
class NQueenSymmetry : public SymmetryBreaker {
public:
NQueenSymmetry(Solver* const s, const std::vector<IntVar*>& vars)
public:
NQueenSymmetry(Solver *const s, const std::vector<IntVar *> &vars)
: solver_(s), vars_(vars), size_(vars.size()) {
for (int i = 0; i < size_; ++i) {
indices_[vars[i]] = i;
@@ -58,133 +58,133 @@ class NQueenSymmetry : public SymmetryBreaker {
}
~NQueenSymmetry() override {}
protected:
int Index(IntVar* const var) const {
protected:
int Index(IntVar *const var) const {
return gtl::FindWithDefault(indices_, var, -1);
}
IntVar* Var(int index) const {
IntVar *Var(int index) const {
DCHECK_GE(index, 0);
DCHECK_LT(index, size_);
return vars_[index];
}
int size() const { return size_; }
int symmetric(int index) const { return size_ - 1 - index; }
Solver* const solver() const { return solver_; }
Solver *const solver() const { return solver_; }
private:
Solver* const solver_;
const std::vector<IntVar*> vars_;
std::map<const IntVar*, int> indices_;
private:
Solver *const solver_;
const std::vector<IntVar *> vars_;
std::map<const IntVar *, int> indices_;
const int size_;
};
// Symmetry vertical axis.
class SX : public NQueenSymmetry {
public:
SX(Solver* const s, const std::vector<IntVar*>& vars)
public:
SX(Solver *const s, const std::vector<IntVar *> &vars)
: NQueenSymmetry(s, vars) {}
~SX() override {}
void VisitSetVariableValue(IntVar* const var, int64 value) override {
void VisitSetVariableValue(IntVar *const var, int64 value) override {
const int index = Index(var);
IntVar* const other_var = Var(symmetric(index));
IntVar *const other_var = Var(symmetric(index));
AddIntegerVariableEqualValueClause(other_var, value);
}
};
// Symmetry horizontal axis.
class SY : public NQueenSymmetry {
public:
SY(Solver* const s, const std::vector<IntVar*>& vars)
public:
SY(Solver *const s, const std::vector<IntVar *> &vars)
: NQueenSymmetry(s, vars) {}
~SY() override {}
void VisitSetVariableValue(IntVar* const var, int64 value) override {
void VisitSetVariableValue(IntVar *const var, int64 value) override {
AddIntegerVariableEqualValueClause(var, symmetric(value));
}
};
// Symmetry first diagonal axis.
class SD1 : public NQueenSymmetry {
public:
SD1(Solver* const s, const std::vector<IntVar*>& vars)
public:
SD1(Solver *const s, const std::vector<IntVar *> &vars)
: NQueenSymmetry(s, vars) {}
~SD1() override {}
void VisitSetVariableValue(IntVar* const var, int64 value) override {
void VisitSetVariableValue(IntVar *const var, int64 value) override {
const int index = Index(var);
IntVar* const other_var = Var(value);
IntVar *const other_var = Var(value);
AddIntegerVariableEqualValueClause(other_var, index);
}
};
// Symmetry second diagonal axis.
class SD2 : public NQueenSymmetry {
public:
SD2(Solver* const s, const std::vector<IntVar*>& vars)
public:
SD2(Solver *const s, const std::vector<IntVar *> &vars)
: NQueenSymmetry(s, vars) {}
~SD2() override {}
void VisitSetVariableValue(IntVar* const var, int64 value) override {
void VisitSetVariableValue(IntVar *const var, int64 value) override {
const int index = Index(var);
IntVar* const other_var = Var(symmetric(value));
IntVar *const other_var = Var(symmetric(value));
AddIntegerVariableEqualValueClause(other_var, symmetric(index));
}
};
// Rotate 1/4 turn.
class R90 : public NQueenSymmetry {
public:
R90(Solver* const s, const std::vector<IntVar*>& vars)
public:
R90(Solver *const s, const std::vector<IntVar *> &vars)
: NQueenSymmetry(s, vars) {}
~R90() override {}
void VisitSetVariableValue(IntVar* const var, int64 value) override {
void VisitSetVariableValue(IntVar *const var, int64 value) override {
const int index = Index(var);
IntVar* const other_var = Var(value);
IntVar *const other_var = Var(value);
AddIntegerVariableEqualValueClause(other_var, symmetric(index));
}
};
// Rotate 1/2 turn.
class R180 : public NQueenSymmetry {
public:
R180(Solver* const s, const std::vector<IntVar*>& vars)
public:
R180(Solver *const s, const std::vector<IntVar *> &vars)
: NQueenSymmetry(s, vars) {}
~R180() override {}
void VisitSetVariableValue(IntVar* const var, int64 value) override {
void VisitSetVariableValue(IntVar *const var, int64 value) override {
const int index = Index(var);
IntVar* const other_var = Var(symmetric(index));
IntVar *const other_var = Var(symmetric(index));
AddIntegerVariableEqualValueClause(other_var, symmetric(value));
}
};
// Rotate 3/4 turn.
class R270 : public NQueenSymmetry {
public:
R270(Solver* const s, const std::vector<IntVar*>& vars)
public:
R270(Solver *const s, const std::vector<IntVar *> &vars)
: NQueenSymmetry(s, vars) {}
~R270() override {}
void VisitSetVariableValue(IntVar* const var, int64 value) override {
void VisitSetVariableValue(IntVar *const var, int64 value) override {
const int index = Index(var);
IntVar* const other_var = Var(symmetric(value));
IntVar *const other_var = Var(symmetric(value));
AddIntegerVariableEqualValueClause(other_var, index);
}
};
void CheckNumberOfSolutions(int size, int num_solutions) {
if (FLAGS_use_symmetry) {
if (absl::GetFlag(FLAGS_use_symmetry)) {
if (size - 1 < kKnownUniqueSolutions) {
CHECK_EQ(num_solutions, kNumUniqueSolutions[size - 1]);
} else if (!FLAGS_cp_disable_solve) {
} else if (!absl::GetFlag(FLAGS_cp_disable_solve)) {
CHECK_GT(num_solutions, 0);
}
} else {
if (size - 1 < kKnownSolutions) {
CHECK_EQ(num_solutions, kNumSolutions[size - 1]);
} else if (!FLAGS_cp_disable_solve) {
} else if (!absl::GetFlag(FLAGS_cp_disable_solve)) {
CHECK_GT(num_solutions, 0);
}
}
@@ -195,14 +195,14 @@ void NQueens(int size) {
Solver s("nqueens");
// model
std::vector<IntVar*> queens;
std::vector<IntVar *> queens;
for (int i = 0; i < size; ++i) {
queens.push_back(
s.MakeIntVar(0, size - 1, absl::StrFormat("queen%04d", i)));
}
s.AddConstraint(s.MakeAllDifferent(queens));
std::vector<IntVar*> vars(size);
std::vector<IntVar *> vars(size);
for (int i = 0; i < size; ++i) {
vars[i] = s.MakeSum(queens[i], i)->Var();
}
@@ -212,50 +212,55 @@ void NQueens(int size) {
}
s.AddConstraint(s.MakeAllDifferent(vars));
SolutionCollector* const solution_counter =
SolutionCollector *const solution_counter =
s.MakeAllSolutionCollector(nullptr);
SolutionCollector* const collector = s.MakeAllSolutionCollector();
SolutionCollector *const collector = s.MakeAllSolutionCollector();
collector->Add(queens);
std::vector<SearchMonitor*> monitors;
std::vector<SearchMonitor *> monitors;
monitors.push_back(solution_counter);
monitors.push_back(collector);
DecisionBuilder* const db = s.MakePhase(queens, Solver::CHOOSE_FIRST_UNBOUND,
DecisionBuilder *const db = s.MakePhase(queens, Solver::CHOOSE_FIRST_UNBOUND,
Solver::ASSIGN_MIN_VALUE);
if (FLAGS_use_symmetry) {
std::vector<SymmetryBreaker*> breakers;
NQueenSymmetry* const sx = s.RevAlloc(new SX(&s, queens));
if (absl::GetFlag(FLAGS_use_symmetry)) {
std::vector<SymmetryBreaker *> breakers;
NQueenSymmetry *const sx = s.RevAlloc(new SX(&s, queens));
breakers.push_back(sx);
NQueenSymmetry* const sy = s.RevAlloc(new SY(&s, queens));
NQueenSymmetry *const sy = s.RevAlloc(new SY(&s, queens));
breakers.push_back(sy);
NQueenSymmetry* const sd1 = s.RevAlloc(new SD1(&s, queens));
NQueenSymmetry *const sd1 = s.RevAlloc(new SD1(&s, queens));
breakers.push_back(sd1);
NQueenSymmetry* const sd2 = s.RevAlloc(new SD2(&s, queens));
NQueenSymmetry *const sd2 = s.RevAlloc(new SD2(&s, queens));
breakers.push_back(sd2);
NQueenSymmetry* const r90 = s.RevAlloc(new R90(&s, queens));
NQueenSymmetry *const r90 = s.RevAlloc(new R90(&s, queens));
breakers.push_back(r90);
NQueenSymmetry* const r180 = s.RevAlloc(new R180(&s, queens));
NQueenSymmetry *const r180 = s.RevAlloc(new R180(&s, queens));
breakers.push_back(r180);
NQueenSymmetry* const r270 = s.RevAlloc(new R270(&s, queens));
NQueenSymmetry *const r270 = s.RevAlloc(new R270(&s, queens));
breakers.push_back(r270);
SearchMonitor* const symmetry_manager = s.MakeSymmetryManager(breakers);
SearchMonitor *const symmetry_manager = s.MakeSymmetryManager(breakers);
monitors.push_back(symmetry_manager);
}
for (int loop = 0; loop < FLAGS_nb_loops; ++loop) {
s.Solve(db, monitors); // go!
for (int loop = 0; loop < absl::GetFlag(FLAGS_nb_loops); ++loop) {
s.Solve(db, monitors); // go!
CheckNumberOfSolutions(size, solution_counter->solution_count());
}
const int num_solutions = solution_counter->solution_count();
if (num_solutions > 0 && size < kKnownSolutions) {
int print_max = FLAGS_print_all ? num_solutions : FLAGS_print ? 1 : 0;
int print_max = absl::GetFlag(FLAGS_print_all) ? num_solutions
: absl::GetFlag(FLAGS_print)
? 1
: 0;
for (int n = 0; n < print_max; ++n) {
printf("--- solution #%d\n", n);
for (int i = 0; i < size; ++i) {
const int pos = static_cast<int>(collector->Value(n, queens[i]));
for (int k = 0; k < pos; ++k) printf(" . ");
for (int k = 0; k < pos; ++k)
printf(" . ");
printf("%2d ", i);
for (int k = pos + 1; k < size; ++k) printf(" . ");
for (int k = pos + 1; k < size; ++k)
printf(" . ");
printf("\n");
}
}
@@ -263,12 +268,12 @@ void NQueens(int size) {
printf("========= number of solutions:%d\n", num_solutions);
absl::PrintF(" number of failures: %d\n", s.failures());
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_size != 0) {
operations_research::NQueens(FLAGS_size);
if (absl::GetFlag(FLAGS_size) != 0) {
operations_research::NQueens(absl::GetFlag(FLAGS_size));
} else {
for (int n = 1; n < 12; ++n) {
operations_research::NQueens(n);

View File

@@ -33,17 +33,17 @@ namespace sat {
// The format is described here:
// http://www.cril.univ-artois.fr/PB12/format.pdf
class OpbReader {
public:
public:
OpbReader() {}
// Loads the given opb filename into the given problem.
bool Load(const std::string& filename, LinearBooleanProblem* problem) {
bool Load(const std::string &filename, LinearBooleanProblem *problem) {
problem->Clear();
problem->set_name(ExtractProblemName(filename));
num_variables_ = 0;
int num_lines = 0;
for (const std::string& line : FileLines(filename)) {
for (const std::string &line : FileLines(filename)) {
++num_lines;
ProcessNewLine(problem, line);
}
@@ -54,17 +54,17 @@ class OpbReader {
return true;
}
private:
private:
// Since the problem name is not stored in the cnf format, we infer it from
// the file name.
static std::string ExtractProblemName(const std::string& filename) {
static std::string ExtractProblemName(const std::string &filename) {
const int found = filename.find_last_of("/");
const std::string problem_name =
found != std::string::npos ? filename.substr(found + 1) : filename;
return problem_name;
}
void ProcessNewLine(LinearBooleanProblem* problem, const std::string& line) {
void ProcessNewLine(LinearBooleanProblem *problem, const std::string &line) {
const std::vector<std::string> words =
absl::StrSplit(line, absl::ByAnyChar(" ;"), absl::SkipEmpty());
if (words.empty() || words[0].empty() || words[0][0] == '*') {
@@ -72,10 +72,11 @@ class OpbReader {
}
if (words[0] == "min:") {
LinearObjective* objective = problem->mutable_objective();
LinearObjective *objective = problem->mutable_objective();
for (int i = 1; i < words.size(); ++i) {
const std::string& word = words[i];
if (word.empty() || word[0] == ';') continue;
const std::string &word = words[i];
if (word.empty() || word[0] == ';')
continue;
if (word[0] == 'x') {
int literal;
CHECK(absl::SimpleAtoi(word.substr(1), &literal));
@@ -93,9 +94,9 @@ class OpbReader {
}
return;
}
LinearBooleanConstraint* constraint = problem->add_constraints();
LinearBooleanConstraint *constraint = problem->add_constraints();
for (int i = 0; i < words.size(); ++i) {
const std::string& word = words[i];
const std::string &word = words[i];
CHECK(!word.empty());
if (word == ">=") {
CHECK_LT(i + 1, words.size());
@@ -132,7 +133,7 @@ class OpbReader {
DISALLOW_COPY_AND_ASSIGN(OpbReader);
};
} // namespace sat
} // namespace operations_research
} // namespace sat
} // namespace operations_research
#endif // OR_TOOLS_SAT_OPB_READER_H_
#endif // OR_TOOLS_SAT_OPB_READER_H_

View File

@@ -38,13 +38,11 @@ DEFINE_bool(assignment_optimize_layout, true,
namespace operations_research {
template <typename GraphType>
class LinearSumAssignment;
template <typename GraphType> class LinearSumAssignment;
template <typename GraphType>
class DimacsAssignmentParser {
public:
explicit DimacsAssignmentParser(const std::string& filename)
template <typename GraphType> class DimacsAssignmentParser {
public:
explicit DimacsAssignmentParser(const std::string &filename)
: filename_(filename), graph_builder_(nullptr), assignment_(nullptr) {}
// Reads an assignment problem description from the given file in
@@ -60,31 +58,28 @@ class DimacsAssignmentParser {
// representation back to the caller, the caller lacks a good way to
// free the underlying graph (which isn't owned by the
// LinearAssignment instance).
LinearSumAssignment<GraphType>* Parse(std::string* error_message,
GraphType** graph);
LinearSumAssignment<GraphType> *Parse(std::string *error_message,
GraphType **graph);
private:
void ParseProblemLine(const std::string& line);
private:
void ParseProblemLine(const std::string &line);
void ParseNodeLine(const std::string& line);
void ParseNodeLine(const std::string &line);
void ParseArcLine(const std::string& line);
void ParseArcLine(const std::string &line);
void ParseOneLine(const std::string& line);
void ParseOneLine(const std::string &line);
std::string filename_;
struct ErrorTrackingState {
ErrorTrackingState()
: bad(false),
nodes_described(false),
reason(nullptr),
num_left_nodes(0),
num_arcs(0) {}
: bad(false), nodes_described(false), reason(nullptr),
num_left_nodes(0), num_arcs(0) {}
bool bad;
bool nodes_described;
const char* reason;
const char *reason;
NodeIndex num_left_nodes;
ArcIndex num_arcs;
std::unique_ptr<std::string> bad_line;
@@ -92,18 +87,18 @@ class DimacsAssignmentParser {
ErrorTrackingState state_;
AnnotatedGraphBuildManager<GraphType>* graph_builder_;
AnnotatedGraphBuildManager<GraphType> *graph_builder_;
LinearSumAssignment<GraphType>* assignment_;
LinearSumAssignment<GraphType> *assignment_;
};
// Implementation is below here.
template <typename GraphType>
void DimacsAssignmentParser<GraphType>::ParseProblemLine(
const std::string& line) {
static const char* kIncorrectProblemLine =
void
DimacsAssignmentParser<GraphType>::ParseProblemLine(const std::string &line) {
static const char *kIncorrectProblemLine =
"Incorrect assignment problem line.";
static const char* kAssignmentProblemType = "asn";
static const char *kAssignmentProblemType = "asn";
char problem_type[4];
NodeIndex num_nodes;
ArcIndex num_arcs;
@@ -120,11 +115,11 @@ void DimacsAssignmentParser<GraphType>::ParseProblemLine(
state_.num_arcs = num_arcs;
graph_builder_ = new AnnotatedGraphBuildManager<GraphType>(
num_nodes, num_arcs, FLAGS_assignment_optimize_layout);
num_nodes, num_arcs, absl::GetFlag(FLAGS_assignment_optimize_layout));
}
template <typename GraphType>
void DimacsAssignmentParser<GraphType>::ParseNodeLine(const std::string& line) {
void DimacsAssignmentParser<GraphType>::ParseNodeLine(const std::string &line) {
NodeIndex node_id;
if (sscanf(line.c_str(), "%*c%d", &node_id) != 1) {
state_.bad = true;
@@ -142,7 +137,7 @@ void DimacsAssignmentParser<GraphType>::ParseNodeLine(const std::string& line) {
}
template <typename GraphType>
void DimacsAssignmentParser<GraphType>::ParseArcLine(const std::string& line) {
void DimacsAssignmentParser<GraphType>::ParseArcLine(const std::string &line) {
if (graph_builder_ == nullptr) {
state_.bad = true;
state_.reason =
@@ -165,44 +160,45 @@ void DimacsAssignmentParser<GraphType>::ParseArcLine(const std::string& line) {
state_.bad_line.reset(new std::string(line));
}
ArcIndex arc = graph_builder_->AddArc(tail - 1, head - 1);
assignment_->SetArcCost(arc, FLAGS_assignment_maximize_cost ? -cost : cost);
assignment_->SetArcCost(
arc, absl::GetFlag(FLAGS_assignment_maximize_cost) ? -cost : cost);
}
// Parameters out of style-guide order because this function is used
// as a callback that varies the input line.
template <typename GraphType>
void DimacsAssignmentParser<GraphType>::ParseOneLine(const std::string& line) {
void DimacsAssignmentParser<GraphType>::ParseOneLine(const std::string &line) {
if (state_.bad) {
return;
}
switch (line[0]) {
case 'p': {
// Problem-specification line
ParseProblemLine(line);
break;
}
case 'c': {
// Comment; do nothing.
return;
}
case 'n': {
// Node line defining a node on the left side
ParseNodeLine(line);
break;
}
case 'a': {
ParseArcLine(line);
break;
}
case '0':
case '\n':
break;
default: {
state_.bad = true;
state_.reason = "Unknown line type in the input.";
state_.bad_line.reset(new std::string(line));
break;
}
case 'p': {
// Problem-specification line
ParseProblemLine(line);
break;
}
case 'c': {
// Comment; do nothing.
return;
}
case 'n': {
// Node line defining a node on the left side
ParseNodeLine(line);
break;
}
case 'a': {
ParseArcLine(line);
break;
}
case '0':
case '\n':
break;
default: {
state_.bad = true;
state_.reason = "Unknown line type in the input.";
state_.bad_line.reset(new std::string(line));
break;
}
}
}
@@ -220,12 +216,13 @@ void DimacsAssignmentParser<GraphType>::ParseOneLine(const std::string& line) {
// free the underlying graph (which isn't owned by the
// LinearAssignment instance).
template <typename GraphType>
LinearSumAssignment<GraphType>* DimacsAssignmentParser<GraphType>::Parse(
std::string* error_message, GraphType** graph_handle) {
LinearSumAssignment<GraphType> *
DimacsAssignmentParser<GraphType>::Parse(std::string *error_message,
GraphType **graph_handle) {
CHECK(error_message != nullptr);
CHECK(graph_handle != nullptr);
for (const std::string& line : FileLines(filename_)) {
for (const std::string &line : FileLines(filename_)) {
if (line.empty()) {
continue;
}
@@ -243,7 +240,7 @@ LinearSumAssignment<GraphType>* DimacsAssignmentParser<GraphType>::Parse(
}
std::unique_ptr<PermutationCycleHandler<ArcIndex> > cycle_handler(
assignment_->ArcAnnotationCycleHandler());
GraphType* graph = graph_builder_->Graph(cycle_handler.get());
GraphType *graph = graph_builder_->Graph(cycle_handler.get());
if (graph == nullptr) {
*error_message = "unable to create compact static graph";
return nullptr;
@@ -257,6 +254,6 @@ LinearSumAssignment<GraphType>* DimacsAssignmentParser<GraphType>::Parse(
return assignment_;
}
} // namespace operations_research
} // namespace operations_research
#endif // OR_TOOLS_EXAMPLES_PARSE_DIMACS_ASSIGNMENT_H_
#endif // OR_TOOLS_EXAMPLES_PARSE_DIMACS_ASSIGNMENT_H_

View File

@@ -76,7 +76,7 @@ typedef std::vector<std::pair<int, int> > Coordinates;
// Returns the scaled Euclidean distance between two nodes, coords holding the
// coordinates of the nodes.
int64 Travel(const Coordinates* const coords,
int64 Travel(const Coordinates *const coords,
RoutingIndexManager::NodeIndex from,
RoutingIndexManager::NodeIndex to) {
DCHECK(coords != nullptr);
@@ -89,7 +89,7 @@ int64 Travel(const Coordinates* const coords,
// Returns the scaled service time at a given node, service_times holding the
// service times.
int64 ServiceTime(const std::vector<int64>* const service_times,
int64 ServiceTime(const std::vector<int64> *const service_times,
RoutingIndexManager::NodeIndex node) {
return kScalingFactor * service_times->at(node.value());
}
@@ -98,9 +98,9 @@ int64 ServiceTime(const std::vector<int64>* const service_times,
// holding the coordinates of the nodes and service_times holding the service
// times.
// The service time is the time spent to execute a delivery or a pickup.
int64 TravelPlusServiceTime(const RoutingIndexManager& manager,
const Coordinates* const coords,
const std::vector<int64>* const service_times,
int64 TravelPlusServiceTime(const RoutingIndexManager &manager,
const Coordinates *const coords,
const std::vector<int64> *const service_times,
int64 from_index, int64 to_index) {
const RoutingIndexManager::NodeIndex from = manager.IndexToNode(from_index);
const RoutingIndexManager::NodeIndex to = manager.IndexToNode(to_index);
@@ -113,14 +113,14 @@ int64 TravelPlusServiceTime(const RoutingIndexManager& manager,
// - Number of used vehicles,
// - Total schedule duration.
// TODO(user): add total waiting time.
std::vector<IntVar*> GetTabuVars(std::vector<IntVar*> existing_vars,
operations_research::RoutingModel* routing) {
Solver* const solver = routing->solver();
std::vector<IntVar*> vars(std::move(existing_vars));
std::vector<IntVar *> GetTabuVars(std::vector<IntVar *> existing_vars,
operations_research::RoutingModel *routing) {
Solver *const solver = routing->solver();
std::vector<IntVar *> vars(std::move(existing_vars));
vars.push_back(routing->CostVar());
IntVar* used_vehicles = solver->MakeIntVar(0, routing->vehicles());
std::vector<IntVar*> is_used_vars;
IntVar *used_vehicles = solver->MakeIntVar(0, routing->vehicles());
std::vector<IntVar *> is_used_vars;
// Number of vehicle used
is_used_vars.reserve(routing->vehicles());
for (int v = 0; v < routing->vehicles(); v++) {
@@ -135,14 +135,14 @@ std::vector<IntVar*> GetTabuVars(std::vector<IntVar*> existing_vars,
}
// Outputs a solution to the current model in a std::string.
std::string VerboseOutput(const RoutingModel& routing,
const RoutingIndexManager& manager,
const Assignment& assignment,
const Coordinates& coords,
const std::vector<int64>& service_times) {
std::string VerboseOutput(const RoutingModel &routing,
const RoutingIndexManager &manager,
const Assignment &assignment,
const Coordinates &coords,
const std::vector<int64> &service_times) {
std::string output;
const RoutingDimension& time_dimension = routing.GetDimensionOrDie("time");
const RoutingDimension& load_dimension = routing.GetDimensionOrDie("demand");
const RoutingDimension &time_dimension = routing.GetDimensionOrDie("time");
const RoutingDimension &load_dimension = routing.GetDimensionOrDie("demand");
for (int i = 0; i < routing.vehicles(); ++i) {
absl::StrAppendFormat(&output, "Vehicle %d: ", i);
int64 index = routing.Start(i);
@@ -152,13 +152,13 @@ std::string VerboseOutput(const RoutingModel& routing,
while (!routing.IsEnd(index)) {
absl::StrAppendFormat(&output, "%d ",
manager.IndexToNode(index).value());
const IntVar* vehicle = routing.VehicleVar(index);
const IntVar *vehicle = routing.VehicleVar(index);
absl::StrAppendFormat(&output, "Vehicle(%d) ",
assignment.Value(vehicle));
const IntVar* arrival = time_dimension.CumulVar(index);
const IntVar *arrival = time_dimension.CumulVar(index);
absl::StrAppendFormat(&output, "Time(%d..%d) ", assignment.Min(arrival),
assignment.Max(arrival));
const IntVar* load = load_dimension.CumulVar(index);
const IntVar *load = load_dimension.CumulVar(index);
absl::StrAppendFormat(&output, "Load(%d..%d) ", assignment.Min(load),
assignment.Max(load));
const int64 next_index = assignment.Value(routing.NextVar(index));
@@ -169,12 +169,12 @@ std::string VerboseOutput(const RoutingModel& routing,
index = next_index;
}
output.append("Route end ");
const IntVar* vehicle = routing.VehicleVar(index);
const IntVar *vehicle = routing.VehicleVar(index);
absl::StrAppendFormat(&output, "Vehicle(%d) ", assignment.Value(vehicle));
const IntVar* arrival = time_dimension.CumulVar(index);
const IntVar *arrival = time_dimension.CumulVar(index);
absl::StrAppendFormat(&output, "Time(%d..%d) ", assignment.Min(arrival),
assignment.Max(arrival));
const IntVar* load = load_dimension.CumulVar(index);
const IntVar *load = load_dimension.CumulVar(index);
absl::StrAppendFormat(&output, "Load(%d..%d) ", assignment.Min(load),
assignment.Max(load));
}
@@ -187,27 +187,28 @@ namespace {
// An inefficient but convenient method to parse a whitespace-separated list
// of integers. Returns true iff the input std::string was entirely valid and
// parsed.
bool SafeParseInt64Array(const std::string& str,
std::vector<int64>* parsed_int) {
bool SafeParseInt64Array(const std::string &str,
std::vector<int64> *parsed_int) {
std::istringstream input(str);
int64 x;
parsed_int->clear();
while (input >> x) parsed_int->push_back(x);
while (input >> x)
parsed_int->push_back(x);
return input.eof();
}
} // namespace
} // namespace
// Builds and solves a model from a file in the format defined by Li & Lim
// (https://www.sintef.no/projectweb/top/pdptw/li-lim-benchmark/documentation/).
bool LoadAndSolve(const std::string& pdp_file,
const RoutingModelParameters& model_parameters,
const RoutingSearchParameters& search_parameters) {
bool LoadAndSolve(const std::string &pdp_file,
const RoutingModelParameters &model_parameters,
const RoutingSearchParameters &search_parameters) {
// Load all the lines of the file in RAM (it shouldn't be too large anyway).
std::vector<std::string> lines;
{
std::string contents;
CHECK_OK(file::GetContents(pdp_file, &contents, file::Defaults()));
const int64 kMaxInputFileSize = 1 << 30; // 1GB
const int64 kMaxInputFileSize = 1 << 30; // 1GB
if (contents.size() >= kMaxInputFileSize) {
LOG(WARNING) << "Input file '" << pdp_file << "' is too large (>"
<< kMaxInputFileSize << " bytes).";
@@ -227,8 +228,9 @@ bool LoadAndSolve(const std::string& pdp_file,
LOG(WARNING) << "Malformed header: " << lines[0];
return false;
}
const int num_vehicles =
FLAGS_pdp_force_vehicles > 0 ? FLAGS_pdp_force_vehicles : parsed_int[0];
const int num_vehicles = absl::GetFlag(FLAGS_pdp_force_vehicles) > 0
? absl::GetFlag(FLAGS_pdp_force_vehicles)
: parsed_int[0];
const int64 capacity = parsed_int[1];
// We do not care about the 'speed' field, in third position.
@@ -281,26 +283,28 @@ bool LoadAndSolve(const std::string& pdp_file,
RoutingModel routing(manager, model_parameters);
const int vehicle_cost =
routing.RegisterTransitCallback([&coords, &manager](int64 i, int64 j) {
return Travel(const_cast<const Coordinates*>(&coords),
manager.IndexToNode(i), manager.IndexToNode(j));
});
return Travel(const_cast<const Coordinates *>(&coords),
manager.IndexToNode(i), manager.IndexToNode(j));
});
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
RoutingTransitCallback2 demand_evaluator = [&](int64 from_index,
int64 to_index) {
RoutingTransitCallback2 demand_evaluator =
[&](int64 from_index, int64 to_index) {
return demands[manager.IndexToNode(from_index).value()];
};
}
;
routing.AddDimension(routing.RegisterTransitCallback(demand_evaluator), 0,
capacity, /*fix_start_cumul_to_zero=*/true, "demand");
RoutingTransitCallback2 time_evaluator = [&](int64 from_index,
int64 to_index) {
capacity, /*fix_start_cumul_to_zero=*/ true, "demand");
RoutingTransitCallback2 time_evaluator =
[&](int64 from_index, int64 to_index) {
return TravelPlusServiceTime(manager, &coords, &service_times, from_index,
to_index);
};
}
;
routing.AddDimension(routing.RegisterTransitCallback(time_evaluator),
kScalingFactor * horizon, kScalingFactor * horizon,
/*fix_start_cumul_to_zero=*/true, "time");
const RoutingDimension& time_dimension = routing.GetDimensionOrDie("time");
Solver* const solver = routing.solver();
/*fix_start_cumul_to_zero=*/ true, "time");
const RoutingDimension &time_dimension = routing.GetDimensionOrDie("time");
Solver *const solver = routing.solver();
for (int node = 0; node < num_nodes; ++node) {
const int64 index =
manager.NodeToIndex(RoutingIndexManager::NodeIndex(node));
@@ -314,7 +318,7 @@ bool LoadAndSolve(const std::string& pdp_file,
routing.AddPickupAndDelivery(index,
manager.NodeToIndex(deliveries[node]));
}
IntVar* const cumul = time_dimension.CumulVar(index);
IntVar *const cumul = time_dimension.CumulVar(index);
cumul->SetMin(kScalingFactor * open_times[node]);
cumul->SetMax(kScalingFactor * close_times[node]);
}
@@ -325,13 +329,13 @@ bool LoadAndSolve(const std::string& pdp_file,
// This will be used as one of the Tabu criteria.
// This is done here and not in GetTabuVarsCallback as it requires calling
// AddVariableMinimizedByFinalizer and this method must be called early.
std::vector<IntVar*> end_cumuls;
std::vector<IntVar*> start_cumuls;
std::vector<IntVar *> end_cumuls;
std::vector<IntVar *> start_cumuls;
for (int i = 0; i < routing.vehicles(); ++i) {
end_cumuls.push_back(time_dimension.CumulVar(routing.End(i)));
start_cumuls.push_back(time_dimension.CumulVar(routing.Start(i)));
}
IntVar* total_time = solver->MakeIntVar(0, 99999999, "total");
IntVar *total_time = solver->MakeIntVar(0, 99999999, "total");
solver->AddConstraint(solver->MakeEquality(
solver->MakeDifference(solver->MakeSum(end_cumuls),
solver->MakeSum(start_cumuls)),
@@ -340,9 +344,13 @@ bool LoadAndSolve(const std::string& pdp_file,
routing.AddVariableMinimizedByFinalizer(total_time);
RoutingModel::GetTabuVarsCallback tabu_var_callback =
[total_time](RoutingModel* model) {
return GetTabuVars({total_time}, model);
};
[total_time](RoutingModel * model) {
return GetTabuVars({
total_time
},
model);
}
;
routing.SetTabuVarsCallback(tabu_var_callback);
}
@@ -357,12 +365,12 @@ bool LoadAndSolve(const std::string& pdp_file,
// Solve pickup and delivery problem.
SimpleCycleTimer timer;
timer.Start();
const Assignment* assignment = routing.SolveWithParameters(search_parameters);
const Assignment *assignment = routing.SolveWithParameters(search_parameters);
timer.Stop();
LOG(INFO) << routing.solver()->LocalSearchProfile();
if (nullptr != assignment) {
LOG(INFO) << VerboseOutput(routing, manager, *assignment, coords,
service_times);
LOG(INFO)
<< VerboseOutput(routing, manager, *assignment, coords, service_times);
LOG(INFO) << "Cost: " << assignment->ObjectiveValue();
int skipped_nodes = 0;
for (int node = 0; node < routing.Size(); node++) {
@@ -385,22 +393,22 @@ bool LoadAndSolve(const std::string& pdp_file,
return false;
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char** argv) {
absl::SetFlag(&FLAGS_logtostderr, true);
int main(int argc, char **argv) {
absl::SetFlag(&absl::GetFlag(FLAGS_logtostderr), true);
gflags::ParseCommandLineFlags(&argc, &argv, true);
operations_research::RoutingModelParameters model_parameters =
operations_research::DefaultRoutingModelParameters();
model_parameters.set_reduce_vehicle_cost_model(
FLAGS_reduce_vehicle_cost_model);
absl::GetFlag(FLAGS_reduce_vehicle_cost_model));
operations_research::RoutingSearchParameters search_parameters =
operations_research::DefaultRoutingSearchParameters();
CHECK(google::protobuf::TextFormat::MergeFromString(
FLAGS_routing_search_parameters, &search_parameters));
if (!operations_research::LoadAndSolve(FLAGS_pdp_file, model_parameters,
search_parameters)) {
LOG(INFO) << "Error solving " << FLAGS_pdp_file;
absl::GetFlag(FLAGS_routing_search_parameters), &search_parameters));
if (!operations_research::LoadAndSolve(absl::GetFlag(FLAGS_pdp_file),
model_parameters, search_parameters)) {
LOG(INFO) << "Error solving " << absl::GetFlag(FLAGS_pdp_file);
}
return EXIT_SUCCESS;
}

View File

@@ -30,8 +30,7 @@
namespace operations_research {
template <typename GraphType>
class LinearSumAssignment;
template <typename GraphType> class LinearSumAssignment;
// Given a LinearSumAssigment object representing an assignment problem
// description, outputs the problem in DIMACS format in the output file.
@@ -39,12 +38,12 @@ class LinearSumAssignment;
// http://lpsolve.sourceforge.net/5.5/DIMACS_asn.htm
template <typename GraphType>
void PrintDimacsAssignmentProblem(
const LinearSumAssignment<GraphType>& assignment,
const TailArrayManager<GraphType>& tail_array_manager,
const std::string& output_filename) {
File* output;
const LinearSumAssignment<GraphType> &assignment,
const TailArrayManager<GraphType> &tail_array_manager,
const std::string &output_filename) {
File *output;
CHECK_OK(file::Open(output_filename, "w", &output, file::Defaults()));
const GraphType& graph(assignment.Graph());
const GraphType &graph(assignment.Graph());
std::string output_line =
absl::StrFormat("p asn %d %d\n", graph.num_nodes(), graph.num_arcs());
CHECK_OK(file::WriteString(output, output_line, file::Defaults()));
@@ -67,6 +66,6 @@ void PrintDimacsAssignmentProblem(
}
}
} // namespace operations_research
} // namespace operations_research
#endif // OR_TOOLS_EXAMPLES_PRINT_DIMACS_ASSIGNMENT_H_
#endif // OR_TOOLS_EXAMPLES_PRINT_DIMACS_ASSIGNMENT_H_

View File

@@ -44,11 +44,10 @@ DEFINE_int32(tsp_random_forbidden_connections, 0,
"Number of random forbidden connections.");
DEFINE_bool(tsp_use_deterministic_random_seed, false,
"Use deterministic random seeds.");
DEFINE_string(routing_search_parameters,
"local_search_operators {"
" use_path_lns:BOOL_TRUE"
" use_inactive_lns:BOOL_TRUE"
"}",
DEFINE_string(routing_search_parameters, "local_search_operators {"
" use_path_lns:BOOL_TRUE"
" use_inactive_lns:BOOL_TRUE"
"}",
"Text proto RoutingSearchParameters (possibly partial) that will "
"override the DefaultRoutingSearchParameters()");
@@ -56,7 +55,7 @@ namespace operations_research {
// Random seed generator.
int32 GetSeed() {
if (FLAGS_tsp_use_deterministic_random_seed) {
if (absl::GetFlag(FLAGS_tsp_use_deterministic_random_seed)) {
return ACMRandom::DeterministicSeed();
} else {
return ACMRandom::HostnamePidTimeSeed();
@@ -69,12 +68,12 @@ int32 GetSeed() {
int64 MyDistance(RoutingIndexManager::NodeIndex from,
RoutingIndexManager::NodeIndex to) {
// Put your distance code here.
return (from + to).value(); // for instance
return (from + to).value(); // for instance
}
// Random matrix.
class RandomMatrix {
public:
public:
explicit RandomMatrix(int size) : size_(size) {}
void Initialize() {
matrix_ = absl::make_unique<int64[]>(size_ * size_);
@@ -95,7 +94,7 @@ class RandomMatrix {
return matrix_[MatrixIndex(from, to)];
}
private:
private:
int64 MatrixIndex(RoutingIndexManager::NodeIndex from,
RoutingIndexManager::NodeIndex to) const {
return (from * size_ + to).value();
@@ -105,44 +104,46 @@ class RandomMatrix {
};
void Tsp() {
if (FLAGS_tsp_size > 0) {
// TSP of size FLAGS_tsp_size.
if (absl::GetFlag(FLAGS_tsp_size) > 0) {
// TSP of size absl::GetFlag(FLAGS_tsp_size).
// Second argument = 1 to build a single tour (it's a TSP).
// Nodes are indexed from 0 to FLAGS_tsp_size - 1, by default the start of
// Nodes are indexed from 0 to absl::GetFlag(FLAGS_tsp_size) - 1, by default
// the start of
// the route is node 0.
RoutingIndexManager manager(FLAGS_tsp_size, 1,
RoutingIndexManager manager(absl::GetFlag(FLAGS_tsp_size), 1,
RoutingIndexManager::NodeIndex(0));
RoutingModel routing(manager);
RoutingSearchParameters parameters = DefaultRoutingSearchParameters();
CHECK(google::protobuf::TextFormat::MergeFromString(
FLAGS_routing_search_parameters, &parameters));
absl::GetFlag(FLAGS_routing_search_parameters), &parameters));
// Setting the cost function.
// Put a permanent callback to the distance accessor here. The callback
// has the following signature: ResultCallback2<int64, int64, int64>.
// The two arguments are the from and to node inidices.
RandomMatrix matrix(FLAGS_tsp_size);
if (FLAGS_tsp_use_random_matrix) {
RandomMatrix matrix(absl::GetFlag(FLAGS_tsp_size));
if (absl::GetFlag(FLAGS_tsp_use_random_matrix)) {
matrix.Initialize();
const int vehicle_cost = routing.RegisterTransitCallback(
[&matrix, &manager](int64 i, int64 j) {
return matrix.Distance(manager.IndexToNode(i),
manager.IndexToNode(j));
});
return matrix.Distance(manager.IndexToNode(i), manager.IndexToNode(j));
});
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
} else {
const int vehicle_cost =
routing.RegisterTransitCallback([&manager](int64 i, int64 j) {
return MyDistance(manager.IndexToNode(i), manager.IndexToNode(j));
});
return MyDistance(manager.IndexToNode(i), manager.IndexToNode(j));
});
routing.SetArcCostEvaluatorOfAllVehicles(vehicle_cost);
}
// Forbid node connections (randomly).
ACMRandom randomizer(GetSeed());
int64 forbidden_connections = 0;
while (forbidden_connections < FLAGS_tsp_random_forbidden_connections) {
const int64 from = randomizer.Uniform(FLAGS_tsp_size - 1);
const int64 to = randomizer.Uniform(FLAGS_tsp_size - 1) + 1;
while (forbidden_connections <
absl::GetFlag(FLAGS_tsp_random_forbidden_connections)) {
const int64 from = randomizer.Uniform(absl::GetFlag(FLAGS_tsp_size) - 1);
const int64 to =
randomizer.Uniform(absl::GetFlag(FLAGS_tsp_size) - 1) + 1;
if (routing.NextVar(from)->Contains(to)) {
LOG(INFO) << "Forbidding connection " << from << " -> " << to;
routing.NextVar(from)->RemoveValue(to);
@@ -150,7 +151,7 @@ void Tsp() {
}
}
// Solve, returns a solution if any (owned by RoutingModel).
const Assignment* solution = routing.SolveWithParameters(parameters);
const Assignment *solution = routing.SolveWithParameters(parameters);
if (solution != nullptr) {
// Solution cost.
LOG(INFO) << "Cost " << solution->ObjectiveValue();
@@ -173,9 +174,9 @@ void Tsp() {
LOG(INFO) << "Specify an instance size greater than 0.";
}
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
operations_research::Tsp();
return EXIT_SUCCESS;

View File

@@ -40,7 +40,7 @@ namespace operations_research {
namespace sat {
struct LinearBooleanProblemWrapper {
explicit LinearBooleanProblemWrapper(LinearBooleanProblem* p) : problem(p) {}
explicit LinearBooleanProblemWrapper(LinearBooleanProblem *p) : problem(p) {}
void SetNumVariables(int num) { problem->set_num_variables(num); }
void SetOriginalNumVariables(int num) {
@@ -48,7 +48,7 @@ struct LinearBooleanProblemWrapper {
}
void AddConstraint(absl::Span<const int> clause) {
LinearBooleanConstraint* constraint = problem->add_constraints();
LinearBooleanConstraint *constraint = problem->add_constraints();
constraint->mutable_literals()->Reserve(clause.size());
constraint->mutable_coefficients()->Reserve(clause.size());
constraint->set_lower_bound(1);
@@ -68,15 +68,15 @@ struct LinearBooleanProblemWrapper {
problem->mutable_objective()->set_offset(offset);
}
LinearBooleanProblem* problem;
LinearBooleanProblem *problem;
};
struct CpModelProtoWrapper {
explicit CpModelProtoWrapper(CpModelProto* p) : problem(p) {}
explicit CpModelProtoWrapper(CpModelProto *p) : problem(p) {}
void SetNumVariables(int num) {
for (int i = 0; i < num; ++i) {
IntegerVariableProto* variable = problem->add_variables();
IntegerVariableProto *variable = problem->add_variables();
variable->add_domain(0);
variable->add_domain(1);
}
@@ -93,7 +93,7 @@ struct CpModelProtoWrapper {
}
void AddConstraint(absl::Span<const int> clause) {
auto* constraint = problem->add_constraints()->mutable_bool_or();
auto *constraint = problem->add_constraints()->mutable_bool_or();
constraint->mutable_literals()->Reserve(clause.size());
for (const int literal : clause) {
constraint->add_literals(LiteralToRef(literal));
@@ -110,7 +110,7 @@ struct CpModelProtoWrapper {
problem->mutable_objective()->set_offset(offset);
}
CpModelProto* problem;
CpModelProto *problem;
};
// This class loads a file in cnf file format into a SatProblem.
@@ -119,7 +119,7 @@ struct CpModelProtoWrapper {
//
// It also support the wcnf input format for partial weighted max-sat problems.
class SatCnfReader {
public:
public:
SatCnfReader() : interpret_cnf_as_max_sat_(false) {}
// If called with true, then a cnf file will be converted to the max-sat
@@ -127,22 +127,22 @@ class SatCnfReader {
void InterpretCnfAsMaxSat(bool v) { interpret_cnf_as_max_sat_ = v; }
// Loads the given cnf filename into the given proto.
bool Load(const std::string& filename, LinearBooleanProblem* problem) {
bool Load(const std::string &filename, LinearBooleanProblem *problem) {
problem->Clear();
problem->set_name(ExtractProblemName(filename));
LinearBooleanProblemWrapper wrapper(problem);
return LoadInternal(filename, &wrapper);
}
bool Load(const std::string& filename, CpModelProto* problem) {
bool Load(const std::string &filename, CpModelProto *problem) {
problem->Clear();
problem->set_name(ExtractProblemName(filename));
CpModelProtoWrapper wrapper(problem);
return LoadInternal(filename, &wrapper);
}
private:
private:
template <class Problem>
bool LoadInternal(const std::string& filename, Problem* problem) {
bool LoadInternal(const std::string &filename, Problem *problem) {
positive_literal_to_weight_.clear();
objective_offset_ = 0;
is_wcnf_ = false;
@@ -154,7 +154,7 @@ class SatCnfReader {
num_slack_variables_ = 0;
int num_lines = 0;
for (const std::string& line : FileLines(filename)) {
for (const std::string &line : FileLines(filename)) {
++num_lines;
ProcessNewLine(line, problem);
}
@@ -185,7 +185,7 @@ class SatCnfReader {
// Since the problem name is not stored in the cnf format, we infer it from
// the file name.
static std::string ExtractProblemName(const std::string& filename) {
static std::string ExtractProblemName(const std::string &filename) {
const int found = filename.find_last_of("/");
const std::string problem_name =
found != std::string::npos ? filename.substr(found + 1) : filename;
@@ -201,7 +201,7 @@ class SatCnfReader {
return value;
}
void ProcessHeader(const std::string& line) {
void ProcessHeader(const std::string &line) {
static const char kWordDelimiters[] = " ";
words_ = absl::StrSplit(line, kWordDelimiters, absl::SkipEmpty());
@@ -220,9 +220,11 @@ class SatCnfReader {
}
template <class Problem>
void ProcessNewLine(const std::string& line, Problem* problem) {
if (line.empty() || end_marker_seen_) return;
if (line[0] == 'c') return;
void ProcessNewLine(const std::string &line, Problem *problem) {
if (line.empty() || end_marker_seen_)
return;
if (line[0] == 'c')
return;
if (line[0] == '%') {
end_marker_seen_ = true;
return;
@@ -251,13 +253,14 @@ class SatCnfReader {
} else {
if (signed_value == 0) {
end_marker_seen = true;
break; // end of clause.
break; // end of clause.
}
tmp_clause_.push_back(signed_value);
}
first = false;
}
if (!end_marker_seen) return;
if (!end_marker_seen)
return;
if (weight == hard_weight_) {
++num_added_clauses_;
@@ -294,11 +297,13 @@ class SatCnfReader {
objective_offset_ += weight;
}
if (FLAGS_wcnf_use_strong_slack) {
if (absl::GetFlag(FLAGS_wcnf_use_strong_slack)) {
// Add the binary implications slack_literal true => all the other
// clause literals are false.
for (int i = 0; i + 1 < tmp_clause_.size(); ++i) {
problem->AddConstraint({-slack_literal, -tmp_clause_[i]});
problem->AddConstraint({
-slack_literal, -tmp_clause_[i]
});
}
}
}
@@ -334,7 +339,7 @@ class SatCnfReader {
DISALLOW_COPY_AND_ASSIGN(SatCnfReader);
};
} // namespace sat
} // namespace operations_research
} // namespace sat
} // namespace operations_research
#endif // OR_TOOLS_SAT_SAT_CNF_READER_H_
#endif // OR_TOOLS_SAT_SAT_CNF_READER_H_

View File

@@ -129,17 +129,18 @@ namespace {
// Returns a trivial best bound. The best bound corresponds to the lower bound
// (resp. upper bound) in case of a minimization (resp. maximization) problem.
double GetScaledTrivialBestBound(const LinearBooleanProblem& problem) {
double GetScaledTrivialBestBound(const LinearBooleanProblem &problem) {
Coefficient best_bound(0);
const LinearObjective& objective = problem.objective();
const LinearObjective &objective = problem.objective();
for (const int64 value : objective.coefficients()) {
if (value < 0) best_bound += Coefficient(value);
if (value < 0)
best_bound += Coefficient(value);
}
return AddOffsetAndScaleObjectiveValue(problem, best_bound);
}
bool LoadBooleanProblem(const std::string& filename,
LinearBooleanProblem* problem, CpModelProto* cp_model) {
bool LoadBooleanProblem(const std::string &filename,
LinearBooleanProblem *problem, CpModelProto *cp_model) {
if (absl::EndsWith(filename, ".opb") ||
absl::EndsWith(filename, ".opb.bz2")) {
OpbReader reader;
@@ -151,11 +152,12 @@ bool LoadBooleanProblem(const std::string& filename,
absl::EndsWith(filename, ".wcnf") ||
absl::EndsWith(filename, ".wcnf.gz")) {
SatCnfReader reader;
if (FLAGS_fu_malik || FLAGS_linear_scan || FLAGS_wpm1 || FLAGS_qmaxsat ||
FLAGS_core_enc) {
if (absl::GetFlag(FLAGS_fu_malik) || absl::GetFlag(FLAGS_linear_scan) ||
absl::GetFlag(FLAGS_wpm1) || absl::GetFlag(FLAGS_qmaxsat) ||
absl::GetFlag(FLAGS_core_enc)) {
reader.InterpretCnfAsMaxSat(true);
}
if (FLAGS_use_cp_model) {
if (absl::GetFlag(FLAGS_use_cp_model)) {
if (!reader.Load(filename, cp_model)) {
LOG(FATAL) << "Cannot load file '" << filename << "'.";
}
@@ -164,7 +166,7 @@ bool LoadBooleanProblem(const std::string& filename,
LOG(FATAL) << "Cannot load file '" << filename << "'.";
}
}
} else if (FLAGS_use_cp_model) {
} else if (absl::GetFlag(FLAGS_use_cp_model)) {
LOG(INFO) << "Reading a CpModelProto.";
*cp_model = ReadFileToProtoOrDie<CpModelProto>(filename);
} else {
@@ -174,12 +176,13 @@ bool LoadBooleanProblem(const std::string& filename,
return true;
}
std::string SolutionString(const LinearBooleanProblem& problem,
const std::vector<bool>& assignment) {
std::string SolutionString(const LinearBooleanProblem &problem,
const std::vector<bool> &assignment) {
std::string output;
BooleanVariable limit(problem.original_num_variables());
for (BooleanVariable index(0); index < limit; ++index) {
if (index > 0) output += " ";
if (index > 0)
output += " ";
absl::StrAppend(&output,
Literal(index, assignment[index.value()]).SignedValue());
}
@@ -190,15 +193,15 @@ std::string SolutionString(const LinearBooleanProblem& problem,
// here.
int Run() {
SatParameters parameters;
if (FLAGS_input.empty()) {
if (absl::GetFlag(FLAGS_input).empty()) {
LOG(FATAL) << "Please supply a data file with --input=";
}
// Parse the --params flag.
if (!FLAGS_params.empty()) {
CHECK(google::protobuf::TextFormat::MergeFromString(FLAGS_params,
&parameters))
<< FLAGS_params;
if (!absl::GetFlag(FLAGS_params).empty()) {
CHECK(google::protobuf::TextFormat::MergeFromString(
absl::GetFlag(FLAGS_params), &parameters))
<< absl::GetFlag(FLAGS_params);
}
// Initialize the solver.
@@ -208,12 +211,12 @@ int Run() {
// Read the problem.
LinearBooleanProblem problem;
CpModelProto cp_model;
if (!LoadBooleanProblem(FLAGS_input, &problem, &cp_model)) {
if (!LoadBooleanProblem(absl::GetFlag(FLAGS_input), &problem, &cp_model)) {
CpSolverResponse response;
response.set_status(CpSolverStatus::MODEL_INVALID);
return EXIT_SUCCESS;
}
if (FLAGS_use_cp_model && cp_model.variables_size() == 0) {
if (absl::GetFlag(FLAGS_use_cp_model) && cp_model.variables_size() == 0) {
LOG(INFO) << "Converting to CpModelProto ...";
cp_model = BooleanProblemToCpModelproto(problem);
}
@@ -221,28 +224,31 @@ int Run() {
// TODO(user): clean this hack. Ideally LinearBooleanProblem should be
// completely replaced by the more general CpModelProto.
if (!cp_model.variables().empty()) {
problem.Clear(); // We no longer need it, release memory.
problem.Clear(); // We no longer need it, release memory.
Model model;
model.Add(NewSatParameters(parameters));
const CpSolverResponse response = SolveCpModel(cp_model, &model);
if (!FLAGS_output.empty()) {
if (absl::EndsWith(FLAGS_output, ".txt")) {
CHECK_OK(file::SetTextProto(FLAGS_output, response, file::Defaults()));
if (!absl::GetFlag(FLAGS_output).empty()) {
if (absl::EndsWith(absl::GetFlag(FLAGS_output), ".txt")) {
CHECK_OK(file::SetTextProto(absl::GetFlag(FLAGS_output), response,
file::Defaults()));
} else {
CHECK_OK(
file::SetBinaryProto(FLAGS_output, response, file::Defaults()));
CHECK_OK(file::SetBinaryProto(absl::GetFlag(FLAGS_output), response,
file::Defaults()));
}
}
// The SAT competition requires a particular exit code and since we don't
// really use it for any other purpose, we comply.
if (response.status() == CpSolverStatus::FEASIBLE) return 10;
if (response.status() == CpSolverStatus::INFEASIBLE) return 20;
if (response.status() == CpSolverStatus::FEASIBLE)
return 10;
if (response.status() == CpSolverStatus::INFEASIBLE)
return 20;
return EXIT_SUCCESS;
}
if (FLAGS_strict_validity) {
if (absl::GetFlag(FLAGS_strict_validity)) {
const absl::Status status = ValidateBooleanProblem(problem);
if (!status.ok()) {
LOG(ERROR) << "Invalid Boolean problem: " << status.message();
@@ -260,14 +266,14 @@ int Run() {
// Probing.
SatPostsolver probing_postsolver(problem.num_variables());
LinearBooleanProblem original_problem;
if (FLAGS_probing) {
if (absl::GetFlag(FLAGS_probing)) {
// TODO(user): This is nice for testing, but consumes memory.
original_problem = problem;
ProbeAndSimplifyProblem(&probing_postsolver, &problem);
}
// Load the problem into the solver.
if (FLAGS_reduce_memory_usage) {
if (absl::GetFlag(FLAGS_reduce_memory_usage)) {
if (!LoadAndConsumeBooleanProblem(&problem, solver.get())) {
LOG(INFO) << "UNSAT when loading the problem.";
}
@@ -276,16 +282,19 @@ int Run() {
LOG(INFO) << "UNSAT when loading the problem.";
}
}
auto strtoint64 = [](const std::string& word) {
auto strtoint64 = [](const std::string & word) {
int64 value = 0;
if (!word.empty()) CHECK(absl::SimpleAtoi(word, &value));
if (!word.empty())
CHECK(absl::SimpleAtoi(word, &value));
return value;
};
if (!AddObjectiveConstraint(problem, !FLAGS_lower_bound.empty(),
Coefficient(strtoint64(FLAGS_lower_bound)),
!FLAGS_upper_bound.empty(),
Coefficient(strtoint64(FLAGS_upper_bound)),
solver.get())) {
}
;
if (!AddObjectiveConstraint(
problem, !absl::GetFlag(FLAGS_lower_bound).empty(),
Coefficient(strtoint64(absl::GetFlag(FLAGS_lower_bound))),
!absl::GetFlag(FLAGS_upper_bound).empty(),
Coefficient(strtoint64(absl::GetFlag(FLAGS_upper_bound))),
solver.get())) {
LOG(INFO) << "UNSAT when setting the objective constraint.";
}
@@ -293,11 +302,11 @@ int Run() {
//
// TODO(user): To make this compatible with presolve, we just need to run
// it after the presolve step.
if (FLAGS_use_symmetry) {
CHECK(!FLAGS_reduce_memory_usage) << "incompatible";
CHECK(!FLAGS_presolve) << "incompatible";
if (absl::GetFlag(FLAGS_use_symmetry)) {
CHECK(!absl::GetFlag(FLAGS_reduce_memory_usage)) << "incompatible";
CHECK(!absl::GetFlag(FLAGS_presolve)) << "incompatible";
LOG(INFO) << "Finding symmetries of the problem.";
std::vector<std::unique_ptr<SparsePermutation>> generators;
std::vector<std::unique_ptr<SparsePermutation> > generators;
FindLinearBooleanProblemSymmetries(problem, &generators);
std::unique_ptr<SymmetryPropagator> propagator(new SymmetryPropagator);
for (int i = 0; i < generators.size(); ++i) {
@@ -310,28 +319,31 @@ int Run() {
// Optimize?
std::vector<bool> solution;
SatSolver::Status result = SatSolver::LIMIT_REACHED;
if (FLAGS_fu_malik || FLAGS_linear_scan || FLAGS_wpm1 || FLAGS_qmaxsat ||
FLAGS_core_enc) {
if (FLAGS_randomize > 0 && (FLAGS_linear_scan || FLAGS_qmaxsat)) {
CHECK(!FLAGS_reduce_memory_usage) << "incompatible";
result = SolveWithRandomParameters(STDOUT_LOG, problem, FLAGS_randomize,
solver.get(), &solution);
if (absl::GetFlag(FLAGS_fu_malik) || absl::GetFlag(FLAGS_linear_scan) ||
absl::GetFlag(FLAGS_wpm1) || absl::GetFlag(FLAGS_qmaxsat) ||
absl::GetFlag(FLAGS_core_enc)) {
if (absl::GetFlag(FLAGS_randomize) > 0 &&
(absl::GetFlag(FLAGS_linear_scan) || absl::GetFlag(FLAGS_qmaxsat))) {
CHECK(!absl::GetFlag(FLAGS_reduce_memory_usage)) << "incompatible";
result = SolveWithRandomParameters(
STDOUT_LOG, problem, absl::GetFlag(FLAGS_randomize), solver.get(),
&solution);
}
if (result == SatSolver::LIMIT_REACHED) {
if (FLAGS_qmaxsat) {
if (absl::GetFlag(FLAGS_qmaxsat)) {
solver = absl::make_unique<SatSolver>();
solver->SetParameters(parameters);
CHECK(LoadBooleanProblem(problem, solver.get()));
result = SolveWithCardinalityEncoding(STDOUT_LOG, problem, solver.get(),
&solution);
} else if (FLAGS_core_enc) {
} else if (absl::GetFlag(FLAGS_core_enc)) {
result = SolveWithCardinalityEncodingAndCore(STDOUT_LOG, problem,
solver.get(), &solution);
} else if (FLAGS_fu_malik) {
} else if (absl::GetFlag(FLAGS_fu_malik)) {
result = SolveWithFuMalik(STDOUT_LOG, problem, solver.get(), &solution);
} else if (FLAGS_wpm1) {
} else if (absl::GetFlag(FLAGS_wpm1)) {
result = SolveWithWPM1(STDOUT_LOG, problem, solver.get(), &solution);
} else if (FLAGS_linear_scan) {
} else if (absl::GetFlag(FLAGS_linear_scan)) {
result =
SolveWithLinearScan(STDOUT_LOG, problem, solver.get(), &solution);
}
@@ -340,7 +352,7 @@ int Run() {
// Only solve the decision version.
parameters.set_log_search_progress(true);
solver->SetParameters(parameters);
if (FLAGS_presolve) {
if (absl::GetFlag(FLAGS_presolve)) {
std::unique_ptr<TimeLimit> time_limit =
TimeLimit::FromParameters(parameters);
result = SolveWithPresolve(&solver, time_limit.get(), &solution, nullptr);
@@ -358,14 +370,15 @@ int Run() {
// Print the solution status.
if (result == SatSolver::FEASIBLE) {
if (FLAGS_fu_malik || FLAGS_linear_scan || FLAGS_wpm1 || FLAGS_core_enc) {
if (absl::GetFlag(FLAGS_fu_malik) || absl::GetFlag(FLAGS_linear_scan) ||
absl::GetFlag(FLAGS_wpm1) || absl::GetFlag(FLAGS_core_enc)) {
printf("s OPTIMUM FOUND\n");
CHECK(!solution.empty());
const Coefficient objective = ComputeObjectiveValue(problem, solution);
scaled_best_bound = AddOffsetAndScaleObjectiveValue(problem, objective);
// Postsolve.
if (FLAGS_probing) {
if (absl::GetFlag(FLAGS_probing)) {
solution = probing_postsolver.PostsolveSolution(solution);
problem = original_problem;
}
@@ -375,18 +388,20 @@ int Run() {
// Check and output the solution.
CHECK(IsAssignmentValid(problem, solution));
if (FLAGS_output_cnf_solution) {
if (absl::GetFlag(FLAGS_output_cnf_solution)) {
printf("v %s\n", SolutionString(problem, solution).c_str());
}
if (!FLAGS_output.empty()) {
CHECK(!FLAGS_reduce_memory_usage) << "incompatible";
if (!absl::GetFlag(FLAGS_output).empty()) {
CHECK(!absl::GetFlag(FLAGS_reduce_memory_usage)) << "incompatible";
if (result == SatSolver::FEASIBLE) {
StoreAssignment(solver->Assignment(), problem.mutable_assignment());
}
if (absl::EndsWith(FLAGS_output, ".txt")) {
CHECK_OK(file::SetTextProto(FLAGS_output, problem, file::Defaults()));
if (absl::EndsWith(absl::GetFlag(FLAGS_output), ".txt")) {
CHECK_OK(file::SetTextProto(absl::GetFlag(FLAGS_output), problem,
file::Defaults()));
} else {
CHECK_OK(file::SetBinaryProto(FLAGS_output, problem, file::Defaults()));
CHECK_OK(file::SetBinaryProto(absl::GetFlag(FLAGS_output), problem,
file::Defaults()));
}
}
}
@@ -419,24 +434,26 @@ int Run() {
// The SAT competition requires a particular exit code and since we don't
// really use it for any other purpose, we comply.
if (result == SatSolver::FEASIBLE) return 10;
if (result == SatSolver::INFEASIBLE) return 20;
if (result == SatSolver::FEASIBLE)
return 10;
if (result == SatSolver::INFEASIBLE)
return 20;
return EXIT_SUCCESS;
}
} // namespace
} // namespace sat
} // namespace operations_research
} // namespace
} // namespace sat
} // namespace operations_research
static const char kUsage[] =
"Usage: see flags.\n"
"This program solves a given Boolean linear problem.";
int main(int argc, char** argv) {
int main(int argc, char **argv) {
// By default, we want to show how the solver progress. Note that this needs
// to be set before InitGoogle() which has the nice side-effect of allowing
// the user to override it.
// absl::SetFlag(&FLAGS_vmodule, "*cp_model*=1");
// absl::SetFlag(&absl::GetFlag(FLAGS_vmodule), "*cp_model*=1");
gflags::SetUsageMessage(kUsage);
gflags::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);

View File

@@ -45,7 +45,7 @@ DEFINE_string(params, "", "Sat parameters in text proto format.");
namespace operations_research {
namespace sat {
class ShiftMinimizationParser {
public:
public:
struct Job {
int start;
int end;
@@ -57,17 +57,15 @@ class ShiftMinimizationParser {
};
ShiftMinimizationParser()
: load_status_(NOT_STARTED),
declared_num_jobs_(0),
declared_num_workers_(0),
num_workers_read_(0) {}
: load_status_(NOT_STARTED), declared_num_jobs_(0),
declared_num_workers_(0), num_workers_read_(0) {}
const std::vector<Job>& jobs() const { return jobs_; }
const std::vector<std::vector<int>>& possible_jobs_per_worker() const {
const std::vector<Job> &jobs() const { return jobs_; }
const std::vector<std::vector<int> > &possible_jobs_per_worker() const {
return possible_jobs_per_worker_;
}
const std::vector<std::vector<Assignment>>& possible_assignments_per_job()
const {
const std::vector<std::vector<Assignment> > &
possible_assignments_per_job() const {
return possible_assignments_per_job_;
}
@@ -78,14 +76,14 @@ class ShiftMinimizationParser {
// <start> <end> // Repeated n times
// Qualifications = <k>
// c: job_1 .. job_c // repeated k times (a counter and job ids after).
bool LoadFile(const std::string& file_name) {
bool LoadFile(const std::string &file_name) {
if (load_status_ != NOT_STARTED) {
return false;
}
load_status_ = STARTED;
for (const std::string& line :
for (const std::string &line :
FileLines(file_name, FileLineIterator::REMOVE_LINEFEED |
FileLineIterator::REMOVE_INLINE_CR)) {
ProcessLine(line);
@@ -98,16 +96,21 @@ class ShiftMinimizationParser {
declared_num_workers_ == num_workers_read_;
}
private:
enum LoadStatus { NOT_STARTED, STARTED, JOBS_SEEN, WORKERS_SEEN };
private:
enum LoadStatus {
NOT_STARTED,
STARTED,
JOBS_SEEN,
WORKERS_SEEN
};
int strtoint32(const std::string& word) {
int strtoint32(const std::string &word) {
int result;
CHECK(absl::SimpleAtoi(word, &result));
return result;
}
void ProcessLine(const std::string& line) {
void ProcessLine(const std::string &line) {
if (line.empty() || line[0] == '#') {
return;
}
@@ -116,78 +119,81 @@ class ShiftMinimizationParser {
absl::StrSplit(line, absl::ByAnyChar(" :\t"), absl::SkipEmpty());
switch (load_status_) {
case NOT_STARTED: {
LOG(FATAL) << "Wrong status: NOT_STARTED";
break;
case NOT_STARTED: {
LOG(FATAL) << "Wrong status: NOT_STARTED";
break;
}
case STARTED: {
if (words.size() == 3 && words[0] == "Type") {
CHECK_EQ(1, strtoint32(words[2]));
} else if (words.size() == 3 && words[0] == "Jobs") {
declared_num_jobs_ = strtoint32(words[2]);
possible_assignments_per_job_.resize(declared_num_jobs_);
load_status_ = JOBS_SEEN;
} else {
LOG(FATAL) << "Wrong state STARTED with line " << line;
}
case STARTED: {
if (words.size() == 3 && words[0] == "Type") {
CHECK_EQ(1, strtoint32(words[2]));
} else if (words.size() == 3 && words[0] == "Jobs") {
declared_num_jobs_ = strtoint32(words[2]);
possible_assignments_per_job_.resize(declared_num_jobs_);
load_status_ = JOBS_SEEN;
} else {
LOG(FATAL) << "Wrong state STARTED with line " << line;
}
break;
break;
}
case JOBS_SEEN: {
if (words.size() == 2) {
jobs_.push_back({
strtoint32(words[0]), strtoint32(words[1])
});
} else if (words.size() == 3 && words[0] == "Qualifications") {
declared_num_workers_ = strtoint32(words[2]);
possible_jobs_per_worker_.resize(declared_num_workers_);
load_status_ = WORKERS_SEEN;
} else {
LOG(FATAL) << "Wrong state JOBS_SEEN with line " << line;
}
case JOBS_SEEN: {
if (words.size() == 2) {
jobs_.push_back({strtoint32(words[0]), strtoint32(words[1])});
} else if (words.size() == 3 && words[0] == "Qualifications") {
declared_num_workers_ = strtoint32(words[2]);
possible_jobs_per_worker_.resize(declared_num_workers_);
load_status_ = WORKERS_SEEN;
} else {
LOG(FATAL) << "Wrong state JOBS_SEEN with line " << line;
}
break;
}
case WORKERS_SEEN: {
CHECK_EQ(strtoint32(words[0]), words.size() - 1);
for (int i = 1; i < words.size(); ++i) {
const int job = strtoint32(words[i]);
const int pos = possible_jobs_per_worker_[num_workers_read_].size();
possible_jobs_per_worker_[num_workers_read_].push_back(job);
possible_assignments_per_job_[job].push_back(
{num_workers_read_, pos});
}
num_workers_read_++;
break;
break;
}
case WORKERS_SEEN: {
CHECK_EQ(strtoint32(words[0]), words.size() - 1);
for (int i = 1; i < words.size(); ++i) {
const int job = strtoint32(words[i]);
const int pos = possible_jobs_per_worker_[num_workers_read_].size();
possible_jobs_per_worker_[num_workers_read_].push_back(job);
possible_assignments_per_job_[job].push_back({
num_workers_read_, pos
});
}
num_workers_read_++;
break;
}
}
}
std::vector<Job> jobs_;
std::vector<std::vector<int>> possible_jobs_per_worker_;
std::vector<std::vector<Assignment>> possible_assignments_per_job_;
std::vector<std::vector<int> > possible_jobs_per_worker_;
std::vector<std::vector<Assignment> > possible_assignments_per_job_;
LoadStatus load_status_;
int declared_num_jobs_;
int declared_num_workers_;
int num_workers_read_;
};
bool Overlaps(const ShiftMinimizationParser::Job& j1,
const ShiftMinimizationParser::Job& j2) {
bool Overlaps(const ShiftMinimizationParser::Job &j1,
const ShiftMinimizationParser::Job &j2) {
// TODO(user): Are end date inclusive or exclusive? To check.
// For now, we assume that they are exclusive.
return !(j1.start > j2.end || j2.start > j1.end);
}
void LoadAndSolve(const std::string& file_name) {
void LoadAndSolve(const std::string &file_name) {
ShiftMinimizationParser parser;
CHECK(parser.LoadFile(file_name));
CpModelBuilder cp_model;
const int num_workers = parser.possible_jobs_per_worker().size();
const std::vector<ShiftMinimizationParser::Job>& jobs = parser.jobs();
const std::vector<ShiftMinimizationParser::Job> &jobs = parser.jobs();
const int num_jobs = jobs.size();
std::vector<BoolVar> active_workers(num_workers);
std::vector<std::vector<BoolVar>> worker_job_vars(num_workers);
std::vector<std::vector<BoolVar>> possible_workers_per_job(num_jobs);
std::vector<std::vector<BoolVar> > worker_job_vars(num_workers);
std::vector<std::vector<BoolVar> > possible_workers_per_job(num_jobs);
for (int w = 0; w < num_workers; ++w) {
// Status variables for workers, are they active or not?
@@ -195,7 +201,7 @@ void LoadAndSolve(const std::string& file_name) {
// Job-Worker variable. worker_job_vars[w][i] is true iff worker w
// performs it's ith possible job.
const std::vector<int>& possible = parser.possible_jobs_per_worker()[w];
const std::vector<int> &possible = parser.possible_jobs_per_worker()[w];
for (int p : possible) {
const BoolVar var = cp_model.NewBoolVar();
worker_job_vars[w].push_back(var);
@@ -210,14 +216,16 @@ void LoadAndSolve(const std::string& file_name) {
if (Overlaps(jobs[job1], jobs[job2])) {
const BoolVar v1 = worker_job_vars[w][i];
const BoolVar v2 = worker_job_vars[w][j];
cp_model.AddBoolOr({Not(v1), Not(v2)});
cp_model.AddBoolOr({
Not(v1), Not(v2)
});
}
}
}
// Maintain active_workers variable.
cp_model.AddBoolOr(worker_job_vars[w]).OnlyEnforceIf(active_workers[w]);
for (const BoolVar& var : worker_job_vars[w]) {
for (const BoolVar &var : worker_job_vars[w]) {
cp_model.AddImplication(var, active_workers[w]);
}
}
@@ -235,7 +243,7 @@ void LoadAndSolve(const std::string& file_name) {
// then the number of active workers on these jobs is equal to the number of
// active jobs.
std::set<int> time_points;
std::set<std::vector<int>> visited_job_lists;
std::set<std::vector<int> > visited_job_lists;
for (int j = 0; j < num_jobs; ++j) {
time_points.insert(parser.jobs()[j].start);
@@ -250,7 +258,7 @@ void LoadAndSolve(const std::string& file_name) {
// Collect all jobs that intersects with this time point.
std::vector<int> intersecting_jobs;
for (int j = 0; j < num_jobs; ++j) {
const ShiftMinimizationParser::Job& job = parser.jobs()[j];
const ShiftMinimizationParser::Job &job = parser.jobs()[j];
// Assumption: End date are inclusive.
if (t >= job.start && t <= job.end) {
intersecting_jobs.push_back(j);
@@ -258,13 +266,14 @@ void LoadAndSolve(const std::string& file_name) {
}
// Check that we have not already visited this exact set of candidate jobs.
if (gtl::ContainsKey(visited_job_lists, intersecting_jobs)) continue;
if (gtl::ContainsKey(visited_job_lists, intersecting_jobs))
continue;
visited_job_lists.insert(intersecting_jobs);
// Collect the relevant worker job vars.
std::vector<BoolVar> overlapping_worker_jobs;
for (int j : intersecting_jobs) {
for (const auto& p : parser.possible_assignments_per_job()[j]) {
for (const auto &p : parser.possible_assignments_per_job()[j]) {
const BoolVar var = worker_job_vars[p.worker_id][p.job_index];
overlapping_worker_jobs.push_back(var);
}
@@ -292,21 +301,21 @@ void LoadAndSolve(const std::string& file_name) {
// Solve.
Model model;
model.Add(NewSatParameters(FLAGS_params));
model.Add(NewSatParameters(absl::GetFlag(FLAGS_params)));
const CpSolverResponse response = SolveCpModel(cp_model.Build(), &model);
LOG(INFO) << CpSolverResponseStats(response);
}
} // namespace sat
} // namespace operations_research
} // namespace sat
} // namespace operations_research
int main(int argc, char** argv) {
absl::SetFlag(&FLAGS_logtostderr, true);
int main(int argc, char **argv) {
absl::SetFlag(&absl::GetFlag(FLAGS_logtostderr), true);
gflags::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_input.empty()) {
if (absl::GetFlag(FLAGS_input).empty()) {
LOG(FATAL) << "Please supply a data file with --input=";
}
operations_research::sat::LoadAndSolve(FLAGS_input);
operations_research::sat::LoadAndSolve(absl::GetFlag(FLAGS_input));
return EXIT_SUCCESS;
}

View File

@@ -21,35 +21,34 @@
#include "ortools/sat/cp_model.h"
#include "ortools/sat/model.h"
const std::vector<std::vector<int>> tiny = {{3, 3, 1}};
const std::vector<std::vector<int> > tiny = { { 3, 3, 1 } };
const std::vector<std::vector<int>> small = {
{3, 2, -1, 3}, {-1, -1, -1, 2}, {3, -1, -1, -1}, {3, -1, 3, 1}};
const std::vector<std::vector<int> > small = {
{ 3, 2, -1, 3 }, { -1, -1, -1, 2 }, { 3, -1, -1, -1 }, { 3, -1, 3, 1 }
};
const std::vector<std::vector<int>> medium = {
{-1, 0, -1, 1, -1, -1, 1, -1}, {-1, 3, -1, -1, 2, 3, -1, 2},
{-1, -1, 0, -1, -1, -1, -1, 0}, {-1, 3, -1, -1, 0, -1, -1, -1},
{-1, -1, -1, 3, -1, -1, 0, -1}, {1, -1, -1, -1, -1, 3, -1, -1},
{3, -1, 1, 3, -1, -1, 3, -1}, {-1, 0, -1, -1, 3, -1, 3, -1}};
const std::vector<std::vector<int> > medium = {
{ -1, 0, -1, 1, -1, -1, 1, -1 }, { -1, 3, -1, -1, 2, 3, -1, 2 },
{ -1, -1, 0, -1, -1, -1, -1, 0 }, { -1, 3, -1, -1, 0, -1, -1, -1 },
{ -1, -1, -1, 3, -1, -1, 0, -1 }, { 1, -1, -1, -1, -1, 3, -1, -1 },
{ 3, -1, 1, 3, -1, -1, 3, -1 }, { -1, 0, -1, -1, 3, -1, 3, -1 }
};
const std::vector<std::vector<int>> big = {
{3, -1, -1, -1, 2, -1, 1, -1, 1, 2},
{1, -1, 0, -1, 3, -1, 2, 0, -1, -1},
{-1, 3, -1, -1, -1, -1, -1, -1, 3, -1},
{2, 0, -1, 3, -1, 2, 3, -1, -1, -1},
{-1, -1, -1, 1, 1, 1, -1, -1, 3, 3},
{2, 3, -1, -1, 2, 2, 3, -1, -1, -1},
{-1, -1, -1, 1, 2, -1, 2, -1, 3, 3},
{-1, 2, -1, -1, -1, -1, -1, -1, 2, -1},
{-1, -1, 1, 1, -1, 2, -1, 1, -1, 3},
{3, 3, -1, 1, -1, 2, -1, -1, -1, 2}};
const std::vector<std::vector<int> > big = {
{ 3, -1, -1, -1, 2, -1, 1, -1, 1, 2 }, { 1, -1, 0, -1, 3, -1, 2, 0, -1, -1 },
{ -1, 3, -1, -1, -1, -1, -1, -1, 3, -1 },
{ 2, 0, -1, 3, -1, 2, 3, -1, -1, -1 }, { -1, -1, -1, 1, 1, 1, -1, -1, 3, 3 },
{ 2, 3, -1, -1, 2, 2, 3, -1, -1, -1 }, { -1, -1, -1, 1, 2, -1, 2, -1, 3, 3 },
{ -1, 2, -1, -1, -1, -1, -1, -1, 2, -1 },
{ -1, -1, 1, 1, -1, 2, -1, 1, -1, 3 }, { 3, 3, -1, 1, -1, 2, -1, -1, -1, 2 }
};
namespace operations_research {
namespace sat {
void PrintSolution(const std::vector<std::vector<int>> &data,
const std::vector<std::vector<bool>> &h_arcs,
const std::vector<std::vector<bool>> &v_arcs) {
void PrintSolution(const std::vector<std::vector<int> > &data,
const std::vector<std::vector<bool> > &h_arcs,
const std::vector<std::vector<bool> > &v_arcs) {
const int num_rows = data.size();
const int num_columns = data[0].size();
@@ -83,7 +82,7 @@ void PrintSolution(const std::vector<std::vector<int>> &data,
std::cout << last_line << std::endl;
}
void SlitherLink(const std::vector<std::vector<int>> &data) {
void SlitherLink(const std::vector<std::vector<int> > &data) {
const int num_rows = data.size();
const int num_columns = data[0].size();
@@ -91,23 +90,26 @@ void SlitherLink(const std::vector<std::vector<int>> &data) {
const int num_horizontal_arcs = num_columns * (num_rows + 1);
const int num_vertical_arcs = (num_rows) * (num_columns + 1);
auto undirected_horizontal_arc = [=](int x, int y) {
auto undirected_horizontal_arc = [ = ](int x, int y) {
CHECK_LT(x, num_columns);
CHECK_LT(y, num_rows + 1);
return x + (num_columns * y);
};
}
;
auto undirected_vertical_arc = [=](int x, int y) {
auto undirected_vertical_arc = [ = ](int x, int y) {
CHECK_LT(x, num_columns + 1);
CHECK_LT(y, num_rows);
return x + (num_columns + 1) * y;
};
}
;
auto node_index = [=](int x, int y) {
auto node_index = [ = ](int x, int y) {
CHECK_LT(x, num_columns + 1);
CHECK_LT(y, num_rows + 1);
return x + y * (num_columns + 1);
};
}
;
CpModelBuilder builder;
@@ -154,7 +156,8 @@ void SlitherLink(const std::vector<std::vector<int>> &data) {
for (int x = 0; x < num_columns; ++x) {
for (int y = 0; y < num_rows; ++y) {
if (data[y][x] == -1) continue;
if (data[y][x] == -1)
continue;
std::vector<BoolVar> neighbors;
const int top_arc = undirected_horizontal_arc(x, y);
neighbors.push_back(horizontal_arcs[2 * top_arc]);
@@ -175,31 +178,43 @@ void SlitherLink(const std::vector<std::vector<int>> &data) {
// Special rule on corners: value == 3 implies 2 corner arcs used.
if (data[0][0] == 3) {
const int h_arc = undirected_horizontal_arc(0, 0);
builder.AddBoolOr(
{horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]});
builder.AddBoolOr({
horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]
});
const int v_arc = undirected_vertical_arc(0, 0);
builder.AddBoolOr({vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]});
builder.AddBoolOr({
vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]
});
}
if (data[0][num_columns - 1] == 3) {
const int h_arc = undirected_horizontal_arc(num_columns - 1, 0);
builder.AddBoolOr(
{horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]});
builder.AddBoolOr({
horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]
});
const int v_arc = undirected_vertical_arc(num_columns, 0);
builder.AddBoolOr({vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]});
builder.AddBoolOr({
vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]
});
}
if (data[num_rows - 1][0] == 3) {
const int h_arc = undirected_horizontal_arc(0, num_rows);
builder.AddBoolOr(
{horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]});
builder.AddBoolOr({
horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]
});
const int v_arc = undirected_vertical_arc(0, num_rows - 1);
builder.AddBoolOr({vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]});
builder.AddBoolOr({
vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]
});
}
if (data[num_rows - 1][num_columns - 1] == 3) {
const int h_arc = undirected_horizontal_arc(num_columns - 1, num_rows);
builder.AddBoolOr(
{horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]});
builder.AddBoolOr({
horizontal_arcs[2 * h_arc], horizontal_arcs[2 * h_arc + 1]
});
const int v_arc = undirected_vertical_arc(num_columns, num_rows - 1);
builder.AddBoolOr({vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]});
builder.AddBoolOr({
vertical_arcs[2 * v_arc], vertical_arcs[2 * v_arc + 1]
});
}
// Topology rule: Border arcs are oriented in one direction.
@@ -219,7 +234,7 @@ void SlitherLink(const std::vector<std::vector<int>> &data) {
const CpSolverResponse response = Solve(builder.Build());
std::vector<std::vector<bool>> h_arcs(num_rows + 1);
std::vector<std::vector<bool> > h_arcs(num_rows + 1);
for (int y = 0; y < num_rows + 1; ++y) {
for (int x = 0; x < num_columns; ++x) {
const int arc = undirected_horizontal_arc(x, y);
@@ -229,7 +244,7 @@ void SlitherLink(const std::vector<std::vector<int>> &data) {
}
}
std::vector<std::vector<bool>> v_arcs(num_columns + 1);
std::vector<std::vector<bool> > v_arcs(num_columns + 1);
for (int y = 0; y < num_rows; ++y) {
for (int x = 0; x < num_columns + 1; ++x) {
const int arc = undirected_vertical_arc(x, y);
@@ -243,8 +258,8 @@ void SlitherLink(const std::vector<std::vector<int>> &data) {
LOG(INFO) << CpSolverResponseStats(response);
}
} // namespace sat
} // namespace operations_research
} // namespace sat
} // namespace operations_research
int main() {
std::cout << "Tiny problem" << std::endl;

View File

@@ -63,7 +63,7 @@ DEFINE_string(dump_model, "", "If non-empty, dumps MPModelProto there.");
DEFINE_string(dump_request, "", "If non-empty, dumps MPModelRequest there.");
DEFINE_string(dump_response, "", "If non-empty, dumps MPModelResponse there.");
DECLARE_bool(verify_solution); // Defined in ./linear_solver.cc
DECLARE_bool(verify_solution); // Defined in ./linear_solver.cc
static const char kUsageStr[] =
"Run MPSolver on the given input file. Many formats are supported: \n"
@@ -81,26 +81,28 @@ namespace {
bool Run() {
// Create the solver and set its parameters.
MPSolver::OptimizationProblemType type;
CHECK(MPSolver::ParseSolverType(FLAGS_solver, &type))
<< "Unsupported --solver: " << FLAGS_solver;
CHECK(MPSolver::ParseSolverType(absl::GetFlag(FLAGS_solver), &type))
<< "Unsupported --solver: " << absl::GetFlag(FLAGS_solver);
// Load the problem into an MPModelProto.
MPModelProto model_proto;
MPModelRequest request_proto;
if (absl::EndsWith(FLAGS_input, ".mps") ||
absl::EndsWith(FLAGS_input, ".mps.gz")) {
CHECK_OK(glop::MPSReader().ParseFile(FLAGS_input, &model_proto))
<< "Error while parsing the mps file '" << FLAGS_input << "'.";
if (absl::EndsWith(absl::GetFlag(FLAGS_input), ".mps") ||
absl::EndsWith(absl::GetFlag(FLAGS_input), ".mps.gz")) {
CHECK_OK(
glop::MPSReader().ParseFile(absl::GetFlag(FLAGS_input), &model_proto))
<< "Error while parsing the mps file '" << absl::GetFlag(FLAGS_input)
<< "'.";
} else {
ReadFileToProto(FLAGS_input, &model_proto);
ReadFileToProto(FLAGS_input, &request_proto);
ReadFileToProto(absl::GetFlag(FLAGS_input), &model_proto);
ReadFileToProto(absl::GetFlag(FLAGS_input), &request_proto);
// If the input proto is in binary format, both ReadFileToProto could return
// true. Instead use the actual number of variables found to test the
// correct format of the input.
const bool is_model_proto = model_proto.variable_size() > 0;
const bool is_request_proto = request_proto.model().variable_size() > 0;
if (!is_model_proto && !is_request_proto) {
LOG(FATAL) << "Failed to parse '" << FLAGS_input
LOG(FATAL) << "Failed to parse '" << absl::GetFlag(FLAGS_input)
<< "' as an MPModelProto or an MPModelRequest.";
} else {
CHECK(!(is_model_proto && is_request_proto));
@@ -112,54 +114,55 @@ bool Run() {
}
}
}
printf("%-12s: '%s'\n", "File", FLAGS_input.c_str());
printf("%-12s: '%s'\n", "File", absl::GetFlag(FLAGS_input).c_str());
// Detect format to dump protos.
operations_research::ProtoWriteFormat write_format;
if (FLAGS_dump_format == "text") {
if (absl::GetFlag(FLAGS_dump_format) == "text") {
write_format = ProtoWriteFormat::kProtoText;
} else if (FLAGS_dump_format == "binary") {
} else if (absl::GetFlag(FLAGS_dump_format) == "binary") {
write_format = ProtoWriteFormat::kProtoBinary;
} else if (FLAGS_dump_format == "json") {
} else if (absl::GetFlag(FLAGS_dump_format) == "json") {
write_format = ProtoWriteFormat::kJson;
} else {
LOG(FATAL) << "Unsupported --dump_format: " << FLAGS_dump_format;
LOG(FATAL)
<< "Unsupported --dump_format: " << absl::GetFlag(FLAGS_dump_format);
}
// Create the solver, we use the name of the model as the solver name.
MPSolver solver(model_proto.name(), type);
const absl::Status set_num_threads_status =
solver.SetNumThreads(FLAGS_num_threads);
solver.SetNumThreads(absl::GetFlag(FLAGS_num_threads));
if (set_num_threads_status.ok()) {
LOG(INFO) << "Set number of threads to " << FLAGS_num_threads << ".";
LOG(INFO) << "Set number of threads to " << absl::GetFlag(FLAGS_num_threads)
<< ".";
} else {
LOG(ERROR) << "Failed to set number of threads due to: "
<< set_num_threads_status.message() << ". Using 1 as default.";
}
solver.EnableOutput();
if (!FLAGS_params_file.empty()) {
if (!absl::GetFlag(FLAGS_params_file).empty()) {
std::string file_contents;
CHECK_OK(
file::GetContents(FLAGS_params_file, &file_contents, file::Defaults()))
CHECK_OK(file::GetContents(absl::GetFlag(FLAGS_params_file), &file_contents,
file::Defaults()))
<< "Could not read parameters file.";
CHECK(solver.SetSolverSpecificParametersAsString(file_contents));
} else if (!FLAGS_params.empty()) {
CHECK(solver.SetSolverSpecificParametersAsString(FLAGS_params))
<< "Wrong --params format.";
} else if (!absl::GetFlag(FLAGS_params).empty()) {
CHECK(solver.SetSolverSpecificParametersAsString(
absl::GetFlag(FLAGS_params))) << "Wrong --params format.";
}
absl::PrintF(
"%-12s: %s\n", "Solver",
MPModelRequest::SolverType_Name(
static_cast<MPModelRequest::SolverType>(solver.ProblemType()))
.c_str());
MPModelRequest::SolverType_Name(static_cast<MPModelRequest::SolverType>(
solver.ProblemType())).c_str());
// Load the proto into the solver.
std::string error_message;
// If requested, save the model to file.
if (!FLAGS_dump_model.empty()) {
CHECK(WriteProtoToFile(FLAGS_dump_model, model_proto, write_format,
FLAGS_dump_gzip));
if (!absl::GetFlag(FLAGS_dump_model).empty()) {
CHECK(WriteProtoToFile(absl::GetFlag(FLAGS_dump_model), model_proto,
write_format, absl::GetFlag(FLAGS_dump_gzip)));
}
const MPSolverResponseStatus status =
@@ -170,8 +173,8 @@ bool Run() {
static_cast<int64>(1000.0 * request_proto.solver_time_limit_seconds()));
}
// Note, the underlying MPSolver treats time limit equal to 0 as no limit.
if (FLAGS_time_limit_ms >= 0) {
solver.set_time_limit(FLAGS_time_limit_ms);
if (absl::GetFlag(FLAGS_time_limit_ms) >= 0) {
solver.set_time_limit(absl::GetFlag(FLAGS_time_limit_ms));
}
if (status != MPSOLVER_MODEL_IS_VALID) {
LOG(ERROR) << MPSolverResponseStatus_Name(status) << ": " << error_message;
@@ -189,7 +192,7 @@ bool Run() {
solving_time = absl::Now() - time_before;
// If requested, re-create a corresponding MPModelRequest and save it to file.
if (!FLAGS_dump_request.empty()) {
if (!absl::GetFlag(FLAGS_dump_request).empty()) {
operations_research::MPModelRequest request;
request.set_solver_type(
static_cast<MPModelRequest::SolverType>(solver.ProblemType()));
@@ -197,21 +200,21 @@ bool Run() {
request.set_solver_specific_parameters(
solver.GetSolverSpecificParametersAsString());
*request.mutable_model() = model_proto;
CHECK(WriteProtoToFile(FLAGS_dump_request, request, write_format,
FLAGS_dump_gzip));
CHECK(WriteProtoToFile(absl::GetFlag(FLAGS_dump_request), request,
write_format, absl::GetFlag(FLAGS_dump_gzip)));
}
const bool has_solution =
solve_status == MPSolver::OPTIMAL || solve_status == MPSolver::FEASIBLE;
// If requested, get the MPModelResponse and save it to file.
if (!FLAGS_dump_response.empty() && has_solution) {
if (!absl::GetFlag(FLAGS_dump_response).empty() && has_solution) {
operations_research::MPSolutionResponse response;
solver.FillSolutionResponseProto(&response);
CHECK(WriteProtoToFile(FLAGS_dump_response, response, write_format,
FLAGS_dump_gzip));
CHECK(WriteProtoToFile(absl::GetFlag(FLAGS_dump_response), response,
write_format, absl::GetFlag(FLAGS_dump_gzip)));
}
if (!FLAGS_output_csv.empty() && has_solution) {
if (!absl::GetFlag(FLAGS_output_csv).empty() && has_solution) {
operations_research::MPSolutionResponse result;
solver.FillSolutionResponseProto(&result);
std::string csv_file;
@@ -219,21 +222,21 @@ bool Run() {
csv_file += absl::StrFormat("%s,%e\n", model_proto.variable(i).name(),
result.variable_value(i));
}
CHECK_OK(file::SetContents(FLAGS_output_csv, csv_file, file::Defaults()));
CHECK_OK(file::SetContents(absl::GetFlag(FLAGS_output_csv), csv_file,
file::Defaults()));
}
// If --verify_solution is true, we already verified it. If not, we add
// a verification step here.
if (has_solution && !FLAGS_verify_solution) {
if (has_solution && !absl::GetFlag(FLAGS_verify_solution)) {
LOG(INFO) << "Verifying the solution";
solver.VerifySolution(/*tolerance=*/param.GetDoubleParam(
solver.VerifySolution(/*tolerance=*/ param.GetDoubleParam(
MPSolverParameters::PRIMAL_TOLERANCE),
/*log_errors=*/true);
/*log_errors=*/ true);
}
absl::PrintF("%-12s: %s\n", "Status",
MPSolverResponseStatus_Name(
static_cast<MPSolverResponseStatus>(solve_status))
.c_str());
static_cast<MPSolverResponseStatus>(solve_status)).c_str());
absl::PrintF("%-12s: %15.15e\n", "Objective",
has_solution ? solver.Objective().Value() : 0.0);
absl::PrintF("%-12s: %15.15e\n", "BestBound",
@@ -247,13 +250,13 @@ bool Run() {
return true;
}
} // namespace
} // namespace operations_research
} // namespace
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
google::InitGoogleLogging(argv[0]);
gflags::ParseCommandLineFlags(&argc, &argv, /*remove_flags=*/true);
CHECK(!FLAGS_input.empty()) << "--input is required";
gflags::ParseCommandLineFlags(&argc, &argv, /*remove_flags=*/ true);
CHECK(!absl::GetFlag(FLAGS_input).empty()) << "--input is required";
operations_research::Run();
return EXIT_SUCCESS;

View File

@@ -61,21 +61,20 @@ void FirstModel(int num_teams) {
CpModelBuilder builder;
// Calendar variables.
std::vector<std::vector<IntVar>> opponents(num_teams);
std::vector<std::vector<BoolVar>> home_aways(num_teams);
std::vector<std::vector<IntVar>> signed_opponents(num_teams);
std::vector<std::vector<IntVar> > opponents(num_teams);
std::vector<std::vector<BoolVar> > home_aways(num_teams);
std::vector<std::vector<IntVar> > signed_opponents(num_teams);
for (int t = 0; t < num_teams; ++t) {
for (int d = 0; d < num_days; ++d) {
Domain opponent_domain(0, num_teams - 1);
Domain signed_opponent_domain(0, 2 * num_teams - 1);
IntVar opp = builder.NewIntVar(opponent_domain)
.WithName(absl::StrCat("opponent_", t, "_", d));
.WithName(absl::StrCat("opponent_", t, "_", d));
BoolVar home =
builder.NewBoolVar().WithName(absl::StrCat("home_aways", t, "_", d));
IntVar signed_opp =
builder.NewIntVar(signed_opponent_domain)
.WithName(absl::StrCat("signed_opponent_", t, "_", d));
IntVar signed_opp = builder.NewIntVar(signed_opponent_domain)
.WithName(absl::StrCat("signed_opponent_", t, "_", d));
opponents[t].push_back(opp);
home_aways[t].push_back(home);
@@ -109,7 +108,10 @@ void FirstModel(int num_teams) {
IntVar second_home = builder.NewBoolVar();
builder.AddVariableElement(day_opponents[first_team], day_home_aways,
second_home);
builder.AddEquality(LinearExpr::Sum({first_home, second_home}), 1);
builder.AddEquality(LinearExpr::Sum({
first_home, second_home
}),
1);
}
builder.AddEquality(LinearExpr::Sum(day_home_aways), num_teams / 2);
@@ -136,11 +138,13 @@ void FirstModel(int num_teams) {
// Forbid sequence of 3 homes or 3 aways.
for (int start = 0; start < num_days - 2; ++start) {
builder.AddBoolOr({home_aways[t][start], home_aways[t][start + 1],
home_aways[t][start + 2]});
builder.AddBoolOr({Not(home_aways[t][start]),
Not(home_aways[t][start + 1]),
Not(home_aways[t][start + 2])});
builder.AddBoolOr({
home_aways[t][start], home_aways[t][start + 1], home_aways[t][start + 2]
});
builder.AddBoolOr({
Not(home_aways[t][start]), Not(home_aways[t][start + 1]),
Not(home_aways[t][start + 2])
});
}
}
@@ -150,9 +154,12 @@ void FirstModel(int num_teams) {
for (int d = 0; d < num_days - 1; ++d) {
BoolVar break_var =
builder.NewBoolVar().WithName(absl::StrCat("break_", t, "_", d));
builder.AddBoolOr(
{Not(home_aways[t][d]), Not(home_aways[t][d + 1]), break_var});
builder.AddBoolOr({home_aways[t][d], home_aways[t][d + 1], break_var});
builder.AddBoolOr({
Not(home_aways[t][d]), Not(home_aways[t][d + 1]), break_var
});
builder.AddBoolOr({
home_aways[t][d], home_aways[t][d + 1], break_var
});
breaks.push_back(break_var);
}
}
@@ -160,8 +167,8 @@ void FirstModel(int num_teams) {
builder.Minimize(LinearExpr::BooleanSum(breaks));
Model model;
if (!FLAGS_params.empty()) {
model.Add(NewSatParameters(FLAGS_params));
if (!absl::GetFlag(FLAGS_params).empty()) {
model.Add(NewSatParameters(absl::GetFlag(FLAGS_params)));
}
const CpSolverResponse response = SolveCpModel(builder.Build(), &model);
@@ -193,7 +200,7 @@ void SecondModel(int num_teams) {
CpModelBuilder builder;
// Does team i receive team j at home on day d?
std::vector<std::vector<std::vector<BoolVar>>> fixtures(num_days);
std::vector<std::vector<std::vector<BoolVar> > > fixtures(num_days);
for (int d = 0; d < num_days; ++d) {
fixtures[d].resize(num_teams);
for (int i = 0; i < num_teams; ++i) {
@@ -209,7 +216,7 @@ void SecondModel(int num_teams) {
}
// Is team t at home on day d?
std::vector<std::vector<BoolVar>> at_home(num_days);
std::vector<std::vector<BoolVar> > at_home(num_days);
for (int d = 0; d < num_days; ++d) {
for (int t = 0; t < num_teams; ++t) {
at_home[d].push_back(builder.NewBoolVar());
@@ -221,7 +228,8 @@ void SecondModel(int num_teams) {
for (int team = 0; team < num_teams; ++team) {
std::vector<BoolVar> possible_opponents;
for (int other = 0; other < num_teams; ++other) {
if (team == other) continue;
if (team == other)
continue;
possible_opponents.push_back(fixtures[d][team][other]);
possible_opponents.push_back(fixtures[d][other][team]);
}
@@ -232,7 +240,8 @@ void SecondModel(int num_teams) {
// Each fixture happens once per season.
for (int team = 0; team < num_teams; ++team) {
for (int other = 0; other < num_teams; ++other) {
if (team == other) continue;
if (team == other)
continue;
std::vector<BoolVar> possible_days;
for (int d = 0; d < num_days; ++d) {
possible_days.push_back(fixtures[d][team][other]);
@@ -244,7 +253,8 @@ void SecondModel(int num_teams) {
// Meet each opponent once per season.
for (int team = 0; team < num_teams; ++team) {
for (int other = 0; other < num_teams; ++other) {
if (team == other) continue;
if (team == other)
continue;
std::vector<BoolVar> first_half;
std::vector<BoolVar> second_half;
for (int d = 0; d < matches_per_day; ++d) {
@@ -262,7 +272,8 @@ void SecondModel(int num_teams) {
for (int d = 0; d < num_days; ++d) {
for (int team = 0; team < num_teams; ++team) {
for (int other = 0; other < num_teams; ++other) {
if (team == other) continue;
if (team == other)
continue;
builder.AddImplication(fixtures[d][team][other], at_home[d][team]);
builder.AddImplication(fixtures[d][team][other],
Not(at_home[d][other]));
@@ -273,10 +284,13 @@ void SecondModel(int num_teams) {
// Forbid sequence of 3 homes or 3 aways.
for (int team = 0; team < num_teams; ++team) {
for (int d = 0; d < num_days - 2; ++d) {
builder.AddBoolOr(
{at_home[d][team], at_home[d + 1][team], at_home[d + 2][team]});
builder.AddBoolOr({Not(at_home[d][team]), Not(at_home[d + 1][team]),
Not(at_home[d + 2][team])});
builder.AddBoolOr({
at_home[d][team], at_home[d + 1][team], at_home[d + 2][team]
});
builder.AddBoolOr({
Not(at_home[d][team]), Not(at_home[d + 1][team]),
Not(at_home[d + 2][team])
});
}
}
@@ -285,13 +299,18 @@ void SecondModel(int num_teams) {
for (int t = 0; t < num_teams; ++t) {
for (int d = 0; d < num_days - 1; ++d) {
BoolVar break_var = builder.NewBoolVar();
builder.AddBoolOr(
{Not(at_home[d][t]), Not(at_home[d + 1][t]), break_var});
builder.AddBoolOr({at_home[d][t], at_home[d + 1][t], break_var});
builder.AddBoolOr(
{Not(at_home[d][t]), at_home[d + 1][t], Not(break_var)});
builder.AddBoolOr(
{at_home[d][t], Not(at_home[d + 1][t]), Not(break_var)});
builder.AddBoolOr({
Not(at_home[d][t]), Not(at_home[d + 1][t]), break_var
});
builder.AddBoolOr({
at_home[d][t], at_home[d + 1][t], break_var
});
builder.AddBoolOr({
Not(at_home[d][t]), at_home[d + 1][t], Not(break_var)
});
builder.AddBoolOr({
at_home[d][t], Not(at_home[d + 1][t]), Not(break_var)
});
breaks.push_back(break_var);
}
}
@@ -301,16 +320,16 @@ void SecondModel(int num_teams) {
builder.Minimize(LinearExpr::BooleanSum(breaks));
Model model;
if (!FLAGS_params.empty()) {
model.Add(NewSatParameters(FLAGS_params));
if (!absl::GetFlag(FLAGS_params).empty()) {
model.Add(NewSatParameters(absl::GetFlag(FLAGS_params)));
}
const CpSolverResponse response = SolveCpModel(builder.Build(), &model);
LOG(INFO) << CpSolverResponseStats(response);
}
} // namespace sat
} // namespace operations_research
} // namespace sat
} // namespace operations_research
static const char kUsage[] =
"Usage: see flags.\nThis program runs a sports scheduling problem."
@@ -319,8 +338,9 @@ static const char kUsage[] =
int main(int argc, char **argv) {
gflags::SetUsageMessage(kUsage);
gflags::ParseCommandLineFlags(&argc, &argv, true);
CHECK_EQ(0, FLAGS_num_teams % 2) << "The number of teams must be even";
CHECK_GE(FLAGS_num_teams, 2) << "At least 2 teams";
operations_research::sat::SecondModel(FLAGS_num_teams);
CHECK_EQ(0, absl::GetFlag(FLAGS_num_teams) % 2)
<< "The number of teams must be even";
CHECK_GE(absl::GetFlag(FLAGS_num_teams), 2) << "At least 2 teams";
operations_research::sat::SecondModel(absl::GetFlag(FLAGS_num_teams));
return EXIT_SUCCESS;
}

View File

@@ -17,16 +17,13 @@
namespace operations_research {
void RunStiglerDietExample() {
// Nutrient minimums.
std::vector<std::pair<std::string, double>> nutrients = {
{"Calories (kcal)", 3.0},
{"Protein (g)", 70.0},
{"Calcium (g)", 0.8},
{"Iron (mg)", 12.0},
{"Vitamin A (kIU)", 5.0},
{"Thiamine (Vitamin B1) (mg)", 1.8},
{"Riboflavin (Vitamin B2) (mg)", 2.7},
{"Niacin (mg)", 18.0},
{"Ascorbic Acid (Vitamin C) (mg)", 75.0}};
std::vector<std::pair<std::string, double> > nutrients = {
{ "Calories (kcal)", 3.0 }, { "Protein (g)", 70.0 }, { "Calcium (g)", 0.8 },
{ "Iron (mg)", 12.0 }, { "Vitamin A (kIU)", 5.0 },
{ "Thiamine (Vitamin B1) (mg)", 1.8 },
{ "Riboflavin (Vitamin B2) (mg)", 2.7 }, { "Niacin (mg)", 18.0 },
{ "Ascorbic Acid (Vitamin C) (mg)", 75.0 }
};
struct Commodity {
// Commodity name
@@ -48,200 +45,146 @@ void RunStiglerDietExample() {
};
std::vector<Commodity> data = {
{"Wheat Flour (Enriched)",
"10 lb.",
36,
{44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0}},
{"Macaroni", "1 lb.", 14.1, {11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0}},
{"Wheat Cereal (Enriched)",
"28 oz.",
24.2,
{11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0}},
{"Corn Flakes", "8 oz.", 7.1, {11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0}},
{"Corn Meal",
"1 lb.",
4.6,
{36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0}},
{"Hominy Grits",
"24 oz.",
8.5,
{28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0}},
{"Rice", "1 lb.", 7.5, {21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0}},
{"Rolled Oats", "1 lb.", 7.1, {25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0}},
{"White Bread (Enriched)",
"1 lb.",
7.9,
{15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0}},
{"Whole Wheat Bread",
"1 lb.",
9.1,
{12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0}},
{"Rye Bread", "1 lb.", 9.1, {12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0}},
{"Pound Cake", "1 lb.", 24.8, {8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0}},
{"Soda Crackers", "1 lb.", 15.1, {12.5, 288, 0.5, 50, 0, 0, 0, 0, 0}},
{"Milk", "1 qt.", 11, {6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177}},
{"Evaporated Milk (can)",
"14.5 oz.",
6.7,
{8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60}},
{"Butter", "1 lb.", 30.8, {10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0}},
{"Oleomargarine", "1 lb.", 16.1, {20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0}},
{"Eggs", "1 doz.", 32.6, {2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0}},
{"Cheese (Cheddar)",
"1 lb.",
24.2,
{7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0}},
{"Cream", "1/2 pt.", 14.1, {3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17}},
{"Peanut Butter",
"1 lb.",
17.9,
{15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0}},
{"Mayonnaise", "1/2 pt.", 16.7, {8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0}},
{"Crisco", "1 lb.", 20.3, {20.1, 0, 0, 0, 0, 0, 0, 0, 0}},
{"Lard", "1 lb.", 9.8, {41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0}},
{"Sirloin Steak",
"1 lb.",
39.6,
{2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0}},
{"Round Steak", "1 lb.", 36.4, {2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0}},
{"Rib Roast", "1 lb.", 29.2, {3.4, 213, 0.1, 33, 0, 0, 2, 0, 0}},
{"Chuck Roast", "1 lb.", 22.6, {3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0}},
{"Plate", "1 lb.", 14.6, {8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0}},
{"Liver (Beef)",
"1 lb.",
26.8,
{2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525}},
{"Leg of Lamb", "1 lb.", 27.6, {3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0}},
{"Lamb Chops (Rib)",
"1 lb.",
36.6,
{3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0}},
{"Pork Chops", "1 lb.", 30.7, {3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0}},
{"Pork Loin Roast",
"1 lb.",
24.2,
{4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0}},
{"Bacon", "1 lb.", 25.6, {10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0}},
{"Ham, smoked", "1 lb.", 27.4, {6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0}},
{"Salt Pork", "1 lb.", 16, {18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0}},
{"Roasting Chicken",
"1 lb.",
30.3,
{1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46}},
{"Veal Cutlets", "1 lb.", 42.3, {1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0}},
{"Salmon, Pink (can)",
"16 oz.",
13,
{5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0}},
{"Apples", "1 lb.", 4.4, {5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544}},
{"Bananas", "1 lb.", 6.1, {4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498}},
{"Lemons", "1 doz.", 26, {1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952}},
{"Oranges", "1 doz.", 30.9, {2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998}},
{"Green Beans", "1 lb.", 7.1, {2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862}},
{"Cabbage", "1 lb.", 3.7, {2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369}},
{"Carrots", "1 bunch", 4.7, {2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608}},
{"Celery", "1 stalk", 7.3, {0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313}},
{"Lettuce", "1 head", 8.2, {0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449}},
{"Onions", "1 lb.", 3.6, {5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184}},
{"Potatoes",
"15 lb.",
34,
{14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522}},
{"Spinach", "1 lb.", 8.1, {1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755}},
{"Sweet Potatoes",
"1 lb.",
5.1,
{9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912}},
{"Peaches (can)",
"No. 2 1/2",
16.8,
{3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196}},
{"Pears (can)",
"No. 2 1/2",
20.4,
{3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81}},
{"Pineapple (can)",
"No. 2 1/2",
21.3,
{2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399}},
{"Asparagus (can)",
"No. 2",
27.7,
{0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272}},
{"Green Beans (can)",
"No. 2",
10,
{1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431}},
{"Pork and Beans (can)",
"16 oz.",
7.1,
{7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0}},
{"Corn (can)", "No. 2", 10.4, {5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218}},
{"Peas (can)",
"No. 2",
13.8,
{2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370}},
{"Tomatoes (can)",
"No. 2",
8.6,
{1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253}},
{"Tomato Soup (can)",
"10 1/2 oz.",
7.6,
{1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862}},
{"Peaches, Dried",
"1 lb.",
15.7,
{8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57}},
{"Prunes, Dried",
"1 lb.",
9,
{12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257}},
{"Raisins, Dried",
"15 oz.",
9.4,
{13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136}},
{"Peas, Dried",
"1 lb.",
7.9,
{20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0}},
{"Lima Beans, Dried",
"1 lb.",
8.9,
{17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0}},
{"Navy Beans, Dried",
"1 lb.",
5.9,
{26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0}},
{"Coffee", "1 lb.", 22.4, {0, 0, 0, 0, 0, 4, 5.1, 50, 0}},
{"Tea", "1/4 lb.", 17.4, {0, 0, 0, 0, 0, 0, 2.3, 42, 0}},
{"Cocoa", "8 oz.", 8.6, {8.7, 237, 3, 72, 0, 2, 11.9, 40, 0}},
{"Chocolate", "8 oz.", 16.2, {8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0}},
{"Sugar", "10 lb.", 51.7, {34.9, 0, 0, 0, 0, 0, 0, 0, 0}},
{"Corn Syrup", "24 oz.", 13.7, {14.7, 0, 0.5, 74, 0, 0, 0, 5, 0}},
{"Molasses", "18 oz.", 13.6, {9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0}},
{"Strawberry Preserves",
"1 lb.",
20.5,
{6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0}}};
{ "Wheat Flour (Enriched)", "10 lb.", 36,
{ 44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0 } },
{ "Macaroni", "1 lb.", 14.1, { 11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0 } },
{ "Wheat Cereal (Enriched)", "28 oz.", 24.2,
{ 11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0 } },
{ "Corn Flakes", "8 oz.", 7.1,
{ 11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0 } },
{ "Corn Meal", "1 lb.", 4.6,
{ 36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0 } },
{ "Hominy Grits", "24 oz.", 8.5,
{ 28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0 } },
{ "Rice", "1 lb.", 7.5, { 21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0 } },
{ "Rolled Oats", "1 lb.", 7.1,
{ 25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0 } },
{ "White Bread (Enriched)", "1 lb.", 7.9,
{ 15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0 } },
{ "Whole Wheat Bread", "1 lb.", 9.1,
{ 12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0 } },
{ "Rye Bread", "1 lb.", 9.1, { 12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0 } },
{ "Pound Cake", "1 lb.", 24.8, { 8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0 } },
{ "Soda Crackers", "1 lb.", 15.1, { 12.5, 288, 0.5, 50, 0, 0, 0, 0, 0 } },
{ "Milk", "1 qt.", 11, { 6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177 } },
{ "Evaporated Milk (can)", "14.5 oz.", 6.7,
{ 8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60 } },
{ "Butter", "1 lb.", 30.8, { 10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0 } },
{ "Oleomargarine", "1 lb.", 16.1,
{ 20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0 } },
{ "Eggs", "1 doz.", 32.6, { 2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0 } },
{ "Cheese (Cheddar)", "1 lb.", 24.2,
{ 7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0 } },
{ "Cream", "1/2 pt.", 14.1, { 3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17 } },
{ "Peanut Butter", "1 lb.", 17.9,
{ 15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0 } },
{ "Mayonnaise", "1/2 pt.", 16.7, { 8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0 } },
{ "Crisco", "1 lb.", 20.3, { 20.1, 0, 0, 0, 0, 0, 0, 0, 0 } },
{ "Lard", "1 lb.", 9.8, { 41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0 } },
{ "Sirloin Steak", "1 lb.", 39.6,
{ 2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0 } },
{ "Round Steak", "1 lb.", 36.4,
{ 2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0 } },
{ "Rib Roast", "1 lb.", 29.2, { 3.4, 213, 0.1, 33, 0, 0, 2, 0, 0 } },
{ "Chuck Roast", "1 lb.", 22.6, { 3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0 } },
{ "Plate", "1 lb.", 14.6, { 8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0 } },
{ "Liver (Beef)", "1 lb.", 26.8,
{ 2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525 } },
{ "Leg of Lamb", "1 lb.", 27.6, { 3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0 } },
{ "Lamb Chops (Rib)", "1 lb.", 36.6,
{ 3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0 } },
{ "Pork Chops", "1 lb.", 30.7, { 3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0 } },
{ "Pork Loin Roast", "1 lb.", 24.2,
{ 4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0 } },
{ "Bacon", "1 lb.", 25.6, { 10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0 } },
{ "Ham, smoked", "1 lb.", 27.4, { 6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0 } },
{ "Salt Pork", "1 lb.", 16, { 18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0 } },
{ "Roasting Chicken", "1 lb.", 30.3,
{ 1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46 } },
{ "Veal Cutlets", "1 lb.", 42.3,
{ 1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0 } },
{ "Salmon, Pink (can)", "16 oz.", 13,
{ 5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0 } },
{ "Apples", "1 lb.", 4.4, { 5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544 } },
{ "Bananas", "1 lb.", 6.1, { 4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498 } },
{ "Lemons", "1 doz.", 26, { 1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952 } },
{ "Oranges", "1 doz.", 30.9,
{ 2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998 } },
{ "Green Beans", "1 lb.", 7.1,
{ 2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862 } },
{ "Cabbage", "1 lb.", 3.7, { 2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369 } },
{ "Carrots", "1 bunch", 4.7,
{ 2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608 } },
{ "Celery", "1 stalk", 7.3, { 0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313 } },
{ "Lettuce", "1 head", 8.2,
{ 0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449 } },
{ "Onions", "1 lb.", 3.6, { 5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184 } },
{ "Potatoes", "15 lb.", 34,
{ 14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522 } },
{ "Spinach", "1 lb.", 8.1,
{ 1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755 } },
{ "Sweet Potatoes", "1 lb.", 5.1,
{ 9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912 } },
{ "Peaches (can)", "No. 2 1/2", 16.8,
{ 3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196 } },
{ "Pears (can)", "No. 2 1/2", 20.4,
{ 3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81 } },
{ "Pineapple (can)", "No. 2 1/2", 21.3,
{ 2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399 } },
{ "Asparagus (can)", "No. 2", 27.7,
{ 0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272 } },
{ "Green Beans (can)", "No. 2", 10,
{ 1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431 } },
{ "Pork and Beans (can)", "16 oz.", 7.1,
{ 7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0 } },
{ "Corn (can)", "No. 2", 10.4,
{ 5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218 } },
{ "Peas (can)", "No. 2", 13.8,
{ 2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370 } },
{ "Tomatoes (can)", "No. 2", 8.6,
{ 1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253 } },
{ "Tomato Soup (can)", "10 1/2 oz.", 7.6,
{ 1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862 } },
{ "Peaches, Dried", "1 lb.", 15.7,
{ 8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57 } },
{ "Prunes, Dried", "1 lb.", 9,
{ 12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257 } },
{ "Raisins, Dried", "15 oz.", 9.4,
{ 13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136 } },
{ "Peas, Dried", "1 lb.", 7.9,
{ 20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0 } },
{ "Lima Beans, Dried", "1 lb.", 8.9,
{ 17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0 } },
{ "Navy Beans, Dried", "1 lb.", 5.9,
{ 26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0 } },
{ "Coffee", "1 lb.", 22.4, { 0, 0, 0, 0, 0, 4, 5.1, 50, 0 } },
{ "Tea", "1/4 lb.", 17.4, { 0, 0, 0, 0, 0, 0, 2.3, 42, 0 } },
{ "Cocoa", "8 oz.", 8.6, { 8.7, 237, 3, 72, 0, 2, 11.9, 40, 0 } },
{ "Chocolate", "8 oz.", 16.2, { 8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0 } },
{ "Sugar", "10 lb.", 51.7, { 34.9, 0, 0, 0, 0, 0, 0, 0, 0 } },
{ "Corn Syrup", "24 oz.", 13.7, { 14.7, 0, 0.5, 74, 0, 0, 0, 5, 0 } },
{ "Molasses", "18 oz.", 13.6, { 9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0 } },
{ "Strawberry Preserves", "1 lb.", 20.5,
{ 6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0 } }
};
// Instantiate the solver
MPSolver solver("StiglerDietExample", MPSolver::GLOP_LINEAR_PROGRAMMING);
// Declare an array to hold our nutritional data.
std::vector<MPVariable*> food;
std::vector<MPVariable *> food;
// Objective: minimize the sum of (price-normalized) foods.
MPObjective* const objective = solver.MutableObjective();
MPObjective *const objective = solver.MutableObjective();
const double infinity = solver.infinity();
for (const Commodity& commodity : data) {
for (const Commodity &commodity : data) {
food.push_back(solver.MakeNumVar(0.0, infinity, commodity.name));
objective->SetCoefficient(food.back(), 1);
}
objective->SetMinimization();
// Create the constraints, one per nutrient.
std::vector<MPConstraint*> constraints;
std::vector<MPConstraint *> constraints;
for (std::size_t i = 0; i < nutrients.size(); ++i) {
constraints.push_back(
solver.MakeRowConstraint(nutrients[i].second, infinity));
@@ -290,11 +233,11 @@ void RunStiglerDietExample() {
LOG(INFO) << "Problem solved in " << solver.wall_time() << " milliseconds";
LOG(INFO) << "Problem solved in " << solver.iterations() << " iterations";
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
google::InitGoogleLogging(argv[0]);
FLAGS_logtostderr = 1;
absl::GetFlag(FLAGS_logtostderr) = 1;
operations_research::RunStiglerDietExample();
return EXIT_SUCCESS;
}

View File

@@ -52,7 +52,7 @@
// No attempt is made to force integrality.
#include <cstdio>
#include <cstring> // strlen
#include <cstring> // strlen
#include <map>
#include <memory>
#include <string>
@@ -77,170 +77,162 @@ struct Instance {
int max_boxes;
int width;
int height;
const char* grid;
const char *grid;
};
Instance kInstances[] = {{4, 22, 6,
"..@@@@@..............."
"..@@@@@@........@@@..."
".....@@@@@......@@@..."
".......@@@@@@@@@@@@..."
".........@@@@@........"
".........@@@@@........"},
{3, 13, 10,
"............."
"............."
"............."
"...@@@@......"
"...@@@@......"
"...@@@@......"
".......@@@..."
".......@@@..."
".......@@@..."
"............."},
{4, 13, 9,
"............."
"..@.@.@......"
"...@.@.@....."
"..@.@.@......"
"..@.@.@......"
"...@.@.@....."
"....@.@......"
"..........@@@"
"..........@@@"},
{4, 13, 9,
".........@..."
".........@..."
"@@@@@@@@@@..."
"..@......@..."
"..@......@..."
"..@......@..."
"..@@@@@@@@@@@"
"..@.........."
"..@.........."},
{7, 25, 14,
"........................."
"..@@@@@@@@@@@@@@@@@@@@..."
"..@@@@@@@@@@@@@@@@@@@@..."
"..@@.................@..."
"..@@.................@..."
"..@@.......@@@.......@.@."
"..@@.......@@@.......@..."
"..@@...@@@@@@@@@@@@@@@..."
"..@@...@@@@@@@@@@@@@@@..."
"..@@.......@@@.......@..."
"..@@.......@@@.......@..."
"..@@.................@..."
"..@@.................@..."
"........................."},
{6, 25, 16,
"........................."
"......@@@@@@@@@@@@@......"
"........................."
".....@..........@........"
".....@..........@........"
".....@......@............"
".....@......@.@@@@@@@...."
".....@......@............"
".....@......@.@@@@@@@...."
".....@......@............"
"....@@@@....@............"
"....@@@@....@............"
"..@@@@@@....@............"
"..@@@.......@............"
"..@@@...................."
"..@@@@@@@@@@@@@@@@@@@@@@@"},
{5, 40, 18,
"........................................"
"........................................"
"...@@@@@@..............................."
"...@@@@@@..............................."
"...@@@@@@..............................."
"...@@@@@@.........@@@@@@@@@@............"
"...@@@@@@.........@@@@@@@@@@............"
"..................@@@@@@@@@@............"
"..................@@@@@@@@@@............"
".............@@@@@@@@@@@@@@@............"
".............@@@@@@@@@@@@@@@............"
"........@@@@@@@@@@@@...................."
"........@@@@@@@@@@@@...................."
"........@@@@@@.........................."
"........@@@@@@.........................."
"........................................"
"........................................"
"........................................"},
{8, 40, 18,
"........................................"
"..@@.@.@.@.............................."
"..@@.@.@.@...............@.............."
"..@@.@.@.@............@................."
"..@@.@.@.@.............................."
"..@@.@.@.@.................@............"
"..@@.@..................@..............."
"..@@.@.................................."
"..@@.@.................................."
"..@@.@................@@@@.............."
"..@@.@..............@@@@@@@@............"
"..@@.@.................................."
"..@@.@..............@@@@@@@@............"
"..@@.@.................................."
"..@@.@................@@@@.............."
"..@@.@.................................."
"..@@.@.................................."
"........................................"},
{10, 40, 19,
"@@@@@..................................."
"@@@@@..................................."
"@@@@@..................................."
"@@@@@..................................."
"@@@@@..................................."
"@@@@@...........@@@@@@@@@@@............."
"@@@@@...........@@@@@@@@@@@............."
"....................@@@@................"
"....................@@@@................"
"....................@@@@................"
"....................@@@@................"
"....................@@@@................"
"...............@@@@@@@@@@@@@@..........."
"...............@@@@@@@@@@@@@@..........."
".......@@@@@@@@@@@@@@@@@@@@@@..........."
".......@@@@@@@@@........................"
"........................................"
"........................................"
"........................................"},
{10, 40, 25,
"...................@...................."
"...............@@@@@@@@@................"
"............@@@.........@@@............."
"...........@...............@............"
"..........@.................@..........."
".........@...................@.........."
".........@...................@.........."
".........@.....@@......@@....@.........."
"........@.....@@@@....@@@@....@........."
"........@.....................@........."
"........@.....................@........."
"........@..........@@.........@........."
".......@@..........@@.........@@........"
"........@.....................@........."
"........@.....................@........."
"........@......@@@@@@@@@......@........."
"........@......@@@@@@@@@......@........."
".........@...................@.........."
".........@...................@.........."
".........@...................@.........."
"..........@.................@..........."
"...........@...............@............"
"............@@@.........@@@............."
"...............@@@@@@@@@................"
"...................@...................."}};
Instance kInstances[] = {
{ 4, 22, 6, "..@@@@@..............."
"..@@@@@@........@@@..."
".....@@@@@......@@@..."
".......@@@@@@@@@@@@..."
".........@@@@@........"
".........@@@@@........" },
{ 3, 13, 10, "............."
"............."
"............."
"...@@@@......"
"...@@@@......"
"...@@@@......"
".......@@@..."
".......@@@..."
".......@@@..."
"............." },
{ 4, 13, 9, "............."
"..@.@.@......"
"...@.@.@....."
"..@.@.@......"
"..@.@.@......"
"...@.@.@....."
"....@.@......"
"..........@@@"
"..........@@@" },
{ 4, 13, 9, ".........@..."
".........@..."
"@@@@@@@@@@..."
"..@......@..."
"..@......@..."
"..@......@..."
"..@@@@@@@@@@@"
"..@.........."
"..@.........." },
{ 7, 25, 14, "........................."
"..@@@@@@@@@@@@@@@@@@@@..."
"..@@@@@@@@@@@@@@@@@@@@..."
"..@@.................@..."
"..@@.................@..."
"..@@.......@@@.......@.@."
"..@@.......@@@.......@..."
"..@@...@@@@@@@@@@@@@@@..."
"..@@...@@@@@@@@@@@@@@@..."
"..@@.......@@@.......@..."
"..@@.......@@@.......@..."
"..@@.................@..."
"..@@.................@..."
"........................." },
{ 6, 25, 16, "........................."
"......@@@@@@@@@@@@@......"
"........................."
".....@..........@........"
".....@..........@........"
".....@......@............"
".....@......@.@@@@@@@...."
".....@......@............"
".....@......@.@@@@@@@...."
".....@......@............"
"....@@@@....@............"
"....@@@@....@............"
"..@@@@@@....@............"
"..@@@.......@............"
"..@@@...................."
"..@@@@@@@@@@@@@@@@@@@@@@@" },
{ 5, 40, 18, "........................................"
"........................................"
"...@@@@@@..............................."
"...@@@@@@..............................."
"...@@@@@@..............................."
"...@@@@@@.........@@@@@@@@@@............"
"...@@@@@@.........@@@@@@@@@@............"
"..................@@@@@@@@@@............"
"..................@@@@@@@@@@............"
".............@@@@@@@@@@@@@@@............"
".............@@@@@@@@@@@@@@@............"
"........@@@@@@@@@@@@...................."
"........@@@@@@@@@@@@...................."
"........@@@@@@.........................."
"........@@@@@@.........................."
"........................................"
"........................................"
"........................................" },
{ 8, 40, 18, "........................................"
"..@@.@.@.@.............................."
"..@@.@.@.@...............@.............."
"..@@.@.@.@............@................."
"..@@.@.@.@.............................."
"..@@.@.@.@.................@............"
"..@@.@..................@..............."
"..@@.@.................................."
"..@@.@.................................."
"..@@.@................@@@@.............."
"..@@.@..............@@@@@@@@............"
"..@@.@.................................."
"..@@.@..............@@@@@@@@............"
"..@@.@.................................."
"..@@.@................@@@@.............."
"..@@.@.................................."
"..@@.@.................................."
"........................................" },
{ 10, 40, 19, "@@@@@..................................."
"@@@@@..................................."
"@@@@@..................................."
"@@@@@..................................."
"@@@@@..................................."
"@@@@@...........@@@@@@@@@@@............."
"@@@@@...........@@@@@@@@@@@............."
"....................@@@@................"
"....................@@@@................"
"....................@@@@................"
"....................@@@@................"
"....................@@@@................"
"...............@@@@@@@@@@@@@@..........."
"...............@@@@@@@@@@@@@@..........."
".......@@@@@@@@@@@@@@@@@@@@@@..........."
".......@@@@@@@@@........................"
"........................................"
"........................................"
"........................................" },
{ 10, 40, 25, "...................@...................."
"...............@@@@@@@@@................"
"............@@@.........@@@............."
"...........@...............@............"
"..........@.................@..........."
".........@...................@.........."
".........@...................@.........."
".........@.....@@......@@....@.........."
"........@.....@@@@....@@@@....@........."
"........@.....................@........."
"........@.....................@........."
"........@..........@@.........@........."
".......@@..........@@.........@@........"
"........@.....................@........."
"........@.....................@........."
"........@......@@@@@@@@@......@........."
"........@......@@@@@@@@@......@........."
".........@...................@.........."
".........@...................@.........."
".........@...................@.........."
"..........@.................@..........."
"...........@...............@............"
"............@@@.........@@@............."
"...............@@@@@@@@@................"
"...................@...................." }
};
const int kInstanceCount = 10;
// ---------- Box ---------
class Box {
public:
public:
static const int kAreaCost = 1;
static const int kFixedCost = 10;
@@ -257,11 +249,14 @@ class Box {
int y_max() const { return y_max_; }
// Lexicographic order
int Compare(const Box& box) const {
int Compare(const Box &box) const {
int c;
if ((c = (x_min() - box.x_min())) != 0) return c;
if ((c = (x_max() - box.x_max())) != 0) return c;
if ((c = (y_min() - box.y_min())) != 0) return c;
if ((c = (x_min() - box.x_min())) != 0)
return c;
if ((c = (x_max() - box.x_max())) != 0)
return c;
if ((c = (y_min() - box.y_min())) != 0)
return c;
return y_max() - box.y_max();
}
@@ -279,7 +274,7 @@ class Box {
y_max(), Cost());
}
private:
private:
int x_min_;
int x_max_;
int y_min_;
@@ -287,7 +282,7 @@ class Box {
};
struct BoxLessThan {
bool operator()(const Box& b1, const Box& b2) const {
bool operator()(const Box &b1, const Box &b2) const {
return b1.Compare(b2) < 0;
}
};
@@ -295,16 +290,13 @@ struct BoxLessThan {
// ---------- Covering Problem ---------
class CoveringProblem {
public:
public:
// Grid is a row-major string of length width*height with '@' for an
// occupied cell (strawberry) and '.' for an empty cell. Solver is
// not owned.
CoveringProblem(MPSolver* const solver, const Instance& instance)
: solver_(solver),
max_boxes_(instance.max_boxes),
width_(instance.width),
height_(instance.height),
grid_(instance.grid) {}
CoveringProblem(MPSolver *const solver, const Instance &instance)
: solver_(solver), max_boxes_(instance.max_boxes), width_(instance.width),
height_(instance.height), grid_(instance.grid) {}
// Constructs initial variables and constraints. Initial column
// (box) covers entire grid, ensuring feasibility.
@@ -316,13 +308,14 @@ class CoveringProblem {
}
for (int i = 0; i < size; ++i) {
char c = grid_[i];
if ((c != '@') && (c != '.')) return false;
if ((c != '@') && (c != '.'))
return false;
}
AddCellConstraints(); // sum for every cell is <=1 or =1
AddMaxBoxesConstraint(); // sum of box variables is <= max_boxes()
if (!FLAGS_colgen_complete) {
AddBox(Box(0, width() - 1, 0, height() - 1)); // grid-covering box
AddCellConstraints(); // sum for every cell is <=1 or =1
AddMaxBoxesConstraint(); // sum of box variables is <= max_boxes()
if (!absl::GetFlag(FLAGS_colgen_complete)) {
AddBox(Box(0, width() - 1, 0, height() - 1)); // grid-covering box
} else {
// Naive alternative to column generation - generate all boxes;
// works fine for smaller problems, too slow for big.
@@ -366,7 +359,7 @@ class CoveringProblem {
// each, so pre-calculate sums of cell duals for all rectangles with
// upper-left at 0, 0, and use these to calculate the sum in
// constant time using the standard inclusion-exclusion trick.
double GetOptimalBox(Box* const target) {
double GetOptimalBox(Box *const target) {
// Cost change threshold for new Box
const double kCostChangeThreshold = -.01;
@@ -383,7 +376,7 @@ class CoveringProblem {
for (int x_min = 0; x_min < width(); ++x_min) {
for (int x_max = x_min; x_max < width(); ++x_max) {
Box box(x_min, x_max, y_min, y_max);
const double cell_coverage_dual = // inclusion-exclusion
const double cell_coverage_dual = // inclusion-exclusion
+zero_access(upper_left_sums, x_max, y_max) -
zero_access(upper_left_sums, x_max, y_min - 1) -
zero_access(upper_left_sums, x_min - 1, y_max) +
@@ -426,9 +419,9 @@ class CoveringProblem {
// Add continuous [0,1] box variable with box.Cost() as objective
// coefficient. Add to cell constraint of all enclosed cells.
MPVariable* AddBox(const Box& box) {
MPVariable *AddBox(const Box &box) {
CHECK(boxes_.find(box) == boxes_.end());
MPVariable* const var = solver_->MakeNumVar(0., 1., box.DebugString());
MPVariable *const var = solver_->MakeNumVar(0., 1., box.DebugString());
solver_->MutableObjective()->SetCoefficient(var, box.Cost());
max_boxes_constraint_->SetCoefficient(var, 1.0);
for (int y = box.y_min(); y <= box.y_max(); ++y) {
@@ -462,7 +455,7 @@ class CoveringProblem {
std::unique_ptr<char[]> display(new char[(width_ + 1) * height_ + 1]);
for (int y = 0; y < height_; ++y) {
memcpy(display.get() + y * (width_ + 1), grid_ + width_ * y,
width_); // Copy the original line.
width_); // Copy the original line.
display[y * (width_ + 1) + width_] = '\n';
}
display[height_ * (width_ + 1)] = '\0';
@@ -475,7 +468,7 @@ class CoveringProblem {
active_box_index++;
absl::StrAppendFormat(&output, "%c: box %s with value %f\n",
box_character, i->first.DebugString(), value);
const Box& box = i->first;
const Box &box = i->first;
for (int x = box.x_min(); x <= box.x_max(); ++x) {
for (int y = box.y_min(); y <= box.y_max(); ++y) {
display[x + y * (width_ + 1)] = box_character;
@@ -487,10 +480,10 @@ class CoveringProblem {
return output;
}
protected:
protected:
int index(int x, int y) const { return width_ * y + x; }
MPConstraint* cell(int x, int y) { return cells_[index(x, y)]; }
const MPConstraint* cell(int x, int y) const { return cells_[index(x, y)]; }
MPConstraint *cell(int x, int y) { return cells_[index(x, y)]; }
const MPConstraint *cell(int x, int y) const { return cells_[index(x, y)]; }
// Adds constraints that every cell is covered at most once, exactly
// once if occupied.
@@ -510,7 +503,7 @@ class CoveringProblem {
}
// Gets 2d array element, returning 0 if out-of-bounds.
double zero_access(const std::vector<double>& array, int x, int y) const {
double zero_access(const std::vector<double> &array, int x, int y) const {
if (x < 0 || y < 0) {
return 0;
}
@@ -519,7 +512,7 @@ class CoveringProblem {
// Precomputes the sum of reduced costs for every upper-left
// rectangle.
void ComputeUpperLeftSums(std::vector<double>* upper_left_sums) const {
void ComputeUpperLeftSums(std::vector<double> *upper_left_sums) const {
for (int y = 0; y < height(); ++y) {
for (int x = 0; x < width(); ++x) {
upper_left_sums->operator[](index(x, y)) =
@@ -530,22 +523,22 @@ class CoveringProblem {
}
}
typedef std::map<Box, MPVariable*, BoxLessThan> BoxTable;
MPSolver* const solver_; // not owned
typedef std::map<Box, MPVariable *, BoxLessThan> BoxTable;
MPSolver *const solver_; // not owned
const int max_boxes_;
const int width_;
const int height_;
const char* const grid_;
std::vector<MPConstraint*> cells_;
const char *const grid_;
std::vector<MPConstraint *> cells_;
BoxTable boxes_;
MPConstraint* max_boxes_constraint_;
MPConstraint *max_boxes_constraint_;
};
// ---------- Main Solve Method ----------
// Solves iteratively using delayed column generation, up to maximum
// number of steps.
void SolveInstance(const Instance& instance,
void SolveInstance(const Instance &instance,
MPSolver::OptimizationProblemType solver_type) {
// Prepares the solver.
MPSolver solver("ColumnGeneration", solver_type);
@@ -558,14 +551,14 @@ void SolveInstance(const Instance& instance,
LOG(INFO) << "Initial problem:\n" << problem.PrintGrid();
int step_number = 0;
while (step_number < FLAGS_colgen_max_iterations) {
if (FLAGS_colgen_verbose) {
while (step_number < absl::GetFlag(FLAGS_colgen_max_iterations)) {
if (absl::GetFlag(FLAGS_colgen_verbose)) {
LOG(INFO) << "Step number " << step_number;
}
// Solve with existing columns.
CHECK_EQ(MPSolver::OPTIMAL, solver.Solve());
if (FLAGS_colgen_verbose) {
if (absl::GetFlag(FLAGS_colgen_verbose)) {
LOG(INFO) << problem.PrintCovering();
}
@@ -577,7 +570,7 @@ void SolveInstance(const Instance& instance,
}
// Add new column to problem.
if (FLAGS_colgen_verbose) {
if (absl::GetFlag(FLAGS_colgen_verbose)) {
LOG(INFO) << "Adding " << box.DebugString()
<< ", reduced_cost =" << reduced_cost;
}
@@ -586,7 +579,7 @@ void SolveInstance(const Instance& instance,
++step_number;
}
if (step_number >= FLAGS_colgen_max_iterations) {
if (step_number >= absl::GetFlag(FLAGS_colgen_max_iterations)) {
// Solve one last time with all generated columns.
CHECK_EQ(MPSolver::OPTIMAL, solver.Solve());
}
@@ -594,9 +587,9 @@ void SolveInstance(const Instance& instance,
LOG(INFO) << step_number << " columns added";
LOG(INFO) << "Final coverage: " << problem.PrintCovering();
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
std::string usage = "column_generation\n";
usage += " --colgen_verbose print verbosely\n";
usage += " --colgen_max_iterations <n> max columns to generate\n";
@@ -607,48 +600,50 @@ int main(int argc, char** argv) {
operations_research::MPSolver::OptimizationProblemType solver_type;
bool found = false;
#if defined(USE_CLP)
if (FLAGS_colgen_solver == "clp") {
if (absl::GetFlag(FLAGS_colgen_solver) == "clp") {
solver_type = operations_research::MPSolver::CLP_LINEAR_PROGRAMMING;
found = true;
}
#endif // USE_CLP
#endif // USE_CLP
#if defined(USE_GLOP)
if (FLAGS_colgen_solver == "glop") {
if (absl::GetFlag(FLAGS_colgen_solver) == "glop") {
solver_type = operations_research::MPSolver::GLOP_LINEAR_PROGRAMMING;
found = true;
}
#endif // USE_GLOP
#endif // USE_GLOP
#if defined(USE_XPRESS)
if (FLAGS_colgen_solver == "xpress") {
if (absl::GetFlag(FLAGS_colgen_solver) == "xpress") {
solver_type = operations_research::MPSolver::XPRESS_LINEAR_PROGRAMMING;
// solver_type = operations_research::MPSolver::CPLEX_LINEAR_PROGRAMMING;
found = true;
}
#endif
#if defined(USE_CPLEX)
if (FLAGS_colgen_solver == "cplex") {
if (absl::GetFlag(FLAGS_colgen_solver) == "cplex") {
solver_type = operations_research::MPSolver::CPLEX_LINEAR_PROGRAMMING;
found = true;
}
#endif
if (!found) {
LOG(ERROR) << "Unknown solver " << FLAGS_colgen_solver;
LOG(ERROR) << "Unknown solver " << absl::GetFlag(FLAGS_colgen_solver);
return 1;
}
LOG(INFO) << "Chosen solver: " << FLAGS_colgen_solver << std::endl;
LOG(INFO) << "Chosen solver: " << absl::GetFlag(FLAGS_colgen_solver)
<< std::endl;
if (FLAGS_colgen_instance == -1) {
if (absl::GetFlag(FLAGS_colgen_instance) == -1) {
for (int i = 0; i < operations_research::kInstanceCount; ++i) {
const operations_research::Instance& instance =
const operations_research::Instance &instance =
operations_research::kInstances[i];
operations_research::SolveInstance(instance, solver_type);
}
} else {
CHECK_GE(FLAGS_colgen_instance, 0);
CHECK_LT(FLAGS_colgen_instance, operations_research::kInstanceCount);
const operations_research::Instance& instance =
operations_research::kInstances[FLAGS_colgen_instance];
CHECK_GE(absl::GetFlag(FLAGS_colgen_instance), 0);
CHECK_LT(absl::GetFlag(FLAGS_colgen_instance),
operations_research::kInstanceCount);
const operations_research::Instance &instance =
operations_research::kInstances[absl::GetFlag(FLAGS_colgen_instance)];
operations_research::SolveInstance(instance, solver_type);
}
return EXIT_SUCCESS;

View File

@@ -39,17 +39,22 @@ DEFINE_double(fix_cost, 5000, "Cost of opening a facility.");
namespace operations_research {
typedef struct {
double x{0};
double y{0};
double x { 0 }
;
double y { 0 }
;
} Location;
typedef struct {
int f{-1};
int c{-1};
MPVariable* x{nullptr};
int f { -1 }
;
int c { -1 }
;
MPVariable *x { nullptr }
;
} Edge;
static double Distance(const Location& src, const Location& dst) {
static double Distance(const Location &src, const Location &dst) {
return sqrt((src.x - dst.x) * (src.x - dst.x) +
(src.y - dst.y) * (src.y - dst.y));
}
@@ -91,15 +96,16 @@ static void UncapacitatedFacilityLocation(
// Distance(f,c) <= kMaxDistance
MPSolver solver("UncapacitatedFacilityLocation", optimization_problem_type);
const double infinity = solver.infinity();
MPObjective* objective = solver.MutableObjective();
MPObjective *objective = solver.MutableObjective();
objective->SetMinimization();
// Add binary facilities variables
std::vector<MPVariable*> xf{};
std::vector<MPVariable *> xf {}
;
for (int f = 0; f < facilities; ++f) {
snprintf(name_buffer, kStrLen, "x[%d](%g,%g)", f, facility[f].x,
facility[f].y);
MPVariable* x = solver.MakeBoolVar(name_buffer);
MPVariable *x = solver.MakeBoolVar(name_buffer);
xf.push_back(x);
objective->SetCoefficient(x, fix_cost);
}
@@ -109,13 +115,14 @@ static void UncapacitatedFacilityLocation(
for (int c = 0; c < clients; ++c) {
snprintf(name_buffer, kStrLen, "R-Client[%d](%g,%g)", c, client[c].x,
client[c].y);
MPConstraint* client_constraint =
solver.MakeRowConstraint(/* lb */ 1,
/* ub */ infinity, name_buffer);
MPConstraint *client_constraint =
solver.MakeRowConstraint(/* lb */ 1, /* ub */ infinity, name_buffer);
for (int f = 0; f < facilities; ++f) {
double distance = Distance(facility[f], client[c]);
if (distance > kMaxDistance) continue;
Edge edge{};
if (distance > kMaxDistance)
continue;
Edge edge {}
;
snprintf(name_buffer, kStrLen, "x[%d,%d]", f, c);
edge.x = solver.MakeNumVar(/* lb */ 0, /*ub */ 1, name_buffer);
edge.f = f;
@@ -126,18 +133,18 @@ static void UncapacitatedFacilityLocation(
client_constraint->SetCoefficient(edge.x, 1);
// add constraint (2)
snprintf(name_buffer, kStrLen, "R-Edge[%d,%d]", f, c);
MPConstraint* edge_constraint =
solver.MakeRowConstraint(/* lb */ 0,
/* ub */ infinity, name_buffer);
MPConstraint *edge_constraint =
solver.MakeRowConstraint(/* lb */ 0, /* ub */ infinity, name_buffer);
edge_constraint->SetCoefficient(edge.x, -1);
edge_constraint->SetCoefficient(xf[f], 1);
}
} // End adding all edge variables
} // End adding all edge variables
LOG(INFO) << "Number of variables = " << solver.NumVariables();
LOG(INFO) << "Number of constraints = " << solver.NumConstraints();
// display on screen LP if small enough
if (clients <= 10 && facilities <= 10) {
std::string lp_string{};
std::string lp_string {}
;
solver.ExportModelAsLpFormat(/* obfuscate */ false, &lp_string);
std::cout << "LP-Model:\n" << lp_string << std::endl;
}
@@ -151,15 +158,17 @@ static void UncapacitatedFacilityLocation(
LOG(FATAL) << "The problem does not have an optimal solution!";
} else {
LOG(INFO) << "Optimal objective value = " << objective->Value();
if (FLAGS_verbose) {
std::vector<std::vector<int>> solution(facilities);
for (auto& edge : edges) {
if (edge.x->solution_value() < 0.5) continue;
if (absl::GetFlag(FLAGS_verbose)) {
std::vector<std::vector<int> > solution(facilities);
for (auto &edge : edges) {
if (edge.x->solution_value() < 0.5)
continue;
solution[edge.f].push_back(edge.c);
}
std::cout << "\tSolution:\n";
for (int f = 0; f < facilities; ++f) {
if (solution[f].size() < 1) continue;
if (solution[f].size() < 1)
continue;
assert(xf[f]->solution_value() > 0.5);
snprintf(name_buffer, kStrLen, "\t Facility[%d](%g,%g):", f,
facility[f].x, facility[f].y);
@@ -208,30 +217,34 @@ void RunAllExamples(int32 facilities, int32 clients, double fix_cost) {
LOG(INFO) << "---- Integer programming example with Gurobi ----";
UncapacitatedFacilityLocation(facilities, clients, fix_cost,
MPSolver::GUROBI_MIXED_INTEGER_PROGRAMMING);
#endif // USE_GUROBI
#endif // USE_GUROBI
#if defined(USE_CPLEX)
LOG(INFO) << "---- Integer programming example with CPLEX ----";
UncapacitatedFacilityLocation(facilities, clients, fix_cost,
MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING);
#endif // USE_CPLEX
#endif // USE_CPLEX
LOG(INFO) << "---- Integer programming example with CP-SAT ----";
UncapacitatedFacilityLocation(facilities, clients, fix_cost,
MPSolver::SAT_INTEGER_PROGRAMMING);
}
} // namespace operations_research
} // namespace operations_research
int main(int argc, char** argv) {
int main(int argc, char **argv) {
google::InitGoogleLogging(argv[0]);
gflags::SetUsageMessage(
std::string("This program solve a (randomly generated)\n") +
std::string("Uncapacitated Facility Location Problem. Sample Usage:\n"));
gflags::ParseCommandLineFlags(&argc, &argv, true);
CHECK_LT(0, FLAGS_facilities) << "Specify an instance size greater than 0.";
CHECK_LT(0, FLAGS_clients) << "Specify a non-null client size.";
CHECK_LT(0, FLAGS_fix_cost) << "Specify a non-null client size.";
FLAGS_logtostderr = 1;
operations_research::RunAllExamples(FLAGS_facilities, FLAGS_clients,
FLAGS_fix_cost);
CHECK_LT(0, absl::GetFlag(FLAGS_facilities))
<< "Specify an instance size greater than 0.";
CHECK_LT(0, absl::GetFlag(FLAGS_clients))
<< "Specify a non-null client size.";
CHECK_LT(0, absl::GetFlag(FLAGS_fix_cost))
<< "Specify a non-null client size.";
absl::GetFlag(FLAGS_logtostderr) = 1;
operations_research::RunAllExamples(absl::GetFlag(FLAGS_facilities),
absl::GetFlag(FLAGS_clients),
absl::GetFlag(FLAGS_fix_cost));
return EXIT_SUCCESS;
}

View File

@@ -24,10 +24,15 @@ void Solve() {
const IntVar end_p2 = cp_model.NewIntVar(Domain(500, 1000));
const IntervalVar p2 = cp_model.NewIntervalVar(start_p2, duration_p2, end_p2);
cp_model.AddEquality(LinearExpr::Sum({duration_p1, duration_p2}), 360);
cp_model.AddEquality(LinearExpr::Sum({
duration_p1, duration_p2
}),
360);
cp_model.AddLessOrEqual(end_p1, start_p2);
cp_model.AddNoOverlap({ins, p1, p2});
cp_model.AddNoOverlap({
ins, p1, p2
});
Model model;
@@ -42,7 +47,7 @@ void Solve() {
const int kSolutionLimit = 100;
int num_solutions = 0;
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse& r) {
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse & r) {
LOG(INFO) << "Solution " << num_solutions;
LOG(INFO) << " start_p1 = " << SolutionIntegerValue(r, start_p1);
LOG(INFO) << " duration_p1 = " << SolutionIntegerValue(r, duration_p1);
@@ -60,8 +65,8 @@ void Solve() {
LOG(INFO) << "Number of solutions found: " << num_solutions;
}
} // namespace sat
} // namespace operations_research
} // namespace sat
} // namespace operations_research
int main() {
operations_research::sat::Solve();

View File

@@ -39,9 +39,9 @@ namespace operations_research {
namespace sat {
// Solve a single machine problem with weighted tardiness cost.
void Solve(const std::vector<int64>& durations,
const std::vector<int64>& due_dates,
const std::vector<int64>& weights) {
void Solve(const std::vector<int64> &durations,
const std::vector<int64> &due_dates,
const std::vector<int64> &weights) {
const int num_tasks = durations.size();
CHECK_EQ(due_dates.size(), num_tasks);
CHECK_EQ(weights.size(), num_tasks);
@@ -63,7 +63,8 @@ void Solve(const std::vector<int64>& durations,
int next_task = -1;
int64 next_cost;
for (int j = 0; j < num_tasks; ++j) {
if (is_taken[j]) continue;
if (is_taken[j])
continue;
const int64 cost = weights[j] * std::max<int64>(0, end - due_dates[j]);
if (next_task == -1 || cost < next_cost) {
next_task = j;
@@ -117,7 +118,8 @@ void Solve(const std::vector<int64>& durations,
cp_model.AddNoOverlap(task_intervals);
// TODO(user): We can't set an objective upper bound with the current cp_model
// interface, so we can't use heuristic or FLAGS_upper_bound here. The best is
// interface, so we can't use heuristic or absl::GetFlag(FLAGS_upper_bound)
// here. The best is
// probably to provide a "solution hint" instead.
//
// Set a known upper bound (or use the flag). This has a bigger impact than
@@ -141,7 +143,8 @@ void Solve(const std::vector<int64>& durations,
int num_added_precedences = 0;
for (int i = 0; i < num_tasks; ++i) {
for (int j = 0; j < num_tasks; ++j) {
if (i == j) continue;
if (i == j)
continue;
if (due_dates[i] <= due_dates[j] && durations[i] <= durations[j] &&
weights[i] >= weights[j]) {
// If two jobs have exactly the same specs, we don't add both
@@ -164,8 +167,8 @@ void Solve(const std::vector<int64>& durations,
// Note that we only fully instantiate the start/end and only look at the
// lower bound for the objective and the tardiness variables.
Model model;
model.Add(NewSatParameters(FLAGS_params));
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse& r) {
model.Add(NewSatParameters(absl::GetFlag(FLAGS_params)));
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse & r) {
// Note that we compute the "real" cost here and do not use the tardiness
// variables. This is because in the core based approach, the tardiness
// variable might be fixed before the end date, and we just have a >=
@@ -215,41 +218,45 @@ void Solve(const std::vector<int64>& durations,
void ParseAndSolve() {
std::vector<int> numbers;
std::vector<std::string> entries;
for (const std::string& line : FileLines(FLAGS_input)) {
for (const std::string &line : FileLines(absl::GetFlag(FLAGS_input))) {
entries = absl::StrSplit(line, ' ', absl::SkipEmpty());
for (const std::string& entry : entries) {
for (const std::string &entry : entries) {
numbers.push_back(0);
CHECK(absl::SimpleAtoi(entry, &numbers.back()));
}
}
const int instance_size = FLAGS_size * 3;
LOG(INFO) << numbers.size() << " numbers in '" << FLAGS_input << "'.";
const int instance_size = absl::GetFlag(FLAGS_size) * 3;
LOG(INFO) << numbers.size() << " numbers in '" << absl::GetFlag(FLAGS_input)
<< "'.";
LOG(INFO) << "This correspond to " << numbers.size() / instance_size
<< " instances of size " << FLAGS_size;
LOG(INFO) << "Loading instance #" << FLAGS_n;
CHECK_GE(FLAGS_n, 0);
CHECK_LE(FLAGS_n * instance_size, numbers.size());
<< " instances of size " << absl::GetFlag(FLAGS_size);
LOG(INFO) << "Loading instance #" << absl::GetFlag(FLAGS_n);
CHECK_GE(absl::GetFlag(FLAGS_n), 0);
CHECK_LE(absl::GetFlag(FLAGS_n) * instance_size, numbers.size());
// The order in a wt file is: duration, tardiness weights and then due_dates.
int index = (FLAGS_n - 1) * instance_size;
int index = (absl::GetFlag(FLAGS_n) - 1) * instance_size;
std::vector<int64> durations;
for (int j = 0; j < FLAGS_size; ++j) durations.push_back(numbers[index++]);
for (int j = 0; j < absl::GetFlag(FLAGS_size); ++j)
durations.push_back(numbers[index++]);
std::vector<int64> weights;
for (int j = 0; j < FLAGS_size; ++j) weights.push_back(numbers[index++]);
for (int j = 0; j < absl::GetFlag(FLAGS_size); ++j)
weights.push_back(numbers[index++]);
std::vector<int64> due_dates;
for (int j = 0; j < FLAGS_size; ++j) due_dates.push_back(numbers[index++]);
for (int j = 0; j < absl::GetFlag(FLAGS_size); ++j)
due_dates.push_back(numbers[index++]);
Solve(durations, due_dates, weights);
}
} // namespace sat
} // namespace operations_research
} // namespace sat
} // namespace operations_research
int main(int argc, char** argv) {
absl::SetFlag(&FLAGS_logtostderr, true);
int main(int argc, char **argv) {
absl::SetFlag(&absl::GetFlag(FLAGS_logtostderr), true);
gflags::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_input.empty()) {
if (absl::GetFlag(FLAGS_input).empty()) {
LOG(FATAL) << "Please supply a data file with --input=";
}
operations_research::sat::ParseAndSolve();