From 219b8459fa3cd6a9eda27364f2ca4003365e9f97 Mon Sep 17 00:00:00 2001 From: "Matthias C. M. Troffaes" Date: Tue, 17 Sep 2024 12:03:24 +0100 Subject: [PATCH] New row order parameter for polyhedron_from_matrix. --- CHANGELOG.rst | 4 ++++ cython/pycddlib.pxi | 17 ++++++++++++++--- cython/pyenums.pxi | 3 ++- docs/source/cdd.rst | 14 ++++++++++++++ src/cdd/__init__.pyi | 14 +++++++++++++- src/cdd/gmp.pyi | 6 ++++-- test/test_polyhedron.py | 28 ++++++++++++++++++++++++++++ 7 files changed, 79 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4a3fffd..7024283 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -90,6 +90,10 @@ Fully detailed changes: * The Fourier and block elimination functions are now exposed (see issue #38). +* You can now specify the row order type + when constructing a ``Polyhedron`` from a matrix. + (This exposes the ``dd_DDMatrix2Poly2`` function.) + * Thanks to the reorganization, there now is a standalone Python package that installs just the floating point interface without needing the gmp or cddlib libraries installed. diff --git a/cython/pycddlib.pxi b/cython/pycddlib.pxi index 97b8d04..08fabd4 100644 --- a/cython/pycddlib.pxi +++ b/cython/pycddlib.pxi @@ -544,15 +544,26 @@ cdef polyhedron_from_ptr(dd_PolyhedraPtr dd_poly): return poly -def polyhedron_from_matrix(mat: Matrix) -> Polyhedron: - """Run the double description method to convert *mat* into a polyhedron.""" +def polyhedron_from_matrix( + mat: Matrix, row_order_type: Optional[RowOrderType] = None +) -> Polyhedron: + """Run the double description method to convert *mat* into a polyhedron, + using *row_order_type* if specified. + + .. versionadded:: 3.0.0 + + The *row_order_type* parameter. + """ if ( mat.dd_mat.representation != dd_Inequality and mat.dd_mat.representation != dd_Generator ): raise ValueError("rep_type must be INEQUALITY or GENERATOR") cdef dd_ErrorType error = dd_NoError - dd_poly = dd_DDMatrix2Poly(mat.dd_mat, &error) + if row_order_type is None: + dd_poly = dd_DDMatrix2Poly(mat.dd_mat, &error) + else: + dd_poly = dd_DDMatrix2Poly2(mat.dd_mat, row_order_type, &error) if error != dd_NoError: dd_FreePolyhedra(dd_poly) _raise_error(error, "failed to run double description method") diff --git a/cython/pyenums.pxi b/cython/pyenums.pxi index aac0735..99e93cc 100644 --- a/cython/pyenums.pxi +++ b/cython/pyenums.pxi @@ -40,7 +40,8 @@ class RepType(IntEnum): INEQUALITY = dd_Inequality GENERATOR = dd_Generator -class _RowOrderType(IntEnum): +class RowOrderType(IntEnum): + """Type of row order to use in the double description method.""" MAX_INDEX = dd_MaxIndex MIN_INDEX = dd_MinIndex MIN_CUTOFF = dd_MinCutoff diff --git a/docs/source/cdd.rst b/docs/source/cdd.rst index a331c79..e9b5d7d 100644 --- a/docs/source/cdd.rst +++ b/docs/source/cdd.rst @@ -46,6 +46,20 @@ Enums INEQUALITY GENERATOR +.. autoclass:: RowOrderType(value) + :show-inheritance: + + .. attribute:: + MAX_INDEX + MIN_INDEX + MIN_CUTOFF + MAX_CUTOFF + MIX_CUTOFF + LEX_MIN + LEX_MAX + RANDOM_ROW + + Classes ------- diff --git a/src/cdd/__init__.pyi b/src/cdd/__init__.pyi index bdc59fc..c783773 100644 --- a/src/cdd/__init__.pyi +++ b/src/cdd/__init__.pyi @@ -71,6 +71,16 @@ class RepType(enum.IntEnum): INEQUALITY: ClassVar[RepType] = ... UNSPECIFIED: ClassVar[RepType] = ... +class RowOrderType(enum.IntEnum): + MAX_INDEX: ClassVar[RowOrderType] = ... + MIN_INDEX: ClassVar[RowOrderType] = ... + MIN_CUTOFF: ClassVar[RowOrderType] = ... + MAX_CUTOFF: ClassVar[RowOrderType] = ... + MIX_CUTOFF: ClassVar[RowOrderType] = ... + LEX_MIN: ClassVar[RowOrderType] = ... + LEX_MAX: ClassVar[RowOrderType] = ... + RANDOM_ROW: ClassVar[RowOrderType] = ... + def block_elimination(mat: Matrix, col_set: Container[int]) -> Matrix: ... def copy_adjacency(poly: Polyhedron) -> Sequence[Set[int]]: ... def copy_generators(poly: Polyhedron) -> Matrix: ... @@ -98,4 +108,6 @@ def matrix_from_array( obj_type: LPObjType = LPObjType.NONE, obj_func: Optional[Sequence[SupportsNumberType]] = None, ) -> Matrix: ... -def polyhedron_from_matrix(mat: Matrix) -> Polyhedron: ... +def polyhedron_from_matrix( + mat: Matrix, row_order_type: Optional[RowOrderType] = None +) -> Polyhedron: ... diff --git a/src/cdd/gmp.pyi b/src/cdd/gmp.pyi index 2f2f174..8400968 100644 --- a/src/cdd/gmp.pyi +++ b/src/cdd/gmp.pyi @@ -2,7 +2,7 @@ from collections.abc import Container, Sequence, Set from fractions import Fraction from typing import Optional, Union -from cdd import LPObjType, LPSolverType, LPStatusType, RepType +from cdd import LPObjType, LPSolverType, LPStatusType, RepType, RowOrderType NumberType = Fraction SupportsNumberType = Union[Fraction, int] @@ -76,4 +76,6 @@ def matrix_from_array( obj_type: LPObjType = LPObjType.NONE, obj_func: Optional[Sequence[SupportsNumberType]] = None, ) -> Matrix: ... -def polyhedron_from_matrix(mat: Matrix) -> Polyhedron: ... +def polyhedron_from_matrix( + mat: Matrix, row_order_type: Optional[RowOrderType] = None +) -> Polyhedron: ... diff --git a/test/test_polyhedron.py b/test/test_polyhedron.py index 820057a..cacb557 100644 --- a/test/test_polyhedron.py +++ b/test/test_polyhedron.py @@ -1,5 +1,8 @@ from collections.abc import Sequence, Set from fractions import Fraction +from typing import Optional + +import pytest import cdd @@ -78,3 +81,28 @@ def test_polyhedron_cube_2() -> None: poly = cdd.polyhedron_from_matrix(mat) assert_matrix_almost_equal(cdd.copy_generators(poly).array, generators) assert_matrix_almost_equal(cdd.copy_inequalities(poly).array, inequalities) + + +@pytest.mark.parametrize( + "row_order_type,order", + [ + (cdd.RowOrderType.MAX_INDEX, [2, 3, 0, 1]), + (cdd.RowOrderType.MIN_INDEX, [2, 1, 0, 3]), + (cdd.RowOrderType.MIN_CUTOFF, [1, 0, 2, 3]), + (cdd.RowOrderType.MAX_CUTOFF, [1, 0, 2, 3]), + (cdd.RowOrderType.MIX_CUTOFF, [1, 0, 2, 3]), + (cdd.RowOrderType.LEX_MIN, [0, 1, 2, 3]), + (cdd.RowOrderType.LEX_MAX, [2, 3, 0, 1]), + ], +) +def test_polyhedron_row_order_type( + row_order_type: Optional[cdd.RowOrderType], order: Sequence[int] +) -> None: + generators = [[1, 1, 0], [1, 0, 0], [1, 0, 1], [1, 1, 1]] + inequalities = [[0, 0, 1], [0, 1, 0], [1, 0, -1], [1, -1, 0]] + mat = cdd.matrix_from_array(inequalities, rep_type=cdd.RepType.INEQUALITY) + poly = cdd.polyhedron_from_matrix(mat, row_order_type=row_order_type) + print(cdd.copy_generators(poly).array) + assert_matrix_almost_equal( + cdd.copy_generators(poly).array, [generators[i] for i in order] + )