remove the pywrap prefix from pybind11 modules; add _pybind to the cmake target of the same modules

This commit is contained in:
Laurent Perron
2023-07-03 14:30:27 +02:00
parent 32175c9c3b
commit 346642b871
19 changed files with 219 additions and 194 deletions

View File

@@ -270,8 +270,8 @@ file(COPY
DESTINATION ${PYTHON_PROJECT_DIR}/linear_solver)
file(COPY
ortools/linear_solver/python/model_builder.py
ortools/linear_solver/python/model_builder_helper.py
ortools/linear_solver/python/pandas_model.py
ortools/linear_solver/python/model_builder_numbers.py
ortools/linear_solver/python/pandas_model.py
DESTINATION ${PYTHON_PROJECT_DIR}/linear_solver/python)
file(COPY
ortools/sat/python/cp_model.py
@@ -318,18 +318,18 @@ add_custom_command(
COMMAND ${CMAKE_COMMAND} -E $<IF:$<STREQUAL:$<TARGET_PROPERTY:ortools,TYPE>,SHARED_LIBRARY>,copy,true>
$<$<STREQUAL:$<TARGET_PROPERTY:ortools,TYPE>,SHARED_LIBRARY>:$<TARGET_SONAME_FILE:ortools>>
${PYTHON_PROJECT}/.libs
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:init> ${PYTHON_PROJECT}/init/python
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:knapsack_solver> ${PYTHON_PROJECT}/algorithms/python
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:init_pybind11> ${PYTHON_PROJECT}/init/python
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:knapsack_solver_pybind11> ${PYTHON_PROJECT}/algorithms/python
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:linear_sum_assignment_pybind11> ${PYTHON_PROJECT}/graph/python
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:max_flow_pybind11> ${PYTHON_PROJECT}/graph/python
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:min_cost_flow_pybind11> ${PYTHON_PROJECT}/graph/python
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:pywrapcp> ${PYTHON_PROJECT}/constraint_solver
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:pywraplp> ${PYTHON_PROJECT}/linear_solver
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:pywrap_model_builder_helper> ${PYTHON_PROJECT}/linear_solver/python
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:model_builder_helper_pybind11> ${PYTHON_PROJECT}/linear_solver/python
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:pywrap_pdlp_pybind11> ${PYTHON_PROJECT}/pdlp/python
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:swig_helper> ${PYTHON_PROJECT}/sat/python
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:rcpsp> ${PYTHON_PROJECT}/scheduling/python
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:sorted_interval_list> ${PYTHON_PROJECT}/util/python
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:swig_helper_pybind11> ${PYTHON_PROJECT}/sat/python
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:rcpsp_pybind11> ${PYTHON_PROJECT}/scheduling/python
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:sorted_interval_list_pybind11> ${PYTHON_PROJECT}/util/python
#COMMAND ${Python3_EXECUTABLE} setup.py bdist_egg bdist_wheel
COMMAND ${Python3_EXECUTABLE} setup.py bdist_wheel
COMMAND ${CMAKE_COMMAND} -E touch ${PROJECT_BINARY_DIR}/python/dist/timestamp
@@ -339,18 +339,18 @@ add_custom_command(
python/setup.py
Py${PROJECT_NAME}_proto
${PROJECT_NAMESPACE}::ortools
init
knapsack_solver
init_pybind11
knapsack_solver_pybind11
linear_sum_assignment_pybind11
max_flow_pybind11
min_cost_flow_pybind11
pywrapcp
pywraplp
pywrap_model_builder_helper
model_builder_helper_pybind11
pywrap_pdlp_pybind11
swig_helper
rcpsp
sorted_interval_list
swig_helper_pybind11
rcpsp_pybind11
sorted_interval_list_pybind11
BYPRODUCTS
python/${PYTHON_PROJECT}
python/${PYTHON_PROJECT}.egg-info

View File

@@ -11,23 +11,27 @@
# See the License for the specific language governing permissions and
# limitations under the License.
pybind11_add_module(knapsack_solver MODULE knapsack_solver.cc)
pybind11_add_module(knapsack_solver_pybind11 MODULE knapsack_solver.cc)
set_target_properties(knapsack_solver_pybind11 PROPERTIES
LIBRARY_OUTPUT_NAME "knapsack_solver")
# note: macOS is APPLE and also UNIX !
if(APPLE)
set_target_properties(knapsack_solver PROPERTIES
set_target_properties(knapsack_solver_pybind11 PROPERTIES
SUFFIX ".so"
INSTALL_RPATH "@loader_path;@loader_path/../../../${PYTHON_PROJECT}/.libs"
)
set_property(TARGET knapsack_solver APPEND PROPERTY
set_property(TARGET knapsack_solver_pybind11 APPEND PROPERTY
LINK_FLAGS "-flat_namespace -undefined suppress"
)
elseif(UNIX)
set_target_properties(knapsack_solver PROPERTIES
set_target_properties(knapsack_solver_pybind11 PROPERTIES
INSTALL_RPATH "$ORIGIN:$ORIGIN/../../../${PYTHON_PROJECT}/.libs"
)
endif()
target_link_libraries(knapsack_solver PRIVATE ${PROJECT_NAMESPACE}::ortools)
add_library(${PROJECT_NAMESPACE}::knapsack_solver ALIAS knapsack_solver)
target_link_libraries(knapsack_solver_pybind11 PRIVATE ${PROJECT_NAMESPACE}::ortools)
add_library(${PROJECT_NAMESPACE}::knapsack_solver_pybind11 ALIAS knapsack_solver_pybind11)
if(BUILD_TESTING)
file(GLOB PYTHON_SRCS "*_test.py")

View File

@@ -11,8 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef OR_TOOLS_ALGORITHMS_PYTHON_knapsack_SOLVER_DOC_H_
#define OR_TOOLS_ALGORITHMS_PYTHON_knapsack_SOLVER_DOC_H_
#ifndef OR_TOOLS_ALGORITHMS_PYTHON_KNAPSACK_SOLVER_DOC_H_
#define OR_TOOLS_ALGORITHMS_PYTHON_KNAPSACK_SOLVER_DOC_H_
/*
This file contains docstrings for use in the Python bindings.
@@ -292,4 +292,4 @@ static const char* __doc_operations_research_KnapsackState_is_in_2 =
#pragma GCC diagnostic pop
#endif
#endif // OR_TOOLS_ALGORITHMS_PYTHON_knapsack_SOLVER_DOC_H_
#endif // OR_TOOLS_ALGORITHMS_PYTHON_KNAPSACK_SOLVER_DOC_H_

View File

@@ -17,13 +17,11 @@
"""knapsack_solver unittest file."""
from absl import app
import unittest
from absl.testing import absltest
from ortools.algorithms.python import knapsack_solver
class PyWrapAlgorithmsKnapsackSolverTest(unittest.TestCase):
class PyWrapAlgorithmsKnapsackSolverTest(absltest.TestCase):
def RealSolve(self, profits, weights, capacities, solver_type, use_reduction):
solver = knapsack_solver.KnapsackSolver(solver_type, "solver")
solver.set_use_reduction(use_reduction)
@@ -262,7 +260,7 @@ class PyWrapAlgorithmsKnapsackSolverTest(unittest.TestCase):
def main(_):
unittest.main()
absltest.main()
if __name__ == "__main__":

View File

@@ -11,23 +11,27 @@
# See the License for the specific language governing permissions and
# limitations under the License.
pybind11_add_module(init MODULE init.cc)
pybind11_add_module(init_pybind11 MODULE init.cc)
set_target_properties(init_pybind11 PROPERTIES
LIBRARY_OUTPUT_NAME "init")
# note: macOS is APPLE and also UNIX !
if(APPLE)
set_target_properties(init PROPERTIES
set_target_properties(init_pybind11 PROPERTIES
SUFFIX ".so"
INSTALL_RPATH "@loader_path;@loader_path/../../../${PYTHON_PROJECT}/.libs"
)
set_property(TARGET init APPEND PROPERTY
set_property(TARGET init_pybind11 APPEND PROPERTY
LINK_FLAGS "-flat_namespace -undefined suppress"
)
elseif(UNIX)
set_target_properties(init PROPERTIES
set_target_properties(init_pybind11 PROPERTIES
INSTALL_RPATH "$ORIGIN:$ORIGIN/../../../${PYTHON_PROJECT}/.libs"
)
endif()
target_link_libraries(init PRIVATE ${PROJECT_NAMESPACE}::ortools)
add_library(${PROJECT_NAMESPACE}::init ALIAS init)
target_link_libraries(init_pybind11 PRIVATE ${PROJECT_NAMESPACE}::ortools)
add_library(${PROJECT_NAMESPACE}::init_pybind11 ALIAS init_pybind11)
if(BUILD_TESTING)
file(GLOB PYTHON_SRCS "*_test.py")

View File

@@ -11,8 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef OR_TOOLS_OPEN_SOURCE_INIT_PYTHON_PYWRAPINIT_DOC_H_
#define OR_TOOLS_OPEN_SOURCE_INIT_PYTHON_PYWRAPINIT_DOC_H_
#ifndef OR_TOOLS_OPEN_SOURCE_INIT_PYTHON_INIT_DOC_H_
#define OR_TOOLS_OPEN_SOURCE_INIT_PYTHON_INIT_DOC_H_
/*
This file contains docstrings for use in the Python bindings.
@@ -141,4 +141,4 @@ static const char* __doc_operations_research_OrToolsVersion_VersionString =
#pragma GCC diagnostic pop
#endif
#endif // OR_TOOLS_OPEN_SOURCE_INIT_PYTHON_PYWRAPINIT_DOC_H_
#endif // OR_TOOLS_OPEN_SOURCE_INIT_PYTHON_INIT_DOC_H_

View File

@@ -17,8 +17,8 @@ load("@pybind11_bazel//:build_defs.bzl", "pybind_extension")
load("@rules_python//python:defs.bzl", "py_library", "py_test")
pybind_extension(
name = "pywrap_model_builder_helper",
srcs = ["pywrap_model_builder_helper.cc"],
name = "model_builder_helper",
srcs = ["model_builder_helper.cc"],
visibility = ["//visibility:public"],
deps = [
"//ortools/linear_solver:linear_solver_cc_proto",
@@ -30,17 +30,6 @@ pybind_extension(
],
)
py_library(
name = "model_builder_helper",
srcs = ["model_builder_helper.py"],
visibility = ["//visibility:public"],
deps = [
":pywrap_model_builder_helper",
"//ortools/linear_solver:linear_solver_py_pb2",
requirement("numpy"),
],
)
py_test(
name = "model_builder_helper_test",
srcs = ["model_builder_helper_test.py"],
@@ -51,22 +40,32 @@ py_test(
python_version = "PY3",
deps = [
":model_builder_helper",
":pywrap_model_builder_helper",
":model_builder_numbers",
"//ortools/linear_solver:linear_solver_py_pb2",
requirement("absl-py"),
requirement("numpy"),
requirement("scipy"),
],
)
py_library(
name = "model_builder_numbers",
srcs = ["model_builder_numbers.py"],
visibility = ["//visibility:public"],
deps = [
requirement("numpy"),
],
)
py_library(
name = "model_builder",
srcs = ["model_builder.py"],
visibility = ["//visibility:public"],
deps = [
":model_builder_helper",
":pywrap_model_builder_helper",
":model_builder_numbers",
requirement("numpy"),
"//ortools/linear_solver:linear_solver_py_pb2",
"@com_google_protobuf//:protobuf_python",
],
)
@@ -81,7 +80,8 @@ py_test(
deps = [
":model_builder",
":model_builder_helper",
":pywrap_model_builder_helper",
":model_builder_numbers",
requirement("absl-py"),
requirement("numpy"),
],
)
@@ -90,7 +90,7 @@ py_library(
name = "pandas_model",
srcs = ["pandas_model.py"],
deps = [
":pywrap_model_builder_helper",
":model_builder_helper",
requirement("numpy"),
requirement("pandas"),
"//ortools/linear_solver:linear_solver_py_pb2",

View File

@@ -46,32 +46,33 @@ if(MSVC)
target_link_libraries(pywraplp PRIVATE ${Python3_LIBRARIES})
endif()
pybind11_add_module(pywrap_model_builder_helper MODULE pywrap_model_builder_helper.cc)
pybind11_add_module(model_builder_helper_pybind11 MODULE model_builder_helper.cc)
set_target_properties(model_builder_helper_pybind11 PROPERTIES
LIBRARY_OUTPUT_NAME "model_builder_helper")
target_include_directories(pywrap_model_builder_helper PRIVATE
target_include_directories(model_builder_helper_pybind11 PRIVATE
${protobuf_SOURCE_DIR})
# note: macOS is APPLE and also UNIX !
if(APPLE)
set_target_properties(pywrap_model_builder_helper PROPERTIES
set_target_properties(model_builder_helper_pybind11 PROPERTIES
SUFFIX ".so"
INSTALL_RPATH "@loader_path;@loader_path/../../../${PYTHON_PROJECT}/.libs"
)
set_property(TARGET pywrap_model_builder_helper APPEND PROPERTY
set_property(TARGET model_builder_helper_pybind11 APPEND PROPERTY
LINK_FLAGS "-flat_namespace -undefined suppress"
)
elseif(UNIX)
set_target_properties(pywrap_model_builder_helper PROPERTIES
set_target_properties(model_builder_helper_pybind11 PROPERTIES
INSTALL_RPATH "$ORIGIN:$ORIGIN/../../../${PYTHON_PROJECT}/.libs"
)
endif()
target_link_libraries(pywrap_model_builder_helper PRIVATE
target_link_libraries(model_builder_helper_pybind11 PRIVATE
${PROJECT_NAMESPACE}::ortools
pybind11_native_proto_caster
)
add_library(${PROJECT_NAMESPACE}::pywrap_model_builder_helper ALIAS pywrap_model_builder_helper)
add_library(${PROJECT_NAMESPACE}::model_builder_helper_pybind11 ALIAS model_builder_helper_pybind11)
if(BUILD_TESTING)
file(GLOB PYTHON_SRCS "*_test.py")

View File

@@ -34,13 +34,14 @@ rather than for solving specific optimization problems.
import math
import numbers
from typing import Any, Callable, Dict, List, Literal, Optional, Union, Sequence, Tuple
from typing import Any, Callable, Dict, List, Literal, Optional, Sequence, Tuple, Union
import numpy as np
from numpy import typing as npt
from numpy.lib import mixins
from ortools.linear_solver.python import model_builder_helper as mbh
from ortools.linear_solver.python import pywrap_model_builder_helper as pwmb
from ortools.linear_solver.python import model_builder_numbers as mbn
# Custom types.
@@ -67,7 +68,7 @@ SliceT = Union[
# Forward solve statuses.
SolveStatus = pwmb.SolveStatus
SolveStatus = mbh.SolveStatus
class LinearExpr:
@@ -118,10 +119,10 @@ class LinearExpr:
Returns:
a LinearExpr instance or a numerical constant.
"""
checked_constant: np.double = mbh.assert_is_a_number(constant)
checked_constant: np.double = mbn.assert_is_a_number(constant)
if not expressions:
return checked_constant
if len(expressions) == 1 and mbh.is_zero(checked_constant):
if len(expressions) == 1 and mbn.is_zero(checked_constant):
return expressions[0]
return LinearExpr.weighted_sum(
@@ -154,7 +155,7 @@ class LinearExpr:
"LinearExpr.weighted_sum: expressions and coefficients have"
" different lengths"
)
checked_constant: np.double = mbh.assert_is_a_number(constant)
checked_constant: np.double = mbn.assert_is_a_number(constant)
if not expressions:
return checked_constant
@@ -162,10 +163,10 @@ class LinearExpr:
indices = []
coeffs = []
for e, c in zip(expressions, coefficients):
if mbh.is_zero(c):
if mbn.is_zero(c):
continue
if mbh.is_a_number(e):
if mbn.is_a_number(e):
checked_constant += np.double(c * e)
elif isinstance(e, Variable):
indices.append(np.array([e.index], dtype=np.int32))
@@ -203,14 +204,14 @@ class LinearExpr:
Returns:
a LinearExpr instance or a numerical constant.
"""
checked_coefficient: np.double = mbh.assert_is_a_number(coefficient)
checked_constant: np.double = mbh.assert_is_a_number(constant)
checked_coefficient: np.double = mbn.assert_is_a_number(coefficient)
checked_constant: np.double = mbn.assert_is_a_number(constant)
if mbh.is_zero(checked_coefficient):
if mbn.is_zero(checked_coefficient):
return checked_constant
if mbh.is_one(checked_coefficient) and mbh.is_zero(checked_constant):
if mbn.is_one(checked_coefficient) and mbn.is_zero(checked_constant):
return expression
if mbh.is_a_number(expression):
if mbn.is_a_number(expression):
return np.double(expression) * checked_coefficient + checked_constant
if isinstance(expression, Variable):
return _WeightedSum(
@@ -233,7 +234,7 @@ class LinearExpr:
return NotImplemented
def __add__(self, arg: LinearExprT) -> LinearExprT:
if mbh.is_a_number(arg):
if mbn.is_a_number(arg):
return LinearExpr.sum([self], constant=arg)
return LinearExpr.weighted_sum(
[self, arg], [1.0, 1.0], constant=0.0
@@ -243,7 +244,7 @@ class LinearExpr:
return self.__add__(arg)
def __sub__(self, arg: LinearExprT):
if mbh.is_a_number(arg):
if mbn.is_a_number(arg):
return LinearExpr.sum([self], constant=arg * -1.0)
return LinearExpr.weighted_sum(
[self, arg], [1.0, -1.0], constant=0.0
@@ -255,10 +256,10 @@ class LinearExpr:
) # pytype: disable=wrong-arg-types # numpy-scalars
def __mul__(self, arg: NumberT):
arg = mbh.assert_is_a_number(arg)
if mbh.is_one(arg):
arg = mbn.assert_is_a_number(arg)
if mbn.is_one(arg):
return self
elif mbh.is_zero(arg):
elif mbn.is_zero(arg):
return 0.0
return self.multiply_by(arg)
@@ -269,8 +270,8 @@ class LinearExpr:
return self.__mul__(arg)
def __div__(self, arg: NumberT):
coeff = mbh.assert_is_a_number(arg)
if mbh.is_zero(coeff):
coeff = mbn.assert_is_a_number(arg)
if mbn.is_zero(coeff):
raise ValueError("Cannot call the division operator with a zero divisor")
return self.__mul__(1.0 / coeff)
@@ -311,8 +312,8 @@ class LinearExpr:
) -> Union[bool, "BoundedLinearExpression"]:
if arg is None:
return False
if mbh.is_a_number(arg):
arg = mbh.assert_is_a_number(arg)
if mbn.is_a_number(arg):
arg = mbn.assert_is_a_number(arg)
return BoundedLinearExpression(self, arg, arg)
else:
return BoundedLinearExpression(
@@ -320,8 +321,8 @@ class LinearExpr:
) # pytype: disable=wrong-arg-types # numpy-scalars
def __ge__(self, arg: LinearExprT) -> "BoundedLinearExpression":
if mbh.is_a_number(arg):
arg = mbh.assert_is_a_number(arg)
if mbn.is_a_number(arg):
arg = mbn.assert_is_a_number(arg)
return BoundedLinearExpression(
self, arg, math.inf
) # pytype: disable=wrong-arg-types # numpy-scalars
@@ -331,8 +332,8 @@ class LinearExpr:
) # pytype: disable=wrong-arg-types # numpy-scalars
def __le__(self, arg: LinearExprT) -> "BoundedLinearExpression":
if mbh.is_a_number(arg):
arg = mbh.assert_is_a_number(arg)
if mbn.is_a_number(arg):
arg = mbn.assert_is_a_number(arg)
return BoundedLinearExpression(
self, -math.inf, arg
) # pytype: disable=wrong-arg-types # numpy-scalars
@@ -363,13 +364,13 @@ class _WeightedSum(LinearExpr):
):
super().__init__()
self.__variable_indices: npt.NDArray[np.int32] = variable_indices
self.__coefficients: npt.NDArray[np.double] = mbh.assert_is_a_number_array(
self.__coefficients: npt.NDArray[np.double] = mbn.assert_is_a_number_array(
coefficients
)
self.__constant: np.double = constant
def multiply_by(self, arg: NumberT) -> LinearExprT:
if mbh.is_zero(arg):
if mbn.is_zero(arg):
return 0.0 # pytype: disable=bad-return-type # numpy-scalars
if self.__variable_indices.size > 0:
return _WeightedSum(
@@ -392,7 +393,7 @@ class _WeightedSum(LinearExpr):
def constant(self) -> np.double:
return self.__constant
def pretty_string(self, helper: pwmb.ModelBuilderHelper) -> str:
def pretty_string(self, helper: mbh.ModelBuilderHelper) -> str:
"""Pretty print a linear expression into a string."""
output: str = ""
for index, coeff in zip(self.variable_indices, self.coefficients):
@@ -400,15 +401,15 @@ class _WeightedSum(LinearExpr):
if not var_name:
var_name = f"unnamed_var_{index}"
if not output and mbh.is_one(coeff):
if not output and mbn.is_one(coeff):
output = var_name
elif not output and mbh.is_minus_one(coeff):
elif not output and mbn.is_minus_one(coeff):
output = f"-{var_name}"
elif not output:
output = f"{coeff} * {var_name}"
elif mbh.is_one(coeff):
elif mbn.is_one(coeff):
output += f" + {var_name}"
elif mbh.is_minus_one(coeff):
elif mbn.is_minus_one(coeff):
output += f" - {var_name}"
elif coeff > 0.0:
output += f" + {coeff} * {var_name}"
@@ -444,7 +445,7 @@ class Variable(LinearExpr):
def __init__(
self,
helper: pwmb.ModelBuilderHelper,
helper: mbh.ModelBuilderHelper,
lb: NumberT,
ub: Optional[NumberT],
is_integral: Optional[bool],
@@ -452,7 +453,7 @@ class Variable(LinearExpr):
):
"""See ModelBuilder.new_var below."""
LinearExpr.__init__(self)
self.__helper: pwmb.ModelBuilderHelper = helper
self.__helper: mbh.ModelBuilderHelper = helper
# Python do not support multiple __init__ methods.
# This method is only called from the ModelBuilder class.
# We hack the parameter to support the two cases:
@@ -462,13 +463,13 @@ class Variable(LinearExpr):
# case 2:
# helper is a ModelBuilderHelper, lb is an index (int), ub is None,
# is_integral is None, and name is None.
if mbh.is_integral(lb) and ub is None and is_integral is None:
if mbn.is_integral(lb) and ub is None and is_integral is None:
self.__index: np.int32 = np.int32(lb)
self.__helper: pwmb.ModelBuilderHelper = helper
self.__helper: mbh.ModelBuilderHelper = helper
else:
index: np.int32 = helper.add_var()
self.__index: np.int32 = np.int32(index)
self.__helper: pwmb.ModelBuilderHelper = helper
self.__helper: mbh.ModelBuilderHelper = helper
helper.set_var_lower_bound(index, lb)
helper.set_var_upper_bound(index, ub)
helper.set_var_integrality(index, is_integral)
@@ -481,7 +482,7 @@ class Variable(LinearExpr):
return self.__index
@property
def helper(self) -> pwmb.ModelBuilderHelper:
def helper(self) -> mbh.ModelBuilderHelper:
"""Returns the underlying ModelBuilderHelper."""
return self.__helper
@@ -571,8 +572,8 @@ class Variable(LinearExpr):
if isinstance(arg, Variable):
return VarCompVar(self, arg, True)
else:
if mbh.is_a_number(arg):
arg = mbh.assert_is_a_number(arg)
if mbn.is_a_number(arg):
arg = mbn.assert_is_a_number(arg)
return BoundedLinearExpression(self, arg, arg)
else:
return BoundedLinearExpression(
@@ -601,8 +602,8 @@ _REGISTERED_NUMPY_VARIABLE_FUNCS: Dict[Any, NumpyFuncT] = {}
class VariableContainer(mixins.NDArrayOperatorsMixin):
"""Variable container."""
def __init__(self, helper: pwmb.ModelBuilderHelper, indices: npt.NDArray[np.int32]):
self.__helper: pwmb.ModelBuilderHelper = helper
def __init__(self, helper: mbh.ModelBuilderHelper, indices: npt.NDArray[np.int32]):
self.__helper: mbh.ModelBuilderHelper = helper
self.__variable_indices: npt.NDArray[np.int32] = indices
@property
@@ -787,8 +788,8 @@ class BoundedLinearExpression:
def __init__(self, expr: LinearExprT, lb: NumberT, ub: NumberT):
self.__expr: LinearExprT = expr
self.__lb: np.double = mbh.assert_is_a_number(lb)
self.__ub: np.double = mbh.assert_is_a_number(ub)
self.__lb: np.double = mbn.assert_is_a_number(lb)
self.__ub: np.double = mbn.assert_is_a_number(ub)
def __str__(self) -> str:
if self.__lb > -math.inf and self.__ub < math.inf:
@@ -833,9 +834,9 @@ class LinearConstraint:
linear_constraint = model.add(x + 2 * y == 5)
"""
def __init__(self, helper: pwmb.ModelBuilderHelper):
def __init__(self, helper: mbh.ModelBuilderHelper):
self.__index: np.int32 = helper.add_linear_constraint()
self.__helper: pwmb.ModelBuilderHelper = helper
self.__helper: mbh.ModelBuilderHelper = helper
@property
def index(self) -> np.int32:
@@ -843,7 +844,7 @@ class LinearConstraint:
return self.__index
@property
def helper(self) -> pwmb.ModelBuilderHelper:
def helper(self) -> mbh.ModelBuilderHelper:
"""Returns the ModelBuilderHelper instance."""
return self.__helper
@@ -885,7 +886,7 @@ class ModelBuilder:
"""
def __init__(self):
self.__helper: pwmb.ModelBuilderHelper = pwmb.ModelBuilderHelper()
self.__helper: mbh.ModelBuilderHelper = mbh.ModelBuilderHelper()
# Integer variable.
@@ -1129,7 +1130,7 @@ class ModelBuilder:
name: Optional[str] = None,
) -> VariableContainer:
"""Creates a vector of Boolean variables."""
if mbh.is_integral(shape):
if mbn.is_integral(shape):
shape = [shape]
name = name or ""
@@ -1159,7 +1160,7 @@ class ModelBuilder:
ct = LinearConstraint(self.__helper)
if name:
self.__helper.set_constraint_name(ct.index, name)
if mbh.is_a_number(linear_expr):
if mbn.is_a_number(linear_expr):
self.__helper.set_constraint_lower_bound(ct.index, lb - linear_expr)
self.__helper.set_constraint_upper_bound(ct.index, ub - linear_expr)
elif isinstance(linear_expr, Variable):
@@ -1236,7 +1237,7 @@ class ModelBuilder:
"""Defines the objective."""
self.helper.clear_objective()
self.__helper.set_maximize(maximize)
if mbh.is_a_number(linear_expr):
if mbn.is_a_number(linear_expr):
self.helper.set_objective_offset(linear_expr)
elif isinstance(linear_expr, Variable):
self.helper.set_var_objective_coefficient(linear_expr.index, 1.0)
@@ -1260,12 +1261,12 @@ class ModelBuilder:
# Input/Output
def export_to_lp_string(self, obfuscate: bool = False) -> str:
options: pwmb.MPModelExportOptions = pwmb.MPModelExportOptions()
options: mbh.MPModelExportOptions = mbh.MPModelExportOptions()
options.obfuscate = obfuscate
return self.__helper.export_to_lp_string(options)
def export_to_mps_string(self, obfuscate: bool = False) -> str:
options: pwmb.MPModelExportOptions = pwmb.MPModelExportOptions()
options: mbh.MPModelExportOptions = mbh.MPModelExportOptions()
options.obfuscate = obfuscate
return self.__helper.export_to_mps_string(options)
@@ -1291,7 +1292,7 @@ class ModelBuilder:
self.__helper.set_name(name)
@property
def helper(self) -> pwmb.ModelBuilderHelper:
def helper(self) -> mbh.ModelBuilderHelper:
"""Returns the model builder helper."""
return self.__helper
@@ -1308,9 +1309,7 @@ class ModelSolver:
"""
def __init__(self, solver_name: str):
self.__solve_helper: pwmb.ModelSolverHelper = pwmb.ModelSolverHelper(
solver_name
)
self.__solve_helper: mbh.ModelSolverHelper = mbh.ModelSolverHelper(solver_name)
self.log_callback: Optional[Callable[[str], None]] = None
def solver_is_supported(self) -> bool:
@@ -1353,7 +1352,7 @@ class ModelSolver:
def value(self, expr: LinearExprT) -> np.double:
"""Returns the value of a linear expression after solve."""
self.__check_has_feasible_solution()
if mbh.is_a_number(expr):
if mbn.is_a_number(expr):
return expr
elif isinstance(expr, Variable):
return self.__solve_helper.var_value(expr.index)

View File

@@ -13,6 +13,8 @@
// A pybind11 wrapper for model_builder_helper.
#include "ortools/linear_solver/wrappers/model_builder_helper.h"
#include <algorithm>
#include <complex>
#include <cstdlib>
@@ -31,7 +33,6 @@
#include "absl/strings/string_view.h"
#include "ortools/linear_solver/linear_solver.pb.h"
#include "ortools/linear_solver/model_exporter.h"
#include "ortools/linear_solver/wrappers/model_builder_helper.h"
#include "pybind11/eigen.h"
#include "pybind11/pybind11.h"
#include "pybind11/pytypes.h"
@@ -150,7 +151,7 @@ std::vector<std::pair<int, double>> SortedGroupedTerms(
return terms;
}
PYBIND11_MODULE(pywrap_model_builder_helper, m) {
PYBIND11_MODULE(model_builder_helper, m) {
pybind11_protobuf::ImportNativeProtoCasters();
m.def("to_mpmodel_proto", &ToMPModelProto, arg("helper"));

View File

@@ -17,30 +17,31 @@
import gzip
import os
import threading
from absl.testing import absltest
import numpy as np
from scipy import sparse
import unittest
from ortools.linear_solver import linear_solver_pb2
from ortools.linear_solver.python import pywrap_model_builder_helper
from ortools.linear_solver.python import model_builder_helper
class PywrapModelBuilderHelperTest(unittest.TestCase):
class PywrapModelBuilderHelperTest(absltest.TestCase):
def test_export_model_proto_to_mps_string(self):
model = pywrap_model_builder_helper.ModelBuilderHelper()
model = model_builder_helper.ModelBuilderHelper()
model.set_name("testmodel")
result = model.export_to_mps_string()
self.assertIn("testmodel", result)
self.assertIn("ENDATA", result)
def test_export_model_proto_to_lp_string(self):
model = pywrap_model_builder_helper.ModelBuilderHelper()
model = model_builder_helper.ModelBuilderHelper()
model.set_maximize(True)
lp_string = model.export_to_lp_string()
self.assertIn("Maximize", lp_string)
def test_import_from_mps_string(self):
model = pywrap_model_builder_helper.ModelBuilderHelper()
model = model_builder_helper.ModelBuilderHelper()
self.assertTrue(model.import_from_mps_string("NAME testmodel"))
self.assertEqual(model.name(), "testmodel")
@@ -48,12 +49,12 @@ class PywrapModelBuilderHelperTest(unittest.TestCase):
def test_import_from_mps_file(self):
path = os.path.dirname(__file__)
mps_path = f"{path}/../testdata/maximization.mps"
model = pywrap_model_builder_helper.ModelBuilderHelper()
model = model_builder_helper.ModelBuilderHelper()
self.assertTrue(model.import_from_mps_file(mps_path))
self.assertEqual(model.name(), "SupportedMaximizationProblem")
def test_import_from_lp_string(self):
model = pywrap_model_builder_helper.ModelBuilderHelper()
model = model_builder_helper.ModelBuilderHelper()
model.import_from_lp_string("max:")
self.assertTrue(model.maximize())
@@ -71,26 +72,28 @@ class PywrapModelBuilderHelperTest(unittest.TestCase):
model=model,
solver_type=linear_solver_pb2.MPModelRequest.GLOP_LINEAR_PROGRAMMING,
)
solver_helper = pywrap_model_builder_helper.ModelSolverHelper("")
solver_helper = model_builder_helper.ModelSolverHelper("")
result = solver_helper.solve_serialized_request(request.SerializeToString())
response = linear_solver_pb2.MPSolutionResponse().FromString(result)
self.assertEqual(
response.status, linear_solver_pb2.MPSolverResponseStatus.MPSOLVER_OPTIMAL
response.status,
linear_solver_pb2.MPSolverResponseStatus.MPSOLVER_OPTIMAL,
)
self.assertAlmostEqual(response.objective_value, 1.0)
def test_solve_with_glop_direct(self):
model = pywrap_model_builder_helper.ModelBuilderHelper()
model = model_builder_helper.ModelBuilderHelper()
self.assertEqual(0, model.add_var())
model.set_var_lower_bound(0, 0.0)
model.set_var_upper_bound(0, 1.0)
model.set_var_objective_coefficient(0, 1.0)
model.set_maximize(True)
solver = pywrap_model_builder_helper.ModelSolverHelper("glop")
solver = model_builder_helper.ModelSolverHelper("glop")
solver.solve(model)
self.assertEqual(
solver.status(), linear_solver_pb2.MPSolverResponseStatus.MPSOLVER_OPTIMAL
solver.status(),
linear_solver_pb2.MPSolverResponseStatus.MPSOLVER_OPTIMAL,
)
self.assertAlmostEqual(solver.objective_value(), 1.0)
self.assertAlmostEqual(solver.var_value(0), 1.0)
@@ -110,7 +113,7 @@ class PywrapModelBuilderHelperTest(unittest.TestCase):
model=model,
solver_type=linear_solver_pb2.MPModelRequest.PDLP_LINEAR_PROGRAMMING,
)
solver_helper = pywrap_model_builder_helper.ModelSolverHelper("")
solver_helper = model_builder_helper.ModelSolverHelper("")
result = solver_helper.solve_serialized_request(request.SerializeToString())
if result:
response = linear_solver_pb2.MPSolutionResponse().FromString(result)
@@ -130,9 +133,9 @@ class PywrapModelBuilderHelperTest(unittest.TestCase):
mps_path = f"{path}/../testdata/large_model.mps.gz"
with gzip.open(mps_path, "r") as f:
mps_data = f.read()
model_helper = pywrap_model_builder_helper.ModelBuilderHelper()
model_helper = model_builder_helper.ModelBuilderHelper()
self.assertTrue(model_helper.import_from_mps_string(mps_data))
solver_helper = pywrap_model_builder_helper.ModelSolverHelper("glop")
solver_helper = model_builder_helper.ModelSolverHelper("glop")
result = []
solve_thread = threading.Thread(
@@ -144,7 +147,7 @@ class PywrapModelBuilderHelperTest(unittest.TestCase):
self.assertTrue(solver_helper.has_response())
self.assertEqual(
solver_helper.status(),
pywrap_model_builder_helper.SolveStatus.CANCELLED_BY_USER,
model_builder_helper.SolveStatus.CANCELLED_BY_USER,
)
def test_build_model(self):
@@ -155,7 +158,7 @@ class PywrapModelBuilderHelperTest(unittest.TestCase):
con_ub = np.array([5.0, 6.0])
constraint_matrix = sparse.csr_matrix(np.array([[1.0], [2.0]]))
model = pywrap_model_builder_helper.ModelBuilderHelper()
model = model_builder_helper.ModelBuilderHelper()
model.fill_model_from_sparse_data(
var_lb, var_ub, obj, con_lb, con_ub, constraint_matrix
)
@@ -183,4 +186,4 @@ class PywrapModelBuilderHelperTest(unittest.TestCase):
if __name__ == "__main__":
unittest.main()
absltest.main()

View File

@@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""helpers methods for the cp_model_builder module."""
"""helpers methods for the cp_model_builder module on numbers."""
import numbers
from typing import Any, Sequence, Union

View File

@@ -15,15 +15,17 @@
"""Tests for ModelBuilder."""
import math
from absl.testing import absltest
import numpy as np
import numpy.testing as np_testing
import os
from ortools.linear_solver.python import model_builder as mb
import unittest
class ModelBuilderTest(unittest.TestCase):
class ModelBuilderTest(absltest.TestCase):
# Number of decimal places to use for numerical tolerance for
# checking primal, dual, objective values and other values.
NUM_PLACES = 5
@@ -92,7 +94,9 @@ class ModelBuilderTest(unittest.TestCase):
4.0 - 1.0 * solver.dual_value(c0) - 5.0 * solver.dual_value(c1)
)
self.assertAlmostEqual(
x3_expected_reduced_cost, solver.reduced_cost(x3), places=self.NUM_PLACES
x3_expected_reduced_cost,
solver.reduced_cost(x3),
places=self.NUM_PLACES,
)
self.assertAlmostEqual(100.0, solver.activity(c0), places=self.NUM_PLACES)
@@ -559,4 +563,4 @@ ENDATA
if __name__ == "__main__":
unittest.main()
absltest.main()

View File

@@ -26,7 +26,7 @@ import numpy as np
import pandas as pd
from ortools.linear_solver import linear_solver_pb2
from ortools.linear_solver.python import pywrap_model_builder_helper as pwmb
from ortools.linear_solver.python import model_builder_helper as mbh
_Number = Union[int, float, np.number]
_LinearType = Union[_Number, "_LinearBase"]
@@ -208,7 +208,7 @@ class _Variable(_LinearBase):
__slots__ = ("_helper", "_index")
_helper: pwmb.ModelBuilderHelper
_helper: mbh.ModelBuilderHelper
_index: int
def __str__(self):
@@ -250,7 +250,7 @@ class _Variable(_LinearBase):
def _create_variable(
helper: pwmb.ModelBuilderHelper,
helper: mbh.ModelBuilderHelper,
*,
name: str,
lower_bound: _Number,
@@ -260,7 +260,7 @@ def _create_variable(
"""Creates a new variable in the helper.
Args:
helper (pwmb.ModelBuilderHelper): The helper to create the variable.
helper (mbh.ModelBuilderHelper): The helper to create the variable.
name (str): The name of the variable.
lower_bound (Union[int, float]): The lower bound of the variable.
upper_bound (Union[int, float]): The upper bound of the variable.
@@ -289,12 +289,12 @@ class _BoundedLinearBase(metaclass=abc.ABCMeta):
@abc.abstractmethod
def _create_linear_constraint(
self, helper: pwmb.ModelBuilderHelper, name: str
self, helper: mbh.ModelBuilderHelper, name: str
) -> "_LinearConstraint":
"""Creates a new linear constraint in the helper.
Args:
helper (pwmb.ModelBuilderHelper): The helper to create the constraint.
helper (mbh.ModelBuilderHelper): The helper to create the constraint.
name (str): The name of the linear constraint.
Returns:
@@ -304,7 +304,7 @@ class _BoundedLinearBase(metaclass=abc.ABCMeta):
def _create_linear_constraint(
constraint: Union[bool, _BoundedLinearBase],
helper: pwmb.ModelBuilderHelper,
helper: mbh.ModelBuilderHelper,
name: str,
):
"""Creates a new linear constraint in the helper.
@@ -370,7 +370,7 @@ class _BoundedLinearExpression(_BoundedLinearBase):
)
def _create_linear_constraint(
self, helper: pwmb.ModelBuilderHelper, name: str
self, helper: mbh.ModelBuilderHelper, name: str
) -> "_LinearConstraint":
index = helper.add_linear_constraint()
expr = _as_flat_linear_expression(self._expression)
@@ -414,7 +414,7 @@ class _VarEqVar(_BoundedLinearBase):
return hash(self._left) == hash(self._right)
def _create_linear_constraint(
self, helper: pwmb.ModelBuilderHelper, name: str
self, helper: mbh.ModelBuilderHelper, name: str
) -> "_LinearConstraint":
index = helper.add_linear_constraint()
helper.set_constraint_lower_bound(index, 0.0)
@@ -442,7 +442,7 @@ class _LinearConstraint:
__slots__ = ("_helper", "_index")
_helper: pwmb.ModelBuilderHelper
_helper: mbh.ModelBuilderHelper
_index: int
@property
@@ -551,7 +551,7 @@ class OptimizationModel:
"""Initializes an optimization model with the given name."""
if not name.isidentifier():
raise ValueError("name={} is not a valid identifier".format(name))
self._helper: pwmb.ModelBuilderHelper = pwmb.ModelBuilderHelper()
self._helper: mbh.ModelBuilderHelper = mbh.ModelBuilderHelper()
self._helper.set_name(name)
self._variables: dict[str, pd.Series] = {}
self._linear_constraints: dict[str, pd.Series] = {}
@@ -567,7 +567,7 @@ class OptimizationModel:
def to_proto(self) -> linear_solver_pb2.MPModelProto:
"""Exports the optimization model to a ProtoBuf format."""
return pwmb.to_mpmodel_proto(self._helper)
return mbh.to_mpmodel_proto(self._helper)
@typing.overload
def _get_linear_constraints(self, constraints: Optional[pd.Index]) -> pd.Index:
@@ -1349,11 +1349,11 @@ class SolveStatus(enum.Enum):
UNBOUNDED = enum.auto()
_solve_status: dict[pwmb.SolveStatus, SolveStatus] = {
pwmb.SolveStatus.OPTIMAL: SolveStatus.OPTIMAL,
pwmb.SolveStatus.FEASIBLE: SolveStatus.FEASIBLE,
pwmb.SolveStatus.INFEASIBLE: SolveStatus.INFEASIBLE,
pwmb.SolveStatus.UNBOUNDED: SolveStatus.UNBOUNDED,
_solve_status: dict[mbh.SolveStatus, SolveStatus] = {
mbh.SolveStatus.OPTIMAL: SolveStatus.OPTIMAL,
mbh.SolveStatus.FEASIBLE: SolveStatus.FEASIBLE,
mbh.SolveStatus.INFEASIBLE: SolveStatus.INFEASIBLE,
mbh.SolveStatus.UNBOUNDED: SolveStatus.UNBOUNDED,
}
@@ -1391,8 +1391,8 @@ class _SolveResult:
def __init__(
self,
model: OptimizationModel,
solver: pwmb.ModelSolverHelper,
status: pwmb.SolveStatus,
solver: mbh.ModelSolverHelper,
status: mbh.SolveStatus,
):
self._model = model
self._solver = solver
@@ -1588,7 +1588,7 @@ class Solver:
Solver (based on its `solver_type`).
RuntimeError: On a solve error.
"""
solver = pwmb.ModelSolverHelper(_solver_type_to_name[self.solver_type])
solver = mbh.ModelSolverHelper(_solver_type_to_name[self.solver_type])
solver.enable_output(options.enable_output)
solver.set_time_limit_in_seconds(options.time_limit_seconds)
if options.solver_specific_parameters:

View File

@@ -63,7 +63,6 @@ def code_sample_py(name):
deps = [
requirement("absl-py"),
requirement("numpy"),
"@com_google_protobuf//:protobuf_python",
],
python_version = "PY3",
srcs_version = "PY3",

View File

@@ -49,8 +49,8 @@ setup(
],
package_data={
'@PYTHON_PROJECT@':[$<$<STREQUAL:$<TARGET_PROPERTY:@PROJECT_NAME@,TYPE>,SHARED_LIBRARY>:'.libs/*','../$<TARGET_SONAME_FILE_NAME:@PROJECT_NAME@>'>],
'@PYTHON_PROJECT@.init.python':['$<TARGET_FILE_NAME:init>'],
'@PYTHON_PROJECT@.algorithms.python':['$<TARGET_FILE_NAME:knapsack_solver>'],
'@PYTHON_PROJECT@.init.python':['$<TARGET_FILE_NAME:init_pybind11>'],
'@PYTHON_PROJECT@.algorithms.python':['$<TARGET_FILE_NAME:knapsack_solver_pybind11>'],
'@PYTHON_PROJECT@.bop':['*.pyi'],
'@PYTHON_PROJECT@.glop':['*.pyi'],
'@PYTHON_PROJECT@.graph.python':[
@@ -60,14 +60,14 @@ setup(
],
'@PYTHON_PROJECT@.constraint_solver':['$<TARGET_FILE_NAME:pywrapcp>', '*.pyi'],
'@PYTHON_PROJECT@.linear_solver':['$<TARGET_FILE_NAME:pywraplp>', '*.pyi'],
'@PYTHON_PROJECT@.linear_solver.python':['$<TARGET_FILE_NAME:pywrap_model_builder_helper>', '*.pyi'],
'@PYTHON_PROJECT@.linear_solver.python':['$<TARGET_FILE_NAME:model_builder_helper_pybind11>', '*.pyi'],
'@PYTHON_PROJECT@.packing':['*.pyi'],
'@PYTHON_PROJECT@.pdlp':['*.pyi'],
'@PYTHON_PROJECT@.pdlp.python':['$<TARGET_FILE_NAME:pywrap_pdlp_pybind11>'],
'@PYTHON_PROJECT@.sat':['*.pyi'],
'@PYTHON_PROJECT@.sat.python':['$<TARGET_FILE_NAME:swig_helper>', '*.pyi'],
'@PYTHON_PROJECT@.scheduling.python':['$<TARGET_FILE_NAME:rcpsp>', '*.pyi'],
'@PYTHON_PROJECT@.util.python':['$<TARGET_FILE_NAME:sorted_interval_list>', '*.pyi'],
'@PYTHON_PROJECT@.sat.python':['$<TARGET_FILE_NAME:swig_helper_pybind11>', '*.pyi'],
'@PYTHON_PROJECT@.scheduling.python':['$<TARGET_FILE_NAME:rcpsp_pybind11>', '*.pyi'],
'@PYTHON_PROJECT@.util.python':['$<TARGET_FILE_NAME:sorted_interval_list_pybind11>', '*.pyi'],
},
include_package_data=True,
license='Apache 2.0',

View File

@@ -11,29 +11,32 @@
# See the License for the specific language governing permissions and
# limitations under the License.
pybind11_add_module(swig_helper MODULE swig_helper.cc)
pybind11_add_module(swig_helper_pybind11 MODULE swig_helper.cc)
set_target_properties(swig_helper_pybind11 PROPERTIES
LIBRARY_OUTPUT_NAME "swig_helper")
# note: macOS is APPLE and also UNIX !
if(APPLE)
set_target_properties(swig_helper PROPERTIES
set_target_properties(swig_helper_pybind11 PROPERTIES
SUFFIX ".so"
INSTALL_RPATH "@loader_path;@loader_path/../../../${PYTHON_PROJECT}/.libs"
)
set_property(TARGET swig_helper APPEND PROPERTY
set_property(TARGET swig_helper_pybind11 APPEND PROPERTY
LINK_FLAGS "-flat_namespace -undefined suppress"
)
elseif(UNIX)
set_target_properties(swig_helper PROPERTIES
set_target_properties(swig_helper_pybind11 PROPERTIES
INSTALL_RPATH "$ORIGIN:$ORIGIN/../../../${PYTHON_PROJECT}/.libs"
)
endif()
target_link_libraries(swig_helper PRIVATE
target_link_libraries(swig_helper_pybind11 PRIVATE
${PROJECT_NAMESPACE}::ortools
pybind11_native_proto_caster
protobuf::libprotobuf
)
target_include_directories(swig_helper PRIVATE ${protobuf_SOURCE_DIR})
add_library(${PROJECT_NAMESPACE}::swig_helper ALIAS swig_helper)
target_include_directories(swig_helper_pybind11 PRIVATE ${protobuf_SOURCE_DIR})
add_library(${PROJECT_NAMESPACE}::swig_helper_pybind11 ALIAS swig_helper_pybind11)
if(BUILD_TESTING)
file(GLOB PYTHON_SRCS "*_test.py")

View File

@@ -11,27 +11,32 @@
# See the License for the specific language governing permissions and
# limitations under the License.
pybind11_add_module(rcpsp MODULE rcpsp.cc)
pybind11_add_module(rcpsp_pybind11 MODULE rcpsp.cc)
set_target_properties(rcpsp_pybind11 PROPERTIES
LIBRARY_OUTPUT_NAME "rcpsp")
# note: macOS is APPLE and also UNIX !
if(APPLE)
set_target_properties(rcpsp PROPERTIES
set_target_properties(rcpsp_pybind11 PROPERTIES
SUFFIX ".so"
INSTALL_RPATH "@loader_path;@loader_path/../../../${PYTHON_PROJECT}/.libs"
)
set_property(TARGET rcpsp APPEND PROPERTY
set_property(TARGET rcpsp_pybind11 APPEND PROPERTY
LINK_FLAGS "-flat_namespace -undefined suppress"
)
elseif(UNIX)
set_target_properties(rcpsp PROPERTIES
set_target_properties(rcpsp_pybind11 PROPERTIES
INSTALL_RPATH "$ORIGIN:$ORIGIN/../../../${PYTHON_PROJECT}/.libs"
)
endif()
target_link_libraries(rcpsp PRIVATE
target_link_libraries(rcpsp_pybind11 PRIVATE
${PROJECT_NAMESPACE}::ortools
pybind11_native_proto_caster
protobuf::libprotobuf
)
target_include_directories(rcpsp PRIVATE ${protobuf_SOURCE_DIR})
target_include_directories(rcpsp_pybind11 PRIVATE ${protobuf_SOURCE_DIR})
add_library(${PROJECT_NAMESPACE}::rcpsp_pybind11 ALIAS rcpsp_pybind11)
if(BUILD_TESTING)
file(GLOB PYTHON_SRCS "*_test.py")

View File

@@ -11,23 +11,27 @@
# See the License for the specific language governing permissions and
# limitations under the License.
pybind11_add_module(sorted_interval_list MODULE sorted_interval_list.cc)
pybind11_add_module(sorted_interval_list_pybind11 MODULE sorted_interval_list.cc)
set_target_properties(sorted_interval_list_pybind11 PROPERTIES
LIBRARY_OUTPUT_NAME "sorted_interval_list")
# note: macOS is APPLE and also UNIX !
if(APPLE)
set_target_properties(sorted_interval_list PROPERTIES
set_target_properties(sorted_interval_list_pybind11 PROPERTIES
SUFFIX ".so"
INSTALL_RPATH "@loader_path;@loader_path/../../../${PYTHON_PROJECT}/.libs"
)
set_property(TARGET sorted_interval_list APPEND PROPERTY
set_property(TARGET sorted_interval_list_pybind11 APPEND PROPERTY
LINK_FLAGS "-flat_namespace -undefined suppress"
)
elseif(UNIX)
set_target_properties(sorted_interval_list PROPERTIES
set_target_properties(sorted_interval_list_pybind11 PROPERTIES
INSTALL_RPATH "$ORIGIN:$ORIGIN/../../../${PYTHON_PROJECT}/.libs"
)
endif()
target_link_libraries(sorted_interval_list PRIVATE ${PROJECT_NAMESPACE}::ortools)
add_library(${PROJECT_NAMESPACE}::sorted_interval_list ALIAS sorted_interval_list)
target_link_libraries(sorted_interval_list_pybind11 PRIVATE ${PROJECT_NAMESPACE}::ortools)
add_library(${PROJECT_NAMESPACE}::sorted_interval_list_pybind11 ALIAS sorted_interval_list_pybind11)
if(BUILD_TESTING)
file(GLOB PYTHON_SRCS "*_test.py")