docs: add MPPI rollout sampling and EKF estimation showcase GIFs #80
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | ||
| on: | ||
| push: | ||
| branches: [ "main", "develop" ] | ||
| pull_request: | ||
| branches: [ "main", "develop" ] | ||
| jobs: | ||
| dependency-contract: | ||
| runs-on: ubuntu-latest | ||
| env: | ||
| JAX_PLATFORM_NAME: cpu | ||
| UV_CACHE_DIR: /tmp/.uv-cache | ||
| JAX_COMPILATION_CACHE_DIR: /tmp/jax_cache | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Set up Python 3.10 | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: "3.10" | ||
| - name: Cache uv | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: /tmp/.uv-cache | ||
| key: ${{ runner.os }}-uv-${{ hashFiles('uv.lock') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-uv- | ||
| - name: Install base package (no extras) | ||
| env: | ||
| UV_SYSTEM_PYTHON: 1 | ||
| run: | | ||
| pip install uv | ||
| uv pip install -e . | ||
| - name: Validate optional dependency contracts | ||
| run: | | ||
| python - <<'PY' | ||
| import importlib.util | ||
| import os | ||
| import runpy | ||
| import tempfile | ||
| from pathlib import Path | ||
| import jax.numpy as jnp | ||
| cache_root = Path(tempfile.gettempdir()) / "cbfkit_optional_dep_cache" | ||
| cache_root.mkdir(parents=True, exist_ok=True) | ||
| mpl_cache = cache_root / "mpl" | ||
| xdg_cache = cache_root / "xdg" | ||
| mpl_cache.mkdir(parents=True, exist_ok=True) | ||
| xdg_cache.mkdir(parents=True, exist_ok=True) | ||
| os.environ.setdefault("MPLCONFIGDIR", str(mpl_cache)) | ||
| os.environ.setdefault("XDG_CACHE_HOME", str(xdg_cache)) | ||
| import cbfkit.utils.visualization as visualization | ||
| if importlib.util.find_spec("casadi") is None: | ||
| module_path = Path("src/cbfkit/optimization/quadratic_program/qp_solver_casadi.py") | ||
| qp_solver_casadi_ns = runpy.run_path(str(module_path)) | ||
| solve = qp_solver_casadi_ns["solve"] | ||
| try: | ||
| solve(jnp.eye(1), jnp.zeros((1,))) | ||
| except ImportError as exc: | ||
| if "cbfkit[casadi]" not in str(exc): | ||
| raise AssertionError( | ||
| "CasADi missing-path error must include guidance for `cbfkit[casadi]`." | ||
| ) from exc | ||
| else: | ||
| raise AssertionError("Expected ImportError with installation guidance for CasADi.") | ||
| if not visualization.HAS_MATPLOTLIB: | ||
| try: | ||
| visualization.require_visualization() | ||
| except ImportError as exc: | ||
| if "cbfkit[vis]" not in str(exc): | ||
| raise AssertionError( | ||
| "Visualization missing-path error must include guidance for `cbfkit[vis]`." | ||
| ) from exc | ||
| else: | ||
| raise AssertionError( | ||
| "Expected ImportError with installation guidance for visualization." | ||
| ) | ||
| print("optional dependency contract checks passed") | ||
| PY | ||
| extra-profile-smoke: | ||
| needs: dependency-contract | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| matrix: | ||
| profile: ["test", "codegen", "vis", "casadi"] | ||
| env: | ||
| JAX_PLATFORM_NAME: cpu | ||
| UV_CACHE_DIR: /tmp/.uv-cache | ||
| MPLCONFIGDIR: /tmp/.mplconfig | ||
| XDG_CACHE_HOME: /tmp/.xdg-cache | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Set up Python 3.10 | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: "3.10" | ||
| - name: Cache uv | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: /tmp/.uv-cache | ||
| key: ${{ runner.os }}-uv-${{ hashFiles('uv.lock') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-uv- | ||
| - name: Install profile and run smoke checks | ||
| env: | ||
| UV_SYSTEM_PYTHON: 1 | ||
| run: | | ||
| pip install uv | ||
| case "${{ matrix.profile }}" in | ||
| test) | ||
| uv pip install -e ".[test]" | ||
| python - <<'PY' | ||
| import pytest | ||
| import dotenv | ||
| print("test profile smoke ok", pytest.__version__, bool(dotenv)) | ||
| PY | ||
| ;; | ||
| codegen) | ||
| uv pip install -e ".[codegen]" | ||
| python - <<'PY' | ||
| from cbfkit.codegen.create_new_system.generate_model import generate_model | ||
| assert callable(generate_model) | ||
| print("codegen profile smoke ok") | ||
| PY | ||
| ;; | ||
| vis) | ||
| uv pip install -e ".[vis]" | ||
| python - <<'PY' | ||
| import cbfkit.utils.visualization as visualization | ||
| visualization.require_visualization() | ||
| print("vis profile smoke ok") | ||
| PY | ||
| ;; | ||
| casadi) | ||
| uv pip install -e ".[casadi]" | ||
| python - <<'PY' | ||
| import jax.numpy as jnp | ||
| from cbfkit.optimization.quadratic_program.qp_solver_casadi import solve | ||
| P = jnp.eye(1) | ||
| q = jnp.zeros((1,)) | ||
| G = jnp.array([[1.0], [-1.0]]) | ||
| h = jnp.array([1.0, 1.0]) | ||
| sol, status = solve(P, q, G, h) | ||
| assert sol.shape == (1,) | ||
| assert status in (0, 1) | ||
| print("casadi profile smoke ok", int(status)) | ||
| PY | ||
| ;; | ||
| *) | ||
| echo "Unknown profile: ${{ matrix.profile }}" >&2 | ||
| exit 2 | ||
| ;; | ||
| esac | ||
| build: | ||
| needs: [dependency-contract, extra-profile-smoke] | ||
| runs-on: ubuntu-latest | ||
| env: | ||
| JAX_PLATFORM_NAME: cpu | ||
| UV_CACHE_DIR: /tmp/.uv-cache | ||
| JAX_COMPILATION_CACHE_DIR: /tmp/jax_cache | ||
| strategy: | ||
| matrix: | ||
| python-version: ["3.10", "3.11", "3.12"] | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Set up Python ${{ matrix.python-version }} | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: ${{ matrix.python-version }} | ||
| - name: Cache uv | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: /tmp/.uv-cache | ||
| key: ${{ runner.os }}-uv-${{ hashFiles('uv.lock') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-uv- | ||
| - name: Cache JAX compilation | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: /tmp/jax_cache | ||
| key: ${{ runner.os }}-jax-${{ github.sha }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-jax- | ||
| - name: Install dependencies | ||
| env: | ||
| UV_SYSTEM_PYTHON: 1 | ||
| run: | | ||
| pip install uv | ||
| if [ "${{ matrix.python-version }}" == "3.10" ]; then | ||
| uv pip install -e ".[test,codegen]" ruff mypy | ||
| else | ||
| uv pip install -e ".[test,codegen]" | ||
| fi | ||
| - name: Lint with ruff | ||
| if: matrix.python-version == '3.10' | ||
| env: | ||
| UV_SYSTEM_PYTHON: 1 | ||
| run: | | ||
| # Run ruff check. Exit non-zero on failure. | ||
| ruff check src | ||
| - name: Type check with mypy | ||
| if: matrix.python-version == '3.10' | ||
| env: | ||
| UV_SYSTEM_PYTHON: 1 | ||
| run: | | ||
| mypy src/cbfkit || true | ||
| - name: Test with pytest | ||
| run: | | ||
| pytest -m "not slow" tests | ||
| - name: Test slow tests | ||
| if: matrix.python-version == '3.10' | ||
| env: | ||
| CBFKIT_TEST_MODE: "1" | ||
| run: | | ||
| pytest -m "slow" tests | ||