Skip to content

Commit a34f79d

Browse files
committed
math_opt: few fix
* Enable and fix most python tests * export from google3 * export python/testing/
1 parent 5ad4300 commit a34f79d

27 files changed

+276
-92
lines changed

cmake/python.cmake

+5
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ if(BUILD_MATH_OPT)
311311
file(GENERATE OUTPUT ${PYTHON_PROJECT_DIR}/math_opt/core/__init__.py CONTENT "")
312312
file(GENERATE OUTPUT ${PYTHON_PROJECT_DIR}/math_opt/core/python/__init__.py CONTENT "")
313313
file(GENERATE OUTPUT ${PYTHON_PROJECT_DIR}/math_opt/python/__init__.py CONTENT "")
314+
file(GENERATE OUTPUT ${PYTHON_PROJECT_DIR}/math_opt/python/testing/__init__.py CONTENT "")
314315
file(GENERATE OUTPUT ${PYTHON_PROJECT_DIR}/math_opt/solvers/__init__.py CONTENT "")
315316
endif()
316317
file(GENERATE OUTPUT ${PYTHON_PROJECT_DIR}/packing/__init__.py CONTENT "")
@@ -352,6 +353,10 @@ if(BUILD_MATH_OPT)
352353
ortools/math_opt/python/sparse_containers.py
353354
ortools/math_opt/python/statistics.py
354355
DESTINATION ${PYTHON_PROJECT_DIR}/math_opt/python)
356+
file(COPY
357+
ortools/math_opt/python/testing/compare_proto.py
358+
ortools/math_opt/python/testing/proto_matcher.py
359+
DESTINATION ${PYTHON_PROJECT_DIR}/math_opt/python/testing)
355360
endif()
356361
file(COPY
357362
ortools/sat/python/cp_model.py

ortools/math_opt/model_parameters.proto

+13
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,17 @@ message ModelSolveParametersProto {
146146
// Requirements:
147147
// * Map keys must also be map keys of ModelProto.auxiliary_objectives.
148148
map<int64, ObjectiveParametersProto> auxiliary_objective_parameters = 8;
149+
150+
// Optional lazy constraint annotations. Included linear constraints will be
151+
// marked as "lazy" with supporting solvers, meaning that they will only be
152+
// added to the working model as-needed as the solver runs.
153+
//
154+
// Note that this an algorithmic hint that does not affect the model's
155+
// feasible region; solvers not supporting these annotations will simply
156+
// ignore it.
157+
//
158+
// Requirements:
159+
// * Each entry must be an element of VariablesProto.ids.
160+
// * Entries must be in strictly increasing order (i.e., sorted, no repeats).
161+
repeated int64 lazy_linear_constraint_ids = 9;
149162
}

ortools/math_opt/python/CMakeLists.txt

+6-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@
1313

1414
if(BUILD_TESTING)
1515
file(GLOB PYTHON_SRCS "*_test.py")
16+
list(FILTER PYTHON_SRCS EXCLUDE REGEX ".*/solve_gurobi_test.py") # need gurobi
17+
list(FILTER PYTHON_SRCS EXCLUDE REGEX ".*/solve_test.py") # need OSQP
18+
list(FILTER PYTHON_SRCS EXCLUDE REGEX ".*/normalize_test.py") # need google3 stuff
19+
list(FILTER PYTHON_SRCS EXCLUDE REGEX ".*/callback_test") # segfault
20+
list(FILTER PYTHON_SRCS EXCLUDE REGEX ".*/mathopt_test") # import test fail
1621
foreach(FILE_NAME IN LISTS PYTHON_SRCS)
17-
#add_python_test(FILE_NAME ${FILE_NAME})
22+
add_python_test(FILE_NAME ${FILE_NAME})
1823
endforeach()
1924
endif()

ortools/math_opt/python/callback_test.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import datetime
1616
import math
1717

18-
import unittest
18+
from absl.testing import absltest
1919
from ortools.math_opt import callback_pb2
2020
from ortools.math_opt import sparse_containers_pb2
2121
from ortools.math_opt.python import callback
@@ -24,7 +24,7 @@
2424
from ortools.math_opt.python.testing import compare_proto
2525

2626

27-
class CallbackDataTest(compare_proto.MathOptProtoAssertions, unittest.TestCase):
27+
class CallbackDataTest(compare_proto.MathOptProtoAssertions, absltest.TestCase):
2828
def test_parse_callback_data_no_solution(self) -> None:
2929
mod = model.Model(name="test_model")
3030
cb_data_proto = callback_pb2.CallbackDataProto(
@@ -85,7 +85,7 @@ def test_parse_callback_data_with_solution(self) -> None:
8585
)
8686

8787

88-
class CallbackRegistrationTest(compare_proto.MathOptProtoAssertions, unittest.TestCase):
88+
class CallbackRegistrationTest(compare_proto.MathOptProtoAssertions, absltest.TestCase):
8989
def testToProto(self) -> None:
9090
mod = model.Model(name="test_model")
9191
x = mod.add_binary_variable(name="x")
@@ -121,7 +121,7 @@ def testToProto(self) -> None:
121121

122122

123123
class GeneratedLinearConstraintTest(
124-
compare_proto.MathOptProtoAssertions, unittest.TestCase
124+
compare_proto.MathOptProtoAssertions, absltest.TestCase
125125
):
126126
def testToProto(self) -> None:
127127
mod = model.Model(name="test_model")
@@ -147,7 +147,7 @@ def testToProto(self) -> None:
147147
)
148148

149149

150-
class CallbackResultTest(compare_proto.MathOptProtoAssertions, unittest.TestCase):
150+
class CallbackResultTest(compare_proto.MathOptProtoAssertions, absltest.TestCase):
151151
def testToProto(self) -> None:
152152
mod = model.Model(name="test_model")
153153
x = mod.add_binary_variable(name="x")
@@ -250,4 +250,4 @@ def testToProtoEmpty(self) -> None:
250250

251251

252252
if __name__ == "__main__":
253-
unittest.main()
253+
absltest.main()

ortools/math_opt/python/compute_infeasible_subsystem_result_test.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
"""Tests for compute_infeasible_subsystem_result.py."""
1616

17-
import unittest
17+
from absl.testing import absltest
1818
from ortools.math_opt import infeasible_subsystem_pb2
1919
from ortools.math_opt.python import compute_infeasible_subsystem_result
2020
from ortools.math_opt.python import model
@@ -28,7 +28,7 @@
2828
)
2929

3030

31-
class ModelSubsetBoundsTest(unittest.TestCase, compare_proto.MathOptProtoAssertions):
31+
class ModelSubsetBoundsTest(absltest.TestCase, compare_proto.MathOptProtoAssertions):
3232
def test_empty(self) -> None:
3333
self.assertTrue(_ModelSubsetBounds().empty())
3434
self.assertFalse(_ModelSubsetBounds(lower=True).empty())
@@ -60,7 +60,7 @@ def test_proto_round_trip_upper(self) -> None:
6060
)
6161

6262

63-
class ModelSubsetTest(unittest.TestCase, compare_proto.MathOptProtoAssertions):
63+
class ModelSubsetTest(absltest.TestCase, compare_proto.MathOptProtoAssertions):
6464
def test_empty(self) -> None:
6565
m = model.Model()
6666
x = m.add_binary_variable()
@@ -167,7 +167,7 @@ def test_parse_proto_indicator_unsupported(self) -> None:
167167
compute_infeasible_subsystem_result.parse_model_subset(model_subset, m)
168168

169169

170-
class ComputeInfeasibleSubsystemResultTest(unittest.TestCase):
170+
class ComputeInfeasibleSubsystemResultTest(absltest.TestCase):
171171
def test_to_proto_round_trip(self) -> None:
172172
m = model.Model()
173173
x = m.add_binary_variable()
@@ -197,4 +197,4 @@ def test_to_proto_round_trip_empty(self) -> None:
197197

198198

199199
if __name__ == "__main__":
200-
unittest.main()
200+
absltest.main()

ortools/math_opt/python/expressions_test.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import unittest
15+
from absl.testing import absltest
1616
from ortools.math_opt.python import expressions
1717
from ortools.math_opt.python import model
1818

@@ -22,7 +22,7 @@ def _type_check_linear_sum(x: model.LinearSum) -> None:
2222
del x # Unused.
2323

2424

25-
class FastSumTest(unittest.TestCase):
25+
class FastSumTest(absltest.TestCase):
2626
def test_variables(self) -> None:
2727
mod = model.Model()
2828
x = mod.add_binary_variable()
@@ -78,7 +78,7 @@ def test_all_quad(self) -> None:
7878
)
7979

8080

81-
class EvaluateExpressionTest(unittest.TestCase):
81+
class EvaluateExpressionTest(absltest.TestCase):
8282
def test_scalar_expression(self) -> None:
8383
mod = model.Model()
8484
x = mod.add_binary_variable()
@@ -108,4 +108,4 @@ def test_quadratic(self) -> None:
108108

109109

110110
if __name__ == "__main__":
111-
unittest.main()
111+
absltest.main()

ortools/math_opt/python/hash_model_storage_test.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414

1515
"""Tests for hash_model_storage that cannot be covered by model_storage_(update)_test."""
1616

17-
import unittest
17+
from absl.testing import absltest
1818
from ortools.math_opt.python import hash_model_storage
1919

2020

21-
class HashModelStorageTest(unittest.TestCase):
21+
class HashModelStorageTest(absltest.TestCase):
2222
def test_quadratic_term_storage(self):
2323
storage = hash_model_storage._QuadraticTermStorage()
2424
storage.set_coefficient(0, 1, 1.0)
@@ -27,4 +27,4 @@ def test_quadratic_term_storage(self):
2727

2828

2929
if __name__ == "__main__":
30-
unittest.main()
30+
absltest.main()

ortools/math_opt/python/linear_expression_test.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
from typing import Any, List, NamedTuple, Union
1717
from unittest import mock
1818

19-
import unittest
20-
from google3.testing.pybase import parameterized
19+
from absl.testing import absltest
20+
from absl.testing import parameterized
2121
from ortools.math_opt.python import model
2222

2323
_LINEAR_TYPES = (
@@ -36,7 +36,7 @@
3636
)
3737

3838

39-
class BoundedExprTest(unittest.TestCase):
39+
class BoundedExprTest(absltest.TestCase):
4040
def test_eq_float(self) -> None:
4141
mod = model.Model()
4242
x = mod.add_binary_variable(name="x")
@@ -333,7 +333,7 @@ def test_geq_expr(self) -> None:
333333
self.assertEqual(bounded_expr.upper_bound, math.inf)
334334

335335

336-
class BoundedExprErrorTest(unittest.TestCase):
336+
class BoundedExprErrorTest(absltest.TestCase):
337337
def test_ne(self) -> None:
338338
mod = model.Model()
339339
x = mod.add_binary_variable(name="x")
@@ -588,7 +588,7 @@ def test_bounded_expr_geq_float(self) -> None:
588588
# pylint: enable=pointless-statement
589589

590590

591-
class BoundedExprStrAndReprTest(unittest.TestCase):
591+
class BoundedExprStrAndReprTest(absltest.TestCase):
592592
def test_upper_bounded_expr(self) -> None:
593593
mod = model.Model()
594594
x = mod.add_binary_variable(name="x")
@@ -1086,7 +1086,7 @@ def test_sub(
10861086
self.assertDictEqual(dict(e_inplace.terms), expected_terms)
10871087

10881088

1089-
class QuadraticTermKey(unittest.TestCase):
1089+
class QuadraticTermKey(absltest.TestCase):
10901090
# Mock QuadraticTermKey.__hash__ to have a collision in the dictionary lookup
10911091
# so that a correct behavior of term1 == term2 is needed to recover the
10921092
# values. For instance, if QuadraticTermKey.__eq__ only compared equality of
@@ -2738,7 +2738,7 @@ def test_quadratic_sum_ast(self) -> None:
27382738

27392739
# Test behavior of LinearExpression and as_flat_linear_expression that is
27402740
# not covered by other tests.
2741-
class LinearExpressionTest(unittest.TestCase):
2741+
class LinearExpressionTest(absltest.TestCase):
27422742
def test_init_to_zero(self) -> None:
27432743
expression = model.LinearExpression()
27442744
self.assertEqual(expression.offset, 0.0)
@@ -2774,7 +2774,7 @@ def test_evaluate(self) -> None:
27742774

27752775
# Test behavior of QuadraticExpression and as_flat_quadratic_expression that is
27762776
# not covered by other tests.
2777-
class QuadraticExpressionTest(unittest.TestCase):
2777+
class QuadraticExpressionTest(absltest.TestCase):
27782778
def test_terms_read_only(self) -> None:
27792779
mod = model.Model()
27802780
x = mod.add_binary_variable(name="x")
@@ -2809,4 +2809,4 @@ def test_evaluate(self) -> None:
28092809

28102810

28112811
if __name__ == "__main__":
2812-
unittest.main()
2812+
absltest.main()

ortools/math_opt/python/mathopt_test.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import typing
1919
from typing import Any, List, Set, Tuple
2020

21-
import unittest
21+
from absl.testing import absltest
2222
from ortools.math_opt.python import callback
2323
from ortools.math_opt.python import expressions
2424
from ortools.math_opt.python import hash_model_storage
@@ -81,7 +81,7 @@ def _get_public_api(module: types.ModuleType) -> List[Tuple[str, Any]]:
8181
return [(name, obj) for name, obj in tuple_list if not name.startswith("_")]
8282

8383

84-
class MathoptTest(unittest.TestCase):
84+
class MathoptTest(absltest.TestCase):
8585
def test_imports(self) -> None:
8686
missing_imports: List[str] = []
8787
for module in _MODULES_TO_CHECK:
@@ -107,4 +107,4 @@ def test_imports(self) -> None:
107107

108108

109109
if __name__ == "__main__":
110-
unittest.main()
110+
absltest.main()

ortools/math_opt/python/message_callback_test.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@
1919

2020
from absl import logging
2121

22-
import unittest
22+
from absl.testing import absltest
2323
from ortools.math_opt.python import message_callback
2424

2525

26-
class PrinterMessageCallbackTest(unittest.TestCase):
26+
class PrinterMessageCallbackTest(absltest.TestCase):
2727
def test_no_prefix(self):
2828
class FlushCountingStringIO(io.StringIO):
2929
def __init__(self):
@@ -53,7 +53,7 @@ def test_with_prefix(self):
5353
)
5454

5555

56-
class LogMessagesTest(unittest.TestCase):
56+
class LogMessagesTest(absltest.TestCase):
5757
def test_defaults(self):
5858
with self.assertLogs(logger="absl", level="INFO") as logs:
5959
message_callback.log_messages(["line 1", "line 2"])
@@ -82,7 +82,7 @@ def test_records_path(self):
8282
)
8383

8484

85-
class VLogMessagesTest(unittest.TestCase):
85+
class VLogMessagesTest(absltest.TestCase):
8686
"""Tests of vlog_messages().
8787
8888
In the tests we abuse the logging level 0 since there is not API in the
@@ -110,7 +110,7 @@ def test_records_path(self):
110110
)
111111

112112

113-
class ListMessageCallbackTest(unittest.TestCase):
113+
class ListMessageCallbackTest(absltest.TestCase):
114114
def test_empty(self):
115115
msgs = []
116116
cb = message_callback.list_message_callback(msgs)
@@ -131,4 +131,4 @@ def test_not_empty(self):
131131

132132

133133
if __name__ == "__main__":
134-
unittest.main()
134+
absltest.main()

ortools/math_opt/python/model_parameters_test.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import unittest
15+
from absl.testing import absltest
1616
from ortools.math_opt import model_parameters_pb2
1717
from ortools.math_opt import solution_pb2
1818
from ortools.math_opt import sparse_containers_pb2
@@ -23,7 +23,7 @@
2323
from ortools.math_opt.python.testing import compare_proto
2424

2525

26-
class ModelParametersTest(compare_proto.MathOptProtoAssertions, unittest.TestCase):
26+
class ModelParametersTest(compare_proto.MathOptProtoAssertions, absltest.TestCase):
2727
def test_solution_hint_round_trip(self) -> None:
2828
mod = model.Model(name="test_model")
2929
x = mod.add_binary_variable(name="x")
@@ -106,4 +106,4 @@ def test_model_parameters_to_proto_with_basis(self) -> None:
106106

107107

108108
if __name__ == "__main__":
109-
unittest.main()
109+
absltest.main()

ortools/math_opt/python/model_storage_test.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
import math
1616
from typing import Any, Callable
1717

18-
import unittest
19-
from google3.testing.pybase import parameterized
18+
from absl.testing import absltest
19+
from absl.testing import parameterized
2020
from ortools.math_opt import model_pb2
2121
from ortools.math_opt import sparse_containers_pb2
2222
from ortools.math_opt.python import hash_model_storage
@@ -925,4 +925,4 @@ def test_nans_pass_through(self, storage_class: _StorageClass) -> None:
925925

926926

927927
if __name__ == "__main__":
928-
unittest.main()
928+
absltest.main()

ortools/math_opt/python/model_storage_update_test.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import unittest
16-
from google3.testing.pybase import parameterized
15+
from absl.testing import absltest
16+
from absl.testing import parameterized
1717
from ortools.math_opt import model_pb2
1818
from ortools.math_opt import model_update_pb2
1919
from ortools.math_opt import sparse_containers_pb2
@@ -1171,4 +1171,4 @@ def test_multiple_update_tracker(self, storage_class: _StorageClass) -> None:
11711171

11721172

11731173
if __name__ == "__main__":
1174-
unittest.main()
1174+
absltest.main()

0 commit comments

Comments
 (0)