diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 616c6d0..72393af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,14 +16,14 @@ jobs: - name: "Checkout sources" uses: actions/checkout@v3 - - name: "Set up Python 3.8" + - name: "Set up Python 3.9" uses: actions/setup-python@v4 with: - python-version: "3.8" + python-version: "3.9" - name: "Install Debian dependencies" run: | - sudo apt install libgmp3-dev + sudo apt-get install -y libcdd-dev libgmp3-dev - name: "Install PyPI dependencies" run: | @@ -55,7 +55,7 @@ jobs: - name: "Install Debian dependencies" run: | - sudo apt install libgmp3-dev + sudo apt-get install -y libcdd-dev libgmp3-dev - name: "Install PyPI dependencies" run: | @@ -74,48 +74,52 @@ jobs: strategy: matrix: - os: [ubuntu-latest, windows-latest] - python-version: ["3.8", "3.9", "3.10"] + os: [ubuntu-latest, macos-13] + python-version: ["3.9", "3.10", "3.11", "3.12"] + + defaults: + run: + # See https://github.com/mamba-org/setup-micromamba?tab=readme-ov-file#about-login-shells + shell: bash -leo pipefail {0} steps: - name: "Checkout sources" uses: actions/checkout@v3 - - name: "Set up Python ${{ matrix.python-version }}" - uses: actions/setup-python@v4 - with: - python-version: "${{ matrix.python-version }}" - - - name: "Install Debian dependencies" - if: matrix.os == 'ubuntu-latest' - run: | - sudo apt install libgmp-dev - - - name: "Install macOS dependencies" - if: matrix.os == 'macos-latest' - run: | - brew install gmp - - - name: "Install PyPI dependencies" - run: | - python -m pip install --upgrade pip - python -m pip install tox tox-gh-actions - - name: "Install GMP (Ubuntu)" if: matrix.os == 'ubuntu-latest' run: | - sudo apt-get install -y libgmp-dev + sudo apt-get install -y libgmp3-dev - name: "Install GMP (macOS)" - if: ${{ matrix.os == 'macos-latest' }} + if: ${{ matrix.os == 'macos-13' }} run: | brew install gmp - - name: "Test with tox for ${{ matrix.os }}" - env: - PLATFORM: ${{ matrix.os }} + - name: "Install Conda environment with Micromamba" + uses: mamba-org/setup-micromamba@v1 + with: + micromamba-version: '1.5.8-0' + environment-name: pypoman_test_env + create-args: >- + python=${{ matrix.python-version }} + cddlib + cvxopt>=1.2.6 + matplotlib>=3.3.4 + numpy>=1.15.4 + pyclipper>=1.3.0 + qpsolvers>=3.3.1 + scipy>=1.7.0 + cache-environment: true + post-cleanup: 'all' + + - name: "Install cdd and pycddlib" + run: | + pip install pycddlib + + - name: "Run unit tests" run: | - tox + python -m unittest discover ci_success: name: "CI success" diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e7ab56..0aa6bc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Changed + +- Bump minimum supported Python version to 3.9 +- Update pycddlib to version 3.0.0 + +### Fixed + +- CICD: Re-enable macOS testing + +### Removed + +- CICD: Dropped Windows support +- Remove cdd reference from polyhedron submodule + ## [1.1.1] - 2024-12-20 ### Changed diff --git a/doc/src/chebyshev-center.rst b/doc/src/chebyshev-center.rst new file mode 100644 index 0000000..7e2a32b --- /dev/null +++ b/doc/src/chebyshev-center.rst @@ -0,0 +1,5 @@ +**************** +Chebyshev center +**************** + +.. autofunction:: pypoman.polyhedron.compute_chebyshev_center diff --git a/doc/src/duality.rst b/doc/src/duality.rst new file mode 100644 index 0000000..4795a03 --- /dev/null +++ b/doc/src/duality.rst @@ -0,0 +1,7 @@ +******* +Duality +******* + +.. automodule:: pypoman.duality + :members: + diff --git a/doc/src/index.rst b/doc/src/index.rst index a2d959e..8a2cbe8 100644 --- a/doc/src/index.rst +++ b/doc/src/index.rst @@ -3,47 +3,12 @@ Welcome to the documentation of **pypoman**, a PYthon module for POlyhedral MANipulations. -Chebyshev center -================ - -.. autofunction:: pypoman.polyhedron.compute_chebyshev_center - -Duality -======= - -.. automodule:: pypoman.duality - :members: - -Intersection -============ - -.. automodule:: pypoman.intersection - :members: - -Linear programming -================== - -.. autofunction:: pypoman.lp.solve_lp - -Polygon manipulation -==================== - -.. automodule:: pypoman.polygon - :members: - -Projection -========== - -.. automodule:: pypoman.projection - :members: - -References -========== - -.. [Boyd04] `Convex Optimization - `_, Stephen Boyd and - Lieven Vandenberghe, Cambridge University Press, 2004. - -.. [Bretl08] *Testing Static Equilibrium for Legged Robots*, T. Bretl and S. - Lall, IEEE Transactions on Robotics, vol. 24, no. 4, pp. 794-807, August - 2008. +.. toctree:: + :maxdepth: 1 + + chebyshev-center.rst + duality.rst + intersection.rst + polygon.rst + projection.rst + references.rst diff --git a/doc/src/intersection.rst b/doc/src/intersection.rst new file mode 100644 index 0000000..a2f5a26 --- /dev/null +++ b/doc/src/intersection.rst @@ -0,0 +1,6 @@ +************ +Intersection +************ + +.. automodule:: pypoman.intersection + :members: diff --git a/doc/src/linear-programming.rst b/doc/src/linear-programming.rst new file mode 100644 index 0000000..5885ddd --- /dev/null +++ b/doc/src/linear-programming.rst @@ -0,0 +1,5 @@ +****************** +Linear programming +****************** + +.. autofunction:: pypoman.lp.solve_lp diff --git a/doc/src/polygon.rst b/doc/src/polygon.rst new file mode 100644 index 0000000..f54c439 --- /dev/null +++ b/doc/src/polygon.rst @@ -0,0 +1,7 @@ +******************** +Polygon manipulation +******************** + +.. automodule:: pypoman.polygon + :members: + diff --git a/doc/src/projection.rst b/doc/src/projection.rst new file mode 100644 index 0000000..7575ec7 --- /dev/null +++ b/doc/src/projection.rst @@ -0,0 +1,6 @@ +********** +Projection +********** + +.. automodule:: pypoman.projection + :members: diff --git a/doc/src/references.rst b/doc/src/references.rst new file mode 100644 index 0000000..028366d --- /dev/null +++ b/doc/src/references.rst @@ -0,0 +1,11 @@ +********** +References +********** + +.. [Boyd04] `Convex Optimization + `_, Stephen Boyd and + Lieven Vandenberghe, Cambridge University Press, 2004. + +.. [Bretl08] *Testing Static Equilibrium for Legged Robots*, T. Bretl and S. + Lall, IEEE Transactions on Robotics, vol. 24, no. 4, pp. 794-807, August + 2008. diff --git a/pypoman/bretl.py b/pypoman/bretl.py index 0ed07a9..6d0bd64 100644 --- a/pypoman/bretl.py +++ b/pypoman/bretl.py @@ -69,8 +69,9 @@ def expand( if ( abs( np.cross( - [xopt - v1.x, yopt - v1.y], [v1.x - v2.x, v1.y - v2.y] - ) + [xopt - v1.x, yopt - v1.y, 0], + [v1.x - v2.x, v1.y - v2.y, 0], + )[2] ) < 1e-4 ): diff --git a/pypoman/duality.py b/pypoman/duality.py index 16bdb66..324e16a 100644 --- a/pypoman/duality.py +++ b/pypoman/duality.py @@ -36,11 +36,11 @@ def compute_cone_face_matrix(S: np.ndarray) -> np.ndarray: ] ) # V-representation: first column is 0 for rays - mat = cdd.Matrix(V, number_type="float") + mat = cdd.matrix_from_array(V) # type: ignore mat.rep_type = cdd.RepType.GENERATOR - P = cdd.Polyhedron(mat) - ineq = P.get_inequalities() - H = np.array(ineq) + P = cdd.polyhedron_from_matrix(mat) + ineq = cdd.copy_inequalities(P) + H = np.array(ineq.array) if H.shape == (0,): # H == [] return H A = [] @@ -82,10 +82,10 @@ def compute_polytope_halfspaces( V = np.vstack(vertices) t = np.ones((V.shape[0], 1)) # first column is 1 for vertices tV = np.hstack([t, V]) - mat = cdd.Matrix(tV, number_type="float") + mat = cdd.matrix_from_array(tV) # type: ignore mat.rep_type = cdd.RepType.GENERATOR - P = cdd.Polyhedron(mat) - bA = np.array(P.get_inequalities()) + P = cdd.polyhedron_from_matrix(mat) + bA = np.array(cdd.copy_inequalities(P).array) if bA.shape == (0,): # bA == [] return bA # the polyhedron is given by b + A x >= 0 where bA = [b|A] @@ -121,11 +121,11 @@ def compute_polytope_vertices( `_. """ b = b.reshape((b.shape[0], 1)) - mat = cdd.Matrix(np.hstack([b, -A]), number_type="float") + mat = cdd.matrix_from_array(np.hstack([b, -A])) # type: ignore mat.rep_type = cdd.RepType.INEQUALITY - P = cdd.Polyhedron(mat) - g = P.get_generators() - V = np.array(g) + P = cdd.polyhedron_from_matrix(mat) + g = cdd.copy_generators(P) + V = np.array(g.array) vertices = [] for i in range(V.shape[0]): if V[i, 0] != 1: # 1 = vertex, 0 = ray diff --git a/pypoman/polyhedron.py b/pypoman/polyhedron.py index a3ceb3d..561bf65 100644 --- a/pypoman/polyhedron.py +++ b/pypoman/polyhedron.py @@ -15,13 +15,6 @@ from .lp import solve_lp from .misc import norm -try: - import cdd -except ImportError: - warn("Could not import cdd, some functions will not be available") - cdd = None - - try: import cvxopt except ImportError: @@ -61,7 +54,6 @@ def compute_chebyshev_center(A: np.ndarray, b: np.ndarray) -> np.ndarray: __all__ = [ - "cdd", "compute_chebyshev_center", "cvxopt", ] diff --git a/pypoman/projection.py b/pypoman/projection.py index 83ab48c..1a70086 100644 --- a/pypoman/projection.py +++ b/pypoman/projection.py @@ -69,24 +69,26 @@ def project_polyhedron( # see ftp://ftp.ifor.math.ethz.ch/pub/fukuda/cdd/cddlibman/node3.html (A, b) = ineq b = b.reshape((b.shape[0], 1)) - linsys = cdd.Matrix(np.hstack([b, -A]), number_type="float") + linsys = cdd.matrix_from_array(np.hstack([b, -A])) # type: ignore linsys.rep_type = cdd.RepType.INEQUALITY - # the input [d, -C] to cdd.Matrix.extend represents (d - C * x == 0) + # the input [d, -C] to the cdd function represents (d - C * x == 0) # see ftp://ftp.ifor.math.ethz.ch/pub/fukuda/cdd/cddlibman/node3.html if eq is not None: (C, d) = eq d = d.reshape((d.shape[0], 1)) - linsys.extend(np.hstack([d, -C]), linear=True) + new_matrix = cdd.matrix_from_array(np.hstack([d, -C])) # type: ignore + cdd.matrix_append_to(linsys, new_matrix) + linsys.rep_type = cdd.RepType.INEQUALITY if canonicalize: - linsys.canonicalize() + cdd.matrix_canonicalize(linsys) # Convert from H- to V-representation - P = cdd.Polyhedron(linsys) - generators = P.get_generators() + P = cdd.polyhedron_from_matrix(linsys) + generators = cdd.copy_generators(P) if generators.lin_set: print("Generators have linear set: {}".format(generators.lin_set)) - V = np.array(generators) + V = np.array(generators.array) # Project output wrenches to 2D set (E, f) = proj diff --git a/pyproject.toml b/pyproject.toml index 4be6cbf..4ae94ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,17 +12,17 @@ maintainers = [ {name = "Stéphane Caron", email = "stephane.caron@normalesup.org"}, ] dynamic = ['version', 'description'] -requires-python = ">=3.7" +requires-python = ">=3.9" classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Intended Audience :: Science/Research", "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", "Operating System :: OS Independent", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Scientific/Engineering :: Mathematics", "Intended Audience :: Developers", "Intended Audience :: Science/Research", @@ -31,7 +31,7 @@ dependencies = [ "cvxopt >=1.2.6", "matplotlib >=3.3.4", "numpy >=1.15.4", - "pycddlib >=2.1.4,<3", + "pycddlib >=3.0.0", "scipy >=1.7.0", ] keywords = ["convex, polyhedron, polyhedra, polytope, projection, duality"] diff --git a/tox.ini b/tox.ini index 3365dd7..b3b8fb9 100644 --- a/tox.ini +++ b/tox.ini @@ -13,13 +13,6 @@ PLATFORM = ubuntu-latest: linux windows-latest: windows -[testenv] -deps = - pyclipper >=1.3.0 - qpsolvers >=3.3.1 -commands = - python -m unittest discover - [testenv:coverage] deps = coverage >=5.5