[CP-SAT] simplify python proto generation workflow
This commit is contained in:
@@ -698,10 +698,6 @@ add_custom_command(
|
||||
$<TARGET_FILE:routing_pybind11> ${PYTHON_PROJECT}/routing/python
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
$<TARGET_FILE:cp_model_helper_pybind11> ${PYTHON_PROJECT}/sat/python
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
$<TARGET_FILE:cp_model_builder_pybind> ${PYTHON_PROJECT}/sat/python
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
$<TARGET_FILE:sat_parameters_builder_pybind> ${PYTHON_PROJECT}/sat/python
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
$<TARGET_FILE:rcpsp_pybind11> ${PYTHON_PROJECT}/scheduling/python
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
@@ -727,9 +723,7 @@ add_custom_command(
|
||||
$<$<BOOL:${BUILD_MATH_OPT}>:math_opt_elemental_pybind11>
|
||||
$<$<BOOL:${BUILD_MATH_OPT}>:math_opt_io_pybind11>
|
||||
$<TARGET_NAME_IF_EXISTS:pdlp_pybind11>
|
||||
cp_model_builder_pybind
|
||||
cp_model_helper_pybind11
|
||||
sat_parameters_builder_pybind
|
||||
rcpsp_pybind11
|
||||
set_cover_pybind11
|
||||
sorted_interval_list_pybind11
|
||||
|
||||
@@ -23,9 +23,7 @@ py_binary(
|
||||
"//ortools/graph/python:linear_sum_assignment.so",
|
||||
"//ortools/graph/python:max_flow.so",
|
||||
"//ortools/graph/python:min_cost_flow.so",
|
||||
"//ortools/sat/python:cp_model_builder_pybind.so",
|
||||
"//ortools/sat/python:cp_model_helper.so",
|
||||
"//ortools/sat/python:sat_parameters_builder_pybind.so",
|
||||
],
|
||||
tags = ["manual"],
|
||||
deps = [
|
||||
|
||||
@@ -126,8 +126,6 @@ setup(
|
||||
'@PYTHON_PROJECT@.sat.colab':['*.pyi', 'py.typed'],
|
||||
'@PYTHON_PROJECT@.sat.python':[
|
||||
'$<TARGET_FILE_NAME:cp_model_helper_pybind11>',
|
||||
'$<TARGET_FILE_NAME:cp_model_builder_pybind>',
|
||||
'$<TARGET_FILE_NAME:sat_parameters_builder_pybind>',
|
||||
'*.pyi',
|
||||
'py.typed'
|
||||
],
|
||||
|
||||
@@ -57,55 +57,12 @@ cc_library(
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gen_cp_model_builder_pybind",
|
||||
srcs = ["gen_cp_model_builder_pybind.cc"],
|
||||
name = "gen_proto_builder_pybind11",
|
||||
srcs = ["gen_proto_builder_pybind11.cc"],
|
||||
deps = [
|
||||
":wrappers",
|
||||
"//ortools/base",
|
||||
"//ortools/sat:cp_model_cc_proto",
|
||||
"@abseil-cpp//absl/log:die_if_null",
|
||||
"@abseil-cpp//absl/strings:str_format",
|
||||
],
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "run_gen_cp_model_builder_pybind",
|
||||
outs = ["cp_model_builder_pybind.cc"],
|
||||
cmd = "$(location :gen_cp_model_builder_pybind) > $@",
|
||||
tools = [":gen_cp_model_builder_pybind"],
|
||||
)
|
||||
|
||||
pybind_extension(
|
||||
name = "cp_model_builder",
|
||||
srcs = [
|
||||
"cp_model_builder_pybind.cc",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//ortools/port:proto_utils",
|
||||
"//ortools/sat:cp_model_cc_proto",
|
||||
"@abseil-cpp//absl/base:nullability",
|
||||
"@abseil-cpp//absl/strings",
|
||||
"@protobuf",
|
||||
],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "cp_model_builder_test",
|
||||
srcs = ["cp_model_builder_test.py"],
|
||||
deps = [
|
||||
":cp_model_builder",
|
||||
requirement("absl-py"),
|
||||
"//ortools/sat:cp_model_py_pb2",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gen_sat_parameters_builder_pybind",
|
||||
srcs = ["gen_sat_parameters_builder_pybind.cc"],
|
||||
deps = [
|
||||
":wrappers",
|
||||
"//ortools/base",
|
||||
"//ortools/sat:sat_parameters_cc_proto",
|
||||
"@abseil-cpp//absl/log:die_if_null",
|
||||
"@abseil-cpp//absl/strings:str_format",
|
||||
@@ -113,34 +70,15 @@ cc_binary(
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "run_gen_sat_parameters_builder_pybind",
|
||||
outs = ["sat_parameters_builder_pybind.cc"],
|
||||
cmd = "$(location :gen_sat_parameters_builder_pybind) > $@",
|
||||
tools = [":gen_sat_parameters_builder_pybind"],
|
||||
name = "run_gen_proto_builder_pybind11",
|
||||
outs = ["proto_builder_pybind11.h"],
|
||||
cmd = "$(location :gen_proto_builder_pybind11) > $@",
|
||||
tools = [":gen_proto_builder_pybind11"],
|
||||
)
|
||||
|
||||
pybind_extension(
|
||||
name = "sat_parameters_builder",
|
||||
srcs = [
|
||||
"sat_parameters_builder_pybind.cc",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//ortools/port:proto_utils",
|
||||
"//ortools/sat:sat_parameters_cc_proto",
|
||||
"@abseil-cpp//absl/base:nullability",
|
||||
"@abseil-cpp//absl/strings",
|
||||
"@protobuf",
|
||||
],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "sat_parameters_builder_test",
|
||||
srcs = ["sat_parameters_builder_test.py"],
|
||||
deps = [
|
||||
":sat_parameters_builder",
|
||||
requirement("absl-py"),
|
||||
],
|
||||
cc_library(
|
||||
name = "proto_builder_pybind11",
|
||||
hdrs = ["proto_builder_pybind11.h"],
|
||||
)
|
||||
|
||||
pybind_extension(
|
||||
@@ -150,6 +88,7 @@ pybind_extension(
|
||||
deps = [
|
||||
":linear_expr",
|
||||
":linear_expr_doc",
|
||||
":proto_builder_pybind11",
|
||||
"//ortools/sat:cp_model_cc_proto",
|
||||
"//ortools/sat:cp_model_utils",
|
||||
"//ortools/sat:sat_parameters_cc_proto",
|
||||
@@ -162,9 +101,7 @@ py_test(
|
||||
name = "cp_model_helper_test",
|
||||
srcs = ["cp_model_helper_test.py"],
|
||||
deps = [
|
||||
":cp_model_builder",
|
||||
":cp_model_helper",
|
||||
":sat_parameters_builder",
|
||||
"//ortools/util/python:sorted_interval_list",
|
||||
requirement("absl-py"),
|
||||
],
|
||||
@@ -175,9 +112,7 @@ py_library(
|
||||
srcs = ["cp_model.py"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":cp_model_builder",
|
||||
":cp_model_helper",
|
||||
":sat_parameters_builder",
|
||||
requirement("numpy"),
|
||||
requirement("pandas"),
|
||||
"//ortools/util/python:sorted_interval_list",
|
||||
|
||||
@@ -26,12 +26,12 @@ target_link_libraries(${WRAPPERS_NAME} PUBLIC
|
||||
protobuf::libprotobuf)
|
||||
add_library(${PROJECT_NAMESPACE}::${WRAPPERS_NAME} ALIAS ${WRAPPERS_NAME})
|
||||
|
||||
# gen_cp_model_builder_pybind code generator.
|
||||
add_executable(gen_cp_model_builder_pybind)
|
||||
target_sources(gen_cp_model_builder_pybind PRIVATE "gen_cp_model_builder_pybind.cc")
|
||||
target_include_directories(gen_cp_model_builder_pybind PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_compile_features(gen_cp_model_builder_pybind PRIVATE cxx_std_17)
|
||||
target_link_libraries(gen_cp_model_builder_pybind PRIVATE
|
||||
# gen_proto_builder_pybind11 code generator.
|
||||
add_executable(gen_proto_builder_pybind11)
|
||||
target_sources(gen_proto_builder_pybind11 PRIVATE "gen_proto_builder_pybind11.cc")
|
||||
target_include_directories(gen_proto_builder_pybind11 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_compile_features(gen_proto_builder_pybind11 PRIVATE cxx_std_17)
|
||||
target_link_libraries(gen_proto_builder_pybind11 PRIVATE
|
||||
absl::flags_commandlineflag
|
||||
absl::flags_parse
|
||||
absl::flags_usage
|
||||
@@ -43,101 +43,25 @@ target_link_libraries(gen_cp_model_builder_pybind PRIVATE
|
||||
|
||||
include(GNUInstallDirs)
|
||||
if(APPLE)
|
||||
set_target_properties(gen_cp_model_builder_pybind PROPERTIES INSTALL_RPATH
|
||||
set_target_properties(gen_proto_builder_pybind11 PROPERTIES INSTALL_RPATH
|
||||
"@loader_path/../${CMAKE_INSTALL_LIBDIR};@loader_path")
|
||||
elseif(UNIX)
|
||||
cmake_path(RELATIVE_PATH CMAKE_INSTALL_FULL_LIBDIR
|
||||
BASE_DIRECTORY ${CMAKE_INSTALL_FULL_BINDIR}
|
||||
OUTPUT_VARIABLE libdir_relative_path)
|
||||
set_target_properties(gen_cp_model_builder_pybind PROPERTIES
|
||||
set_target_properties(gen_proto_builder_pybind11 PROPERTIES
|
||||
INSTALL_RPATH "$ORIGIN/${libdir_relative_path}")
|
||||
endif()
|
||||
|
||||
install(TARGETS gen_cp_model_builder_pybind)
|
||||
install(TARGETS gen_proto_builder_pybind11)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT cp_model_builder_pybind.cc
|
||||
COMMAND gen_cp_model_builder_pybind > cp_model_builder_pybind.cc
|
||||
COMMENT "Generate C++ cp_model_builder_pybind.cc"
|
||||
OUTPUT proto_builder_pybind11.h
|
||||
COMMAND gen_proto_builder_pybind11 > proto_builder_pybind11.h
|
||||
COMMENT "Generate C++ proto_builder_pybind11.h"
|
||||
VERBATIM)
|
||||
|
||||
# gen_sat_parameters_builder_pybind code generator.
|
||||
add_executable(gen_sat_parameters_builder_pybind)
|
||||
target_sources(gen_sat_parameters_builder_pybind PRIVATE "gen_sat_parameters_builder_pybind.cc")
|
||||
target_include_directories(gen_sat_parameters_builder_pybind PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_compile_features(gen_sat_parameters_builder_pybind PRIVATE cxx_std_17)
|
||||
target_link_libraries(gen_sat_parameters_builder_pybind PRIVATE
|
||||
absl::flags_commandlineflag
|
||||
absl::flags_parse
|
||||
absl::flags_usage
|
||||
absl::die_if_null
|
||||
absl::str_format
|
||||
protobuf::libprotobuf
|
||||
${PROJECT_NAMESPACE}::ortools_proto
|
||||
${PROJECT_NAMESPACE}::${WRAPPERS_NAME})
|
||||
|
||||
include(GNUInstallDirs)
|
||||
if(APPLE)
|
||||
set_target_properties(gen_sat_parameters_builder_pybind PROPERTIES INSTALL_RPATH
|
||||
"@loader_path/../${CMAKE_INSTALL_LIBDIR};@loader_path")
|
||||
elseif(UNIX)
|
||||
cmake_path(RELATIVE_PATH CMAKE_INSTALL_FULL_LIBDIR
|
||||
BASE_DIRECTORY ${CMAKE_INSTALL_FULL_BINDIR}
|
||||
OUTPUT_VARIABLE libdir_relative_path)
|
||||
set_target_properties(gen_sat_parameters_builder_pybind PROPERTIES
|
||||
INSTALL_RPATH "$ORIGIN/${libdir_relative_path}")
|
||||
endif()
|
||||
|
||||
install(TARGETS gen_sat_parameters_builder_pybind)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT sat_parameters_builder_pybind.cc
|
||||
COMMAND gen_sat_parameters_builder_pybind > sat_parameters_builder_pybind.cc
|
||||
COMMENT "Generate C++ sat_parameters_builder_pybind.cc"
|
||||
VERBATIM)
|
||||
|
||||
# Generate both pybind extensins (cp_model_builder and sat_parameters_builder).
|
||||
pybind11_add_module(cp_model_builder_pybind MODULE cp_model_builder_pybind.cc)
|
||||
set_target_properties(cp_model_builder_pybind PROPERTIES
|
||||
LIBRARY_OUTPUT_NAME "cp_model_builder")
|
||||
|
||||
# note: macOS is APPLE and also UNIX !
|
||||
if(APPLE)
|
||||
set_target_properties(cp_model_builder_pybind PROPERTIES
|
||||
SUFFIX ".so"
|
||||
INSTALL_RPATH "@loader_path;@loader_path/../../../${PYTHON_PROJECT}/.libs")
|
||||
elseif(UNIX)
|
||||
set_target_properties(cp_model_builder_pybind PROPERTIES
|
||||
INSTALL_RPATH "$ORIGIN:$ORIGIN/../../../${PYTHON_PROJECT}/.libs")
|
||||
endif()
|
||||
target_link_libraries(cp_model_builder_pybind PRIVATE
|
||||
${PROJECT_NAMESPACE}::ortools
|
||||
protobuf::libprotobuf)
|
||||
|
||||
target_include_directories(cp_model_builder_pybind PRIVATE ${protobuf_SOURCE_DIR})
|
||||
add_library(${PROJECT_NAMESPACE}::cp_model_builder_pybind ALIAS cp_model_builder_pybind)
|
||||
|
||||
pybind11_add_module(sat_parameters_builder_pybind MODULE sat_parameters_builder_pybind.cc)
|
||||
set_target_properties(sat_parameters_builder_pybind PROPERTIES
|
||||
LIBRARY_OUTPUT_NAME "sat_parameters_builder")
|
||||
|
||||
# note: macOS is APPLE and also UNIX !
|
||||
if(APPLE)
|
||||
set_target_properties(sat_parameters_builder_pybind PROPERTIES
|
||||
SUFFIX ".so"
|
||||
INSTALL_RPATH "@loader_path;@loader_path/../../../${PYTHON_PROJECT}/.libs")
|
||||
elseif(UNIX)
|
||||
set_target_properties(sat_parameters_builder_pybind PROPERTIES
|
||||
INSTALL_RPATH "$ORIGIN:$ORIGIN/../../../${PYTHON_PROJECT}/.libs")
|
||||
endif()
|
||||
target_link_libraries(sat_parameters_builder_pybind PRIVATE
|
||||
${PROJECT_NAMESPACE}::ortools
|
||||
protobuf::libprotobuf)
|
||||
|
||||
target_include_directories(sat_parameters_builder_pybind PRIVATE ${protobuf_SOURCE_DIR})
|
||||
add_library(${PROJECT_NAMESPACE}::sat_parameters_builder_pybind ALIAS sat_parameters_builder_pybind)
|
||||
|
||||
pybind11_add_module(cp_model_helper_pybind11 MODULE cp_model_helper.cc)
|
||||
pybind11_add_module(cp_model_helper_pybind11 MODULE cp_model_helper.cc proto_builder_pybind11.h)
|
||||
set_target_properties(cp_model_helper_pybind11 PROPERTIES
|
||||
LIBRARY_OUTPUT_NAME "cp_model_helper")
|
||||
|
||||
|
||||
@@ -64,14 +64,7 @@ import warnings
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
# Make sure the generated cp_model_helper is imported before the builder
|
||||
# modules as the import duplicates versions of the protobufs.
|
||||
from ortools.sat.python import (
|
||||
cp_model_helper as cmh,
|
||||
) # pylint: disable=g-bad-import-order
|
||||
|
||||
from ortools.sat.python import cp_model_builder as cmb
|
||||
from ortools.sat.python import sat_parameters_builder as spb
|
||||
from ortools.sat.python import cp_model_helper as cmh
|
||||
from ortools.util.python import sorted_interval_list
|
||||
|
||||
# Import external types.
|
||||
@@ -82,6 +75,10 @@ FlatIntExpr = cmh.FlatIntExpr
|
||||
LinearExpr = cmh.LinearExpr
|
||||
IntVar = cmh.IntVar
|
||||
NotBooleanVariable = cmh.NotBooleanVariable
|
||||
CpModelProto = cmh.CpModelProto
|
||||
CpSolverStatus = cmh.CpSolverStatus
|
||||
CpSolverResponse = cmh.CpSolverResponse
|
||||
SatParameters = cmh.SatParameters
|
||||
|
||||
|
||||
# The classes below allow linear expressions to be expressed naturally with the
|
||||
@@ -94,52 +91,52 @@ INT32_MIN = -(2**31)
|
||||
INT32_MAX = 2**31 - 1
|
||||
|
||||
# CpSolver status (exported to avoid importing cp_model_cp2).
|
||||
UNKNOWN = cmb.CpSolverStatus.UNKNOWN
|
||||
UNKNOWN = cmb.CpSolverStatus.UNKNOWN
|
||||
MODEL_INVALID = cmb.CpSolverStatus.MODEL_INVALID
|
||||
FEASIBLE = cmb.CpSolverStatus.FEASIBLE
|
||||
INFEASIBLE = cmb.CpSolverStatus.INFEASIBLE
|
||||
OPTIMAL = cmb.CpSolverStatus.OPTIMAL
|
||||
UNKNOWN = cmh.CpSolverStatus.UNKNOWN
|
||||
UNKNOWN = cmh.CpSolverStatus.UNKNOWN
|
||||
MODEL_INVALID = cmh.CpSolverStatus.MODEL_INVALID
|
||||
FEASIBLE = cmh.CpSolverStatus.FEASIBLE
|
||||
INFEASIBLE = cmh.CpSolverStatus.INFEASIBLE
|
||||
OPTIMAL = cmh.CpSolverStatus.OPTIMAL
|
||||
|
||||
# Variable selection strategy
|
||||
CHOOSE_FIRST = cmb.DecisionStrategyProto.VariableSelectionStrategy.CHOOSE_FIRST
|
||||
CHOOSE_FIRST = cmh.DecisionStrategyProto.VariableSelectionStrategy.CHOOSE_FIRST
|
||||
CHOOSE_LOWEST_MIN = (
|
||||
cmb.DecisionStrategyProto.VariableSelectionStrategy.CHOOSE_LOWEST_MIN
|
||||
cmh.DecisionStrategyProto.VariableSelectionStrategy.CHOOSE_LOWEST_MIN
|
||||
)
|
||||
CHOOSE_HIGHEST_MAX = (
|
||||
cmb.DecisionStrategyProto.VariableSelectionStrategy.CHOOSE_HIGHEST_MAX
|
||||
cmh.DecisionStrategyProto.VariableSelectionStrategy.CHOOSE_HIGHEST_MAX
|
||||
)
|
||||
CHOOSE_MIN_DOMAIN_SIZE = (
|
||||
cmb.DecisionStrategyProto.VariableSelectionStrategy.CHOOSE_MIN_DOMAIN_SIZE
|
||||
cmh.DecisionStrategyProto.VariableSelectionStrategy.CHOOSE_MIN_DOMAIN_SIZE
|
||||
)
|
||||
CHOOSE_MAX_DOMAIN_SIZE = (
|
||||
cmb.DecisionStrategyProto.VariableSelectionStrategy.CHOOSE_MAX_DOMAIN_SIZE
|
||||
cmh.DecisionStrategyProto.VariableSelectionStrategy.CHOOSE_MAX_DOMAIN_SIZE
|
||||
)
|
||||
|
||||
# Domain reduction strategy
|
||||
SELECT_MIN_VALUE = cmb.DecisionStrategyProto.DomainReductionStrategy.SELECT_MIN_VALUE
|
||||
SELECT_MAX_VALUE = cmb.DecisionStrategyProto.DomainReductionStrategy.SELECT_MAX_VALUE
|
||||
SELECT_LOWER_HALF = cmb.DecisionStrategyProto.DomainReductionStrategy.SELECT_LOWER_HALF
|
||||
SELECT_UPPER_HALF = cmb.DecisionStrategyProto.DomainReductionStrategy.SELECT_UPPER_HALF
|
||||
SELECT_MIN_VALUE = cmh.DecisionStrategyProto.DomainReductionStrategy.SELECT_MIN_VALUE
|
||||
SELECT_MAX_VALUE = cmh.DecisionStrategyProto.DomainReductionStrategy.SELECT_MAX_VALUE
|
||||
SELECT_LOWER_HALF = cmh.DecisionStrategyProto.DomainReductionStrategy.SELECT_LOWER_HALF
|
||||
SELECT_UPPER_HALF = cmh.DecisionStrategyProto.DomainReductionStrategy.SELECT_UPPER_HALF
|
||||
SELECT_MEDIAN_VALUE = (
|
||||
cmb.DecisionStrategyProto.DomainReductionStrategy.SELECT_MEDIAN_VALUE
|
||||
cmh.DecisionStrategyProto.DomainReductionStrategy.SELECT_MEDIAN_VALUE
|
||||
)
|
||||
SELECT_RANDOM_HALF = (
|
||||
cmb.DecisionStrategyProto.DomainReductionStrategy.SELECT_RANDOM_HALF
|
||||
cmh.DecisionStrategyProto.DomainReductionStrategy.SELECT_RANDOM_HALF
|
||||
)
|
||||
|
||||
# Search branching
|
||||
AUTOMATIC_SEARCH = spb.SatParameters.SearchBranching.AUTOMATIC_SEARCH
|
||||
FIXED_SEARCH = spb.SatParameters.SearchBranching.FIXED_SEARCH
|
||||
PORTFOLIO_SEARCH = spb.SatParameters.SearchBranching.PORTFOLIO_SEARCH
|
||||
LP_SEARCH = spb.SatParameters.SearchBranching.LP_SEARCH
|
||||
PSEUDO_COST_SEARCH = spb.SatParameters.SearchBranching.PSEUDO_COST_SEARCH
|
||||
AUTOMATIC_SEARCH = cmh.SatParameters.SearchBranching.AUTOMATIC_SEARCH
|
||||
FIXED_SEARCH = cmh.SatParameters.SearchBranching.FIXED_SEARCH
|
||||
PORTFOLIO_SEARCH = cmh.SatParameters.SearchBranching.PORTFOLIO_SEARCH
|
||||
LP_SEARCH = cmh.SatParameters.SearchBranching.LP_SEARCH
|
||||
PSEUDO_COST_SEARCH = cmh.SatParameters.SearchBranching.PSEUDO_COST_SEARCH
|
||||
PORTFOLIO_WITH_QUICK_RESTART_SEARCH = (
|
||||
spb.SatParameters.SearchBranching.PORTFOLIO_WITH_QUICK_RESTART_SEARCH
|
||||
cmh.SatParameters.SearchBranching.PORTFOLIO_WITH_QUICK_RESTART_SEARCH
|
||||
)
|
||||
HINT_SEARCH = spb.SatParameters.SearchBranching.HINT_SEARCH
|
||||
PARTIAL_FIXED_SEARCH = spb.SatParameters.SearchBranching.PARTIAL_FIXED_SEARCH
|
||||
RANDOMIZED_SEARCH = spb.SatParameters.SearchBranching.RANDOMIZED_SEARCH
|
||||
HINT_SEARCH = cmh.SatParameters.SearchBranching.HINT_SEARCH
|
||||
PARTIAL_FIXED_SEARCH = cmh.SatParameters.SearchBranching.PARTIAL_FIXED_SEARCH
|
||||
RANDOMIZED_SEARCH = cmh.SatParameters.SearchBranching.RANDOMIZED_SEARCH
|
||||
|
||||
# Type aliases
|
||||
IntegralT = Union[int, np.int8, np.uint8, np.int32, np.uint32, np.int64, np.uint64]
|
||||
@@ -187,7 +184,7 @@ ArcT = Tuple[IntegralT, IntegralT, LiteralT]
|
||||
_IndexOrSeries = Union[pd.Index, pd.Series]
|
||||
|
||||
|
||||
def short_name(model: cmb.CpModelProto, i: int) -> str:
|
||||
def short_name(model: cmh.CpModelProto, i: int) -> str:
|
||||
"""Returns a short name of an integer variable, or its negation."""
|
||||
if i >= 0:
|
||||
return str(IntVar(model, i))
|
||||
@@ -196,8 +193,8 @@ def short_name(model: cmb.CpModelProto, i: int) -> str:
|
||||
|
||||
|
||||
def short_expr_name(
|
||||
model: cmb.CpModelProto,
|
||||
e: cmb.LinearExpressionProto,
|
||||
model: cmh.CpModelProto,
|
||||
e: cmh.LinearExpressionProto,
|
||||
) -> str:
|
||||
"""Pretty-print LinearExpressionProto instances."""
|
||||
if not e.vars:
|
||||
@@ -231,8 +228,8 @@ def arg_is_boolean(x: Any) -> bool:
|
||||
|
||||
|
||||
def rebuild_from_linear_expression_proto(
|
||||
proto: cmb.LinearExpressionProto,
|
||||
model_proto: cmb.CpModelProto,
|
||||
proto: cmh.LinearExpressionProto,
|
||||
model_proto: cmh.CpModelProto,
|
||||
) -> LinearExprT:
|
||||
"""Recreate a LinearExpr from a LinearExpressionProto."""
|
||||
num_elements = len(proto.vars)
|
||||
@@ -344,7 +341,7 @@ class Constraint:
|
||||
return self.__index
|
||||
|
||||
@property
|
||||
def proto(self) -> cmb.ConstraintProto:
|
||||
def proto(self) -> cmh.ConstraintProto:
|
||||
"""Returns the constraint protobuf."""
|
||||
return self.__cp_model.proto.constraints[self.__index]
|
||||
|
||||
@@ -365,7 +362,7 @@ class Constraint:
|
||||
def Index(self) -> int:
|
||||
return self.index
|
||||
|
||||
def Proto(self) -> cmb.ConstraintProto:
|
||||
def Proto(self) -> cmh.ConstraintProto:
|
||||
return self.proto
|
||||
|
||||
# pylint: enable=invalid-name
|
||||
@@ -394,16 +391,16 @@ class IntervalVar:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
model: cmb.CpModelProto,
|
||||
start: Union[cmb.LinearExpressionProto, int],
|
||||
size: Optional[cmb.LinearExpressionProto],
|
||||
end: Optional[cmb.LinearExpressionProto],
|
||||
model: cmh.CpModelProto,
|
||||
start: Union[cmh.LinearExpressionProto, int],
|
||||
size: Optional[cmh.LinearExpressionProto],
|
||||
end: Optional[cmh.LinearExpressionProto],
|
||||
is_present_index: Optional[int],
|
||||
name: Optional[str],
|
||||
) -> None:
|
||||
self.__model: cmb.CpModelProto = model
|
||||
self.__model: cmh.CpModelProto = model
|
||||
self.__index: int
|
||||
self.__ct: cmb.ConstraintProto
|
||||
self.__ct: cmh.ConstraintProto
|
||||
# As with the IntVar::__init__ method, we hack the __init__ method to
|
||||
# support two use cases:
|
||||
# case 1: called when creating a new interval variable.
|
||||
@@ -443,12 +440,12 @@ class IntervalVar:
|
||||
return self.__index
|
||||
|
||||
@property
|
||||
def proto(self) -> cmb.ConstraintProto:
|
||||
def proto(self) -> cmh.ConstraintProto:
|
||||
"""Returns the interval protobuf."""
|
||||
return self.__model.constraints[self.__index]
|
||||
|
||||
@property
|
||||
def model_proto(self) -> cmb.CpModelProto:
|
||||
def model_proto(self) -> cmh.CpModelProto:
|
||||
"""Returns the model protobuf."""
|
||||
return self.__model
|
||||
|
||||
@@ -502,7 +499,7 @@ class IntervalVar:
|
||||
def Index(self) -> int:
|
||||
return self.index
|
||||
|
||||
def Proto(self) -> cmb.ConstraintProto:
|
||||
def Proto(self) -> cmh.ConstraintProto:
|
||||
return self.proto
|
||||
|
||||
StartExpr = start_expr
|
||||
@@ -548,7 +545,7 @@ class CpModel:
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.__model: cmb.CpModelProto = cmb.CpModelProto()
|
||||
self.__model: cmh.CpModelProto = cmh.CpModelProto()
|
||||
self.__constant_map: Dict[IntegralT, int] = {}
|
||||
|
||||
# Naming.
|
||||
@@ -1966,7 +1963,7 @@ class CpModel:
|
||||
return str(self.__model)
|
||||
|
||||
@property
|
||||
def proto(self) -> cmb.CpModelProto:
|
||||
def proto(self) -> cmh.CpModelProto:
|
||||
"""Returns the underlying CpModelProto."""
|
||||
return self.__model
|
||||
|
||||
@@ -2022,9 +2019,9 @@ class CpModel:
|
||||
|
||||
def parse_linear_expression(
|
||||
self, linear_expr: LinearExprT, negate: bool = False
|
||||
) -> cmb.LinearExpressionProto:
|
||||
) -> cmh.LinearExpressionProto:
|
||||
"""Returns a LinearExpressionProto built from a LinearExpr instance."""
|
||||
result: cmb.LinearExpressionProto = cmb.LinearExpressionProto()
|
||||
result: cmh.LinearExpressionProto = cmh.LinearExpressionProto()
|
||||
mult = -1 if negate else 1
|
||||
if isinstance(linear_expr, IntegralTypes):
|
||||
result.offset = int(linear_expr) * mult
|
||||
@@ -2091,8 +2088,8 @@ class CpModel:
|
||||
def add_decision_strategy(
|
||||
self,
|
||||
variables: Sequence[IntVar],
|
||||
var_strategy: cmb.DecisionStrategyProto.VariableSelectionStrategy,
|
||||
domain_strategy: cmb.DecisionStrategyProto.DomainReductionStrategy,
|
||||
var_strategy: cmh.DecisionStrategyProto.VariableSelectionStrategy,
|
||||
domain_strategy: cmh.DecisionStrategyProto.DomainReductionStrategy,
|
||||
) -> None:
|
||||
"""Adds a search strategy to the model.
|
||||
|
||||
@@ -2105,7 +2102,7 @@ class CpModel:
|
||||
solve() will fail.
|
||||
"""
|
||||
|
||||
strategy: cmb.DecisionStrategyProto = self.__model.search_strategy.add()
|
||||
strategy: cmh.DecisionStrategyProto = self.__model.search_strategy.add()
|
||||
for v in variables:
|
||||
expr = strategy.exprs.add()
|
||||
if v.index >= 0:
|
||||
@@ -2223,7 +2220,7 @@ class CpModel:
|
||||
def SetName(self, name: str) -> None:
|
||||
self.name = name
|
||||
|
||||
def Proto(self) -> cmb.CpModelProto:
|
||||
def Proto(self) -> cmh.CpModelProto:
|
||||
return self.proto
|
||||
|
||||
NewIntVar = new_int_var
|
||||
@@ -2314,7 +2311,7 @@ class CpSolver:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.__response_wrapper: Optional[cmh.ResponseWrapper] = None
|
||||
self.parameters: spb.SatParameters = spb.SatParameters()
|
||||
self.parameters: cmh.SatParameters = cmh.SatParameters()
|
||||
self.log_callback: Optional[Callable[[str], None]] = None
|
||||
self.best_bound_callback: Optional[Callable[[float], None]] = None
|
||||
self.__solve_wrapper: Optional[cmh.SolveWrapper] = None
|
||||
@@ -2324,7 +2321,7 @@ class CpSolver:
|
||||
self,
|
||||
model: CpModel,
|
||||
solution_callback: Optional["CpSolverSolutionCallback"] = None,
|
||||
) -> cmb.CpSolverStatus:
|
||||
) -> cmh.CpSolverStatus:
|
||||
"""Solves a problem and passes each solution to the callback if not null."""
|
||||
with self.__lock:
|
||||
self.__solve_wrapper = cmh.SolveWrapper()
|
||||
@@ -2497,7 +2494,7 @@ class CpSolver:
|
||||
return self._checked_response.user_time()
|
||||
|
||||
@property
|
||||
def response_proto(self) -> cmb.CpSolverResponse:
|
||||
def response_proto(self) -> cmh.CpSolverResponse:
|
||||
"""Returns the response object."""
|
||||
return self._checked_response.response()
|
||||
|
||||
@@ -2557,7 +2554,7 @@ class CpSolver:
|
||||
def ObjectiveValue(self) -> float:
|
||||
return self.objective_value
|
||||
|
||||
def ResponseProto(self) -> cmb.CpSolverResponse:
|
||||
def ResponseProto(self) -> cmh.CpSolverResponse:
|
||||
return self.response_proto
|
||||
|
||||
def ResponseStats(self) -> str:
|
||||
@@ -2567,7 +2564,7 @@ class CpSolver:
|
||||
self,
|
||||
model: CpModel,
|
||||
solution_callback: Optional["CpSolverSolutionCallback"] = None,
|
||||
) -> cmb.CpSolverStatus:
|
||||
) -> cmh.CpSolverStatus:
|
||||
return self.solve(model, solution_callback)
|
||||
|
||||
def SolutionInfo(self) -> str:
|
||||
@@ -2596,7 +2593,7 @@ class CpSolver:
|
||||
|
||||
def SolveWithSolutionCallback(
|
||||
self, model: CpModel, callback: "CpSolverSolutionCallback"
|
||||
) -> cmb.CpSolverStatus:
|
||||
) -> cmh.CpSolverStatus:
|
||||
"""DEPRECATED Use solve() with the callback argument."""
|
||||
warnings.warn(
|
||||
"solve_with_solution_callback is deprecated; use solve() with"
|
||||
@@ -2607,7 +2604,7 @@ class CpSolver:
|
||||
|
||||
def SearchForAllSolutions(
|
||||
self, model: CpModel, callback: "CpSolverSolutionCallback"
|
||||
) -> cmb.CpSolverStatus:
|
||||
) -> cmh.CpSolverStatus:
|
||||
"""DEPRECATED Use solve() with the right parameter.
|
||||
|
||||
Search for all solutions of a satisfiability problem.
|
||||
@@ -2641,7 +2638,7 @@ class CpSolver:
|
||||
enumerate_all = self.parameters.enumerate_all_solutions
|
||||
self.parameters.enumerate_all_solutions = True
|
||||
|
||||
status: cmb.CpSolverStatus = self.solve(model, callback)
|
||||
status: cmh.CpSolverStatus = self.solve(model, callback)
|
||||
|
||||
# Restore parameter.
|
||||
self.parameters.enumerate_all_solutions = enumerate_all
|
||||
@@ -2802,7 +2799,7 @@ class CpSolverSolutionCallback(cmh.SolutionCallback):
|
||||
return self.UserTime()
|
||||
|
||||
@property
|
||||
def response_proto(self) -> cmb.CpSolverResponse:
|
||||
def response_proto(self) -> cmh.CpSolverResponse:
|
||||
"""Returns the response object."""
|
||||
if not self.has_response():
|
||||
raise RuntimeError("solve() has not been called.")
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2010-2025 Google LLC
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from absl.testing import absltest
|
||||
from ortools.sat import cp_model_pb2
|
||||
from ortools.sat.python import cp_model_builder
|
||||
|
||||
|
||||
class CpModelBuilderTest(absltest.TestCase):
|
||||
|
||||
def test_basic(self):
|
||||
model_proto = cp_model_builder.CpModelProto()
|
||||
|
||||
# Singular message.
|
||||
objective = model_proto.objective
|
||||
|
||||
# Singular int.
|
||||
self.assertEqual(objective.offset, 0)
|
||||
objective.offset = 123
|
||||
self.assertEqual(objective.offset, 123)
|
||||
|
||||
# Set a message.
|
||||
new_obj = cp_model_builder.CpObjectiveProto()
|
||||
new_obj.offset = 456
|
||||
model_proto.objective = new_obj
|
||||
self.assertEqual(objective.offset, 456)
|
||||
|
||||
# Large int.
|
||||
objective.offset = 500000000000
|
||||
self.assertEqual(objective.offset, 500000000000)
|
||||
|
||||
# Repeated message.
|
||||
my_var = model_proto.variables.add()
|
||||
|
||||
# Singular string.
|
||||
self.assertEqual(my_var.name, "")
|
||||
my_var.name = "my_var"
|
||||
self.assertEqual(my_var.name, "my_var")
|
||||
my_var.domain.extend([0, 1])
|
||||
domain = list(my_var.domain)
|
||||
self.assertLen(domain, 2)
|
||||
self.assertEqual(domain[0], 0)
|
||||
self.assertEqual(domain[1], 1)
|
||||
|
||||
# Repeated int.
|
||||
objective.vars.append(0)
|
||||
self.assertLen(objective.vars, 1)
|
||||
self.assertEqual(objective.vars[0], 0)
|
||||
objective.vars[0] = 42
|
||||
self.assertEqual(objective.vars[0], 42)
|
||||
|
||||
# Singular enum
|
||||
search_strategy = model_proto.search_strategy.add()
|
||||
self.assertEqual(
|
||||
search_strategy.variable_selection_strategy,
|
||||
cp_model_builder.DecisionStrategyProto.CHOOSE_FIRST,
|
||||
)
|
||||
search_strategy.variable_selection_strategy = (
|
||||
cp_model_builder.DecisionStrategyProto.CHOOSE_LOWEST_MIN
|
||||
)
|
||||
self.assertEqual(
|
||||
search_strategy.variable_selection_strategy,
|
||||
cp_model_pb2.DecisionStrategyProto.CHOOSE_LOWEST_MIN,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
absltest.main()
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "absl/functional/any_invocable.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "ortools/port/proto_utils.h" // IWYU: keep
|
||||
#include "ortools/sat/cp_model.pb.h"
|
||||
#include "ortools/sat/cp_model_utils.h"
|
||||
#include "ortools/sat/python/linear_expr.h"
|
||||
@@ -500,8 +501,6 @@ void ClearCtName(int index, std::shared_ptr<CpModelProto> model_proto) {
|
||||
}
|
||||
|
||||
PYBIND11_MODULE(cp_model_helper, m) {
|
||||
py::module::import("ortools.sat.python.cp_model_builder");
|
||||
py::module::import("ortools.sat.python.sat_parameters_builder");
|
||||
py::module::import("ortools.util.python.sorted_interval_list");
|
||||
|
||||
// We keep the CamelCase name for the SolutionCallback class to be
|
||||
@@ -1303,6 +1302,9 @@ PYBIND11_MODULE(cp_model_helper, m) {
|
||||
"not supported."));
|
||||
return false;
|
||||
});
|
||||
#define IMPORT_PROTO_WRAPPER_CODE
|
||||
#include "ortools/sat/python/proto_builder_pybind11.h"
|
||||
#undef IMPORT_PROTO_WRAPPER_CODE
|
||||
} // NOLINT(readability/fn_size)
|
||||
|
||||
} // namespace operations_research::sat::python
|
||||
|
||||
@@ -18,9 +18,7 @@ import sys
|
||||
|
||||
from absl.testing import absltest
|
||||
|
||||
from ortools.sat.python import cp_model_builder
|
||||
from ortools.sat.python import cp_model_helper as cmh
|
||||
from ortools.sat.python import sat_parameters_builder
|
||||
from ortools.util.python import sorted_interval_list
|
||||
|
||||
|
||||
@@ -58,7 +56,7 @@ class CpModelHelperTest(absltest.TestCase):
|
||||
variables { domain: [ -10, 10 ] }
|
||||
variables { domain: [ -5, -5, 3, 6 ] }
|
||||
"""
|
||||
model = cp_model_builder.CpModelProto()
|
||||
model = cmh.CpModelProto()
|
||||
self.assertTrue(model.parse_text_format(model_string))
|
||||
|
||||
d0 = cmh.CpSatHelper.variable_domain(model.variables[0])
|
||||
@@ -99,13 +97,13 @@ class CpModelHelperTest(absltest.TestCase):
|
||||
coeffs: -1
|
||||
scaling_factor: -1
|
||||
}"""
|
||||
model = cp_model_builder.CpModelProto()
|
||||
model = cmh.CpModelProto()
|
||||
self.assertTrue(model.parse_text_format(model_string))
|
||||
|
||||
solve_wrapper = cmh.SolveWrapper()
|
||||
response_wrapper = solve_wrapper.solve_and_return_response_wrapper(model)
|
||||
|
||||
self.assertEqual(cp_model_builder.OPTIMAL, response_wrapper.status())
|
||||
self.assertEqual(cmh.OPTIMAL, response_wrapper.status())
|
||||
self.assertEqual(30.0, response_wrapper.objective_value())
|
||||
|
||||
def test_simple_solve_with_core(self):
|
||||
@@ -140,21 +138,21 @@ class CpModelHelperTest(absltest.TestCase):
|
||||
coeffs: -1
|
||||
scaling_factor: -1
|
||||
}"""
|
||||
model = cp_model_builder.CpModelProto()
|
||||
model = cmh.CpModelProto()
|
||||
self.assertTrue(model.parse_text_format(model_string))
|
||||
|
||||
parameters = sat_parameters_builder.SatParameters()
|
||||
parameters = cmh.SatParameters()
|
||||
parameters.optimize_with_core = True
|
||||
|
||||
solve_wrapper = cmh.SolveWrapper()
|
||||
solve_wrapper.set_parameters(parameters)
|
||||
response_wrapper = solve_wrapper.solve_and_return_response_wrapper(model)
|
||||
|
||||
self.assertEqual(cp_model_builder.OPTIMAL, response_wrapper.status())
|
||||
self.assertEqual(cmh.OPTIMAL, response_wrapper.status())
|
||||
self.assertEqual(30.0, response_wrapper.objective_value())
|
||||
|
||||
def test_simple_solve_with_proto_api(self):
|
||||
model = cp_model_builder.CpModelProto()
|
||||
model = cmh.CpModelProto()
|
||||
x = model.variables.add()
|
||||
x.domain.extend([-10, 10])
|
||||
y = model.variables.add()
|
||||
@@ -172,7 +170,7 @@ class CpModelHelperTest(absltest.TestCase):
|
||||
solve_wrapper = cmh.SolveWrapper()
|
||||
response_wrapper = solve_wrapper.solve_and_return_response_wrapper(model)
|
||||
|
||||
self.assertEqual(cp_model_builder.OPTIMAL, response_wrapper.status())
|
||||
self.assertEqual(cmh.OPTIMAL, response_wrapper.status())
|
||||
self.assertEqual(30.0, response_wrapper.objective_value())
|
||||
self.assertEqual(30.0, response_wrapper.best_objective_bound())
|
||||
self.assertRaises(TypeError, response_wrapper.value, None)
|
||||
@@ -186,19 +184,19 @@ class CpModelHelperTest(absltest.TestCase):
|
||||
constraints {
|
||||
linear { vars: 0 vars: 1 coeffs: 1 coeffs: 1 domain: 6 domain: 6 } }
|
||||
"""
|
||||
model = cp_model_builder.CpModelProto()
|
||||
model = cmh.CpModelProto()
|
||||
self.assertTrue(model.parse_text_format(model_string))
|
||||
|
||||
solve_wrapper = cmh.SolveWrapper()
|
||||
callback = Callback()
|
||||
solve_wrapper.add_solution_callback(callback)
|
||||
params = sat_parameters_builder.SatParameters()
|
||||
params = cmh.SatParameters()
|
||||
params.enumerate_all_solutions = True
|
||||
solve_wrapper.set_parameters(params)
|
||||
response_wrapper = solve_wrapper.solve_and_return_response_wrapper(model)
|
||||
|
||||
self.assertEqual(5, callback.solution_count())
|
||||
self.assertEqual(cp_model_builder.OPTIMAL, response_wrapper.status())
|
||||
self.assertEqual(cmh.OPTIMAL, response_wrapper.status())
|
||||
|
||||
def test_best_bound_callback(self):
|
||||
model_string = """
|
||||
@@ -213,13 +211,13 @@ class CpModelHelperTest(absltest.TestCase):
|
||||
offset: 0.6
|
||||
}
|
||||
"""
|
||||
model = cp_model_builder.CpModelProto()
|
||||
model = cmh.CpModelProto()
|
||||
self.assertTrue(model.parse_text_format(model_string))
|
||||
|
||||
solve_wrapper = cmh.SolveWrapper()
|
||||
best_bound_callback = BestBoundCallback()
|
||||
solve_wrapper.add_best_bound_callback(best_bound_callback.new_best_bound)
|
||||
params = sat_parameters_builder.SatParameters()
|
||||
params = cmh.SatParameters()
|
||||
params.num_workers = 1
|
||||
params.linearization_level = 2
|
||||
params.log_search_progress = True
|
||||
@@ -227,7 +225,7 @@ class CpModelHelperTest(absltest.TestCase):
|
||||
response_wrapper = solve_wrapper.solve_and_return_response_wrapper(model)
|
||||
|
||||
self.assertEqual(2.6, best_bound_callback.best_bound)
|
||||
self.assertEqual(cp_model_builder.OPTIMAL, response_wrapper.status())
|
||||
self.assertEqual(cmh.OPTIMAL, response_wrapper.status())
|
||||
|
||||
def test_model_stats(self):
|
||||
model_string = """
|
||||
@@ -263,13 +261,13 @@ class CpModelHelperTest(absltest.TestCase):
|
||||
}
|
||||
name: 'testModelStats'
|
||||
"""
|
||||
model = cp_model_builder.CpModelProto()
|
||||
model = cmh.CpModelProto()
|
||||
self.assertTrue(model.parse_text_format(model_string))
|
||||
stats = cmh.CpSatHelper.model_stats(model)
|
||||
self.assertTrue(stats)
|
||||
|
||||
def test_int_lin_expr(self):
|
||||
model = cp_model_builder.CpModelProto()
|
||||
model = cmh.CpModelProto()
|
||||
x = cmh.IntVar(model).with_name("x")
|
||||
self.assertTrue(x.is_integer())
|
||||
self.assertIsInstance(x, cmh.IntVar)
|
||||
@@ -316,7 +314,7 @@ class CpModelHelperTest(absltest.TestCase):
|
||||
self.assertEqual(str(e12), "(x + (-y) + (-2 * z))")
|
||||
|
||||
def test_float_lin_expr(self):
|
||||
model = cp_model_builder.CpModelProto()
|
||||
model = cmh.CpModelProto()
|
||||
x = cmh.IntVar(model).with_name("x")
|
||||
self.assertTrue(x.is_integer())
|
||||
self.assertIsInstance(x, cmh.IntVar)
|
||||
@@ -362,5 +360,89 @@ class CpModelHelperTest(absltest.TestCase):
|
||||
self.assertEqual(str(e12), "(3.1 * (x + 2))")
|
||||
|
||||
|
||||
class CpModelBuilderTest(absltest.TestCase):
|
||||
|
||||
def test_basic(self):
|
||||
model_proto = cmh.CpModelProto()
|
||||
|
||||
# Singular message.
|
||||
objective = model_proto.objective
|
||||
|
||||
# Singular int.
|
||||
self.assertEqual(objective.offset, 0)
|
||||
objective.offset = 123
|
||||
self.assertEqual(objective.offset, 123)
|
||||
|
||||
# Set a message.
|
||||
new_obj = cmh.CpObjectiveProto()
|
||||
new_obj.offset = 456
|
||||
model_proto.objective = new_obj
|
||||
self.assertEqual(objective.offset, 456)
|
||||
|
||||
# Large int.
|
||||
objective.offset = 500000000000
|
||||
self.assertEqual(objective.offset, 500000000000)
|
||||
|
||||
# Repeated message.
|
||||
my_var = model_proto.variables.add()
|
||||
|
||||
# Singular string.
|
||||
self.assertEqual(my_var.name, "")
|
||||
my_var.name = "my_var"
|
||||
self.assertEqual(my_var.name, "my_var")
|
||||
my_var.domain.extend([0, 1])
|
||||
domain = list(my_var.domain)
|
||||
self.assertLen(domain, 2)
|
||||
self.assertEqual(domain[0], 0)
|
||||
self.assertEqual(domain[1], 1)
|
||||
|
||||
# Repeated int.
|
||||
objective.vars.append(0)
|
||||
self.assertLen(objective.vars, 1)
|
||||
self.assertEqual(objective.vars[0], 0)
|
||||
objective.vars[0] = 42
|
||||
self.assertEqual(objective.vars[0], 42)
|
||||
|
||||
# Singular enum
|
||||
search_strategy = model_proto.search_strategy.add()
|
||||
self.assertEqual(
|
||||
search_strategy.variable_selection_strategy,
|
||||
cmh.DecisionStrategyProto.CHOOSE_FIRST,
|
||||
)
|
||||
search_strategy.variable_selection_strategy = (
|
||||
cmh.DecisionStrategyProto.CHOOSE_LOWEST_MIN
|
||||
)
|
||||
self.assertEqual(
|
||||
search_strategy.variable_selection_strategy,
|
||||
cmh.DecisionStrategyProto.CHOOSE_LOWEST_MIN,
|
||||
)
|
||||
|
||||
|
||||
class SatParametersBuilderTest(absltest.TestCase):
|
||||
|
||||
def test_basic_api(self) -> None:
|
||||
params = cmh.SatParameters()
|
||||
|
||||
# Test that we can set and get an integer parameter.
|
||||
params.num_workers = 10
|
||||
self.assertEqual(params.num_workers, 10)
|
||||
|
||||
# Test that we can set and get an enum parameter.
|
||||
self.assertEqual(
|
||||
params.clause_cleanup_ordering,
|
||||
cmh.SatParameters.ClauseOrdering.CLAUSE_ACTIVITY,
|
||||
)
|
||||
params.clause_cleanup_ordering = cmh.SatParameters.ClauseOrdering.CLAUSE_LBD
|
||||
self.assertEqual(
|
||||
params.clause_cleanup_ordering,
|
||||
cmh.SatParameters.ClauseOrdering.CLAUSE_LBD,
|
||||
)
|
||||
|
||||
# Test that we can set and get a repeated string parameter.
|
||||
params.subsolvers.append("no_lp")
|
||||
self.assertLen(params.subsolvers, 1)
|
||||
self.assertEqual(params.subsolvers[0], "no_lp")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
absltest.main()
|
||||
|
||||
@@ -22,7 +22,6 @@ import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
from ortools.sat.python import cp_model
|
||||
from ortools.sat.python import cp_model_builder
|
||||
from ortools.sat.python import cp_model_helper as cmh
|
||||
|
||||
|
||||
@@ -585,7 +584,7 @@ class CpModelTest(absltest.TestCase):
|
||||
model.add(3 <= -1)
|
||||
model.minimize(x)
|
||||
solver = cp_model.CpSolver()
|
||||
status: cp_model_builder.CpSolverStatus = solver.solve(model)
|
||||
status: cmh.CpSolverStatus = solver.solve(model)
|
||||
self.assertEqual("INFEASIBLE", status.name)
|
||||
|
||||
def test_sum(self) -> None:
|
||||
@@ -1308,7 +1307,7 @@ class CpModelTest(absltest.TestCase):
|
||||
self.assertEqual(~i.size_expr(), ~y)
|
||||
self.assertRaises(TypeError, i.start_expr().negated)
|
||||
|
||||
proto = cp_model_builder.LinearExpressionProto()
|
||||
proto = cmh.LinearExpressionProto()
|
||||
proto.vars.append(x.index)
|
||||
proto.coeffs.append(1)
|
||||
proto.vars.append(y.index)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "ortools/sat/cp_model.pb.h"
|
||||
#include "ortools/sat/python/wrappers.h"
|
||||
#include "ortools/sat/sat_parameters.pb.h"
|
||||
|
||||
namespace operations_research::sat::python {
|
||||
|
||||
@@ -26,28 +27,13 @@ void ParseAndGenerate() {
|
||||
R"(
|
||||
|
||||
// This is a generated file, do not edit.
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "google/protobuf/text_format.h"
|
||||
#include "pybind11/numpy.h"
|
||||
#include "pybind11/pybind11.h"
|
||||
#include "pybind11/pytypes.h"
|
||||
#include "pybind11/stl.h"
|
||||
#include "ortools/port/proto_utils.h"
|
||||
#include "ortools/sat/cp_model.pb.h"
|
||||
|
||||
namespace py = ::pybind11;
|
||||
|
||||
namespace operations_research::sat::python {
|
||||
|
||||
PYBIND11_MODULE(cp_model_builder, py_module) {
|
||||
#if defined(IMPORT_PROTO_WRAPPER_CODE)
|
||||
%s
|
||||
} // PYBIND11_MODULE
|
||||
|
||||
} // namespace operations_research::sat::python
|
||||
#endif // defined(IMPORT_PROTO_WRAPPER_CODE)
|
||||
)",
|
||||
GeneratePybindCode({ABSL_DIE_IF_NULL(CpModelProto::descriptor()),
|
||||
ABSL_DIE_IF_NULL(CpSolverResponse::descriptor())}));
|
||||
ABSL_DIE_IF_NULL(CpSolverResponse::descriptor()),
|
||||
ABSL_DIE_IF_NULL(SatParameters::descriptor())}));
|
||||
}
|
||||
|
||||
} // namespace operations_research::sat::python
|
||||
@@ -1,59 +0,0 @@
|
||||
// Copyright 2010-2025 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "absl/flags/parse.h"
|
||||
#include "absl/flags/usage.h"
|
||||
#include "absl/log/die_if_null.h"
|
||||
#include "absl/log/initialize.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "ortools/sat/python/wrappers.h"
|
||||
#include "ortools/sat/sat_parameters.pb.h"
|
||||
|
||||
namespace operations_research::sat::python {
|
||||
|
||||
void ParseAndGenerate() {
|
||||
absl::PrintF(
|
||||
R"(
|
||||
|
||||
// This is a generated file, do not edit.
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "google/protobuf/text_format.h"
|
||||
#include "pybind11/numpy.h"
|
||||
#include "pybind11/pybind11.h"
|
||||
#include "pybind11/pytypes.h"
|
||||
#include "pybind11/stl.h"
|
||||
#include "ortools/port/proto_utils.h"
|
||||
#include "ortools/sat/sat_parameters.pb.h"
|
||||
|
||||
namespace py = ::pybind11;
|
||||
namespace operations_research::sat::python {
|
||||
PYBIND11_MODULE(sat_parameters_builder, py_module) {
|
||||
%s
|
||||
} // PYBIND11_MODULE
|
||||
} // namespace operations_research::sat::python
|
||||
)",
|
||||
GeneratePybindCode({ABSL_DIE_IF_NULL(SatParameters::descriptor())}));
|
||||
}
|
||||
|
||||
} // namespace operations_research::sat::python
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// We do not use InitGoogle() to avoid linking with or-tools as this would
|
||||
// create a circular dependency.
|
||||
absl::InitializeLog();
|
||||
absl::SetProgramUsageMessage(argv[0]);
|
||||
absl::ParseCommandLine(argc, argv);
|
||||
operations_research::sat::python::ParseAndGenerate();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2010-2025 Google LLC
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Test sat parameters builder."""
|
||||
|
||||
from absl.testing import absltest
|
||||
from ortools.sat.python import sat_parameters_builder
|
||||
|
||||
|
||||
class SatParametersBuilderTest(absltest.TestCase):
|
||||
|
||||
def test_basic_api(self) -> None:
|
||||
params = sat_parameters_builder.SatParameters()
|
||||
|
||||
# Test that we can set and get an integer parameter.
|
||||
params.num_workers = 10
|
||||
self.assertEqual(params.num_workers, 10)
|
||||
|
||||
# Test that we can set and get an enum parameter.
|
||||
self.assertEqual(
|
||||
params.clause_cleanup_ordering,
|
||||
sat_parameters_builder.SatParameters.ClauseOrdering.CLAUSE_ACTIVITY,
|
||||
)
|
||||
params.clause_cleanup_ordering = (
|
||||
sat_parameters_builder.SatParameters.ClauseOrdering.CLAUSE_LBD
|
||||
)
|
||||
self.assertEqual(
|
||||
params.clause_cleanup_ordering,
|
||||
sat_parameters_builder.SatParameters.ClauseOrdering.CLAUSE_LBD,
|
||||
)
|
||||
|
||||
# Test that we can set and get a repeated string parameter.
|
||||
params.subsolvers.append("no_lp")
|
||||
self.assertLen(params.subsolvers, 1)
|
||||
self.assertEqual(params.subsolvers[0], "no_lp")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
absltest.main()
|
||||
@@ -232,7 +232,7 @@ class Generator {
|
||||
// ptr.
|
||||
void GenerateRepeatedPtrDecl(const google::protobuf::Descriptor& msg) {
|
||||
absl::SubstituteAndAppend(&out_, R"(
|
||||
py::class_<google::protobuf::RepeatedPtrField<$0>>(py_module, "repeated_$1")
|
||||
py::class_<google::protobuf::RepeatedPtrField<$0>>(m, "repeated_$1")
|
||||
.def("add",
|
||||
[](google::protobuf::RepeatedPtrField<$0>* self) {
|
||||
return self->Add();
|
||||
@@ -265,7 +265,7 @@ class Generator {
|
||||
void GenerateRepeatedScalarDecl(absl::string_view scalar_type) {
|
||||
if (scalar_type == "std::string") {
|
||||
absl::StrAppend(&out_, R"(
|
||||
py::class_<google::protobuf::RepeatedPtrField<std::string>>(py_module, "repeated_scalar_std_string")
|
||||
py::class_<google::protobuf::RepeatedPtrField<std::string>>(m, "repeated_scalar_std_string")
|
||||
.def("append",
|
||||
[](google::protobuf::RepeatedPtrField<std::string>* self, std::string str) {
|
||||
self->Add(std::move(str));
|
||||
@@ -299,7 +299,7 @@ class Generator {
|
||||
} else {
|
||||
absl::SubstituteAndAppend(
|
||||
&out_, R"(
|
||||
py::class_<google::protobuf::RepeatedField<$0>>(py_module, "repeated_scalar_$1")
|
||||
py::class_<google::protobuf::RepeatedField<$0>>(m, "repeated_scalar_$1")
|
||||
.def("append", [](google::protobuf::RepeatedField<$0>* self, $0 value) {
|
||||
self->Add(value);
|
||||
})
|
||||
@@ -404,13 +404,13 @@ class Generator {
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the wrapper name for a message (or "py_module" if `msg` is null).
|
||||
// Returns the wrapper name for a message (or "m" if `msg` is null).
|
||||
// Dies if the scope is not found.
|
||||
std::string GetWrapperName(const google::protobuf::Descriptor* msg) {
|
||||
const auto it = wrapper_id_.find(msg);
|
||||
CHECK(it != wrapper_id_.end())
|
||||
<< "wrapper id not found: " << msg->full_name();
|
||||
if (msg == nullptr) return "py_module";
|
||||
if (msg == nullptr) return "m";
|
||||
return absl::StrCat("gen_", it->second);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user