PyDiffGame 1.0.0__tar.gz → 2.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. pydiffgame-2.0.1/.github/workflows/python-publish.yml +132 -0
  2. pydiffgame-2.0.1/.github/workflows/tests.yml +51 -0
  3. pydiffgame-2.0.1/.gitignore +26 -0
  4. pydiffgame-2.0.1/.pre-commit-config.yaml +29 -0
  5. pydiffgame-2.0.1/CLAUDE.md +32 -0
  6. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/CODE_OF_CONDUCT.md +1 -1
  7. pydiffgame-2.0.1/CONTRIBUTING.md +67 -0
  8. pydiffgame-2.0.1/PKG-INFO +421 -0
  9. pydiffgame-2.0.1/README.md +362 -0
  10. pydiffgame-2.0.1/docs/README.md +362 -0
  11. pydiffgame-2.0.1/images/readme/masses_cost.png +0 -0
  12. pydiffgame-2.0.1/images/readme/masses_game_vs_lqr.png +0 -0
  13. pydiffgame-2.0.1/images/readme/masses_schematic.png +0 -0
  14. pydiffgame-2.0.1/pyproject.toml +94 -0
  15. pydiffgame-2.0.1/requirements.txt +8 -0
  16. pydiffgame-2.0.1/src/PyDiffGame/__init__.py +50 -0
  17. pydiffgame-2.0.1/src/PyDiffGame/_typing.py +25 -0
  18. pydiffgame-2.0.1/src/PyDiffGame/base.py +468 -0
  19. pydiffgame-2.0.1/src/PyDiffGame/comparison.py +121 -0
  20. pydiffgame-2.0.1/src/PyDiffGame/continuous.py +223 -0
  21. pydiffgame-2.0.1/src/PyDiffGame/discrete.py +211 -0
  22. pydiffgame-2.0.1/src/PyDiffGame/examples/InvertedPendulumComparison.py +232 -0
  23. pydiffgame-2.0.1/src/PyDiffGame/examples/MassesWithSpringsComparison.py +119 -0
  24. pydiffgame-2.0.1/src/PyDiffGame/examples/PVTOL.py +216 -0
  25. pydiffgame-2.0.1/src/PyDiffGame/examples/PVTOLComparison.py +117 -0
  26. pydiffgame-2.0.1/src/PyDiffGame/examples/QuadRotorControl.py +638 -0
  27. pydiffgame-2.0.1/src/PyDiffGame/lqr.py +30 -0
  28. pydiffgame-2.0.1/src/PyDiffGame/objective.py +108 -0
  29. pydiffgame-2.0.1/src/PyDiffGame/plotting.py +98 -0
  30. pydiffgame-2.0.1/tests/conftest.py +9 -0
  31. pydiffgame-2.0.1/tests/test_discrete.py +50 -0
  32. pydiffgame-2.0.1/tests/test_examples.py +75 -0
  33. pydiffgame-2.0.1/tests/test_game.py +45 -0
  34. pydiffgame-2.0.1/tests/test_lqr.py +66 -0
  35. pydiffgame-2.0.1/tests/test_objective.py +45 -0
  36. pydiffgame-2.0.1/tests/test_simulation.py +60 -0
  37. pydiffgame-2.0.1/tools/bump_version.py +78 -0
  38. pydiffgame-2.0.1/tools/generate_readme_figures.py +336 -0
  39. pydiffgame-2.0.1/uv.lock +1298 -0
  40. pydiffgame-1.0.0/.github/workflows/python-publish.yml +0 -70
  41. pydiffgame-1.0.0/CONTRIBUTING.md +0 -18
  42. pydiffgame-1.0.0/PKG-INFO +0 -306
  43. pydiffgame-1.0.0/README.md +0 -292
  44. pydiffgame-1.0.0/docs/README.md +0 -277
  45. pydiffgame-1.0.0/pyproject.toml +0 -26
  46. pydiffgame-1.0.0/requirements.txt +0 -6
  47. pydiffgame-1.0.0/src/PyDiffGame/ContinuousPyDiffGame.py +0 -275
  48. pydiffgame-1.0.0/src/PyDiffGame/DiscretePyDiffGame.py +0 -359
  49. pydiffgame-1.0.0/src/PyDiffGame/LQR.py +0 -73
  50. pydiffgame-1.0.0/src/PyDiffGame/Objective.py +0 -62
  51. pydiffgame-1.0.0/src/PyDiffGame/PyDiffGame.py +0 -1273
  52. pydiffgame-1.0.0/src/PyDiffGame/PyDiffGameLQRComparison.py +0 -169
  53. pydiffgame-1.0.0/src/PyDiffGame/__init__.py +0 -0
  54. pydiffgame-1.0.0/src/PyDiffGame/examples/InvertedPendulumComparison.py +0 -257
  55. pydiffgame-1.0.0/src/PyDiffGame/examples/MassesWithSpringsComparison.py +0 -218
  56. pydiffgame-1.0.0/src/PyDiffGame/examples/PVTOL.py +0 -222
  57. pydiffgame-1.0.0/src/PyDiffGame/examples/PVTOLComparison.py +0 -111
  58. pydiffgame-1.0.0/src/PyDiffGame/examples/QuadRotorControl.py +0 -548
  59. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/CITATIONS.bib +0 -0
  60. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/LICENSE +0 -0
  61. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/_config.yml +0 -0
  62. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/images/Logo_ISTRC_Green_English.png +0 -0
  63. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/images/logo.png +0 -0
  64. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/images/logo_abc.png +0 -0
  65. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/2/2-players_large_1.png +0 -0
  66. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/2/2-players_large_2.png +0 -0
  67. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/2/LQR_large_1.png +0 -0
  68. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/2/LQR_large_2.png +0 -0
  69. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/2/two_masses_tikz.png +0 -0
  70. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/4/4-players_large_1.png +0 -0
  71. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/4/4-players_large_2.png +0 -0
  72. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/4/LQR_large_1.png +0 -0
  73. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/4/LQR_large_2.png +0 -0
  74. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/8/8-players_large_1.png +0 -0
  75. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/8/8-players_large_2.png +0 -0
  76. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/8/LQR_large_1.png +0 -0
  77. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/8/LQR_large_2.png +0 -0
  78. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/PVTOL/PVTOL1.png +0 -0
  79. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/PVTOL/PVTOL10.png +0 -0
  80. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/PVTOL/PVTOL100.png +0 -0
  81. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/PVTOL/PVTOL1000.png +0 -0
  82. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/PVTOL0001.png +0 -0
  83. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/PVTOL001.png +0 -0
  84. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/PVTOL01.png +0 -0
  85. {pydiffgame-1.0.0 → pydiffgame-2.0.1}/src/PyDiffGame/examples/figures/PVTOL1.png +0 -0
@@ -0,0 +1,132 @@
1
+ # Publishes the package to PyPI and creates the matching GitHub Release,
2
+ # auto-incrementing the version each run.
3
+ #
4
+ # Flow (just run it — Actions -> Upload Python Package -> Run workflow):
5
+ # 1. bump-version : increment the version (carry-at-9 via tools/bump_version.py),
6
+ # commit it back to master.
7
+ # 2. release-build : build the dists from the bumped master.
8
+ # 3. pypi-publish : upload to PyPI via Trusted Publishing (OIDC, no tokens).
9
+ # 4. github-release: create the v<version> GitHub Release with notes + dists.
10
+ #
11
+ # Versions roll over at 9: 2.0.9 -> 2.1.0, 2.9.9 -> 3.0.0.
12
+
13
+ name: Upload Python Package
14
+
15
+ on:
16
+ workflow_dispatch:
17
+
18
+ permissions:
19
+ contents: read
20
+
21
+ jobs:
22
+ bump-version:
23
+ runs-on: ubuntu-latest
24
+ permissions:
25
+ contents: write
26
+ outputs:
27
+ version: ${{ steps.bump.outputs.version }}
28
+ steps:
29
+ - uses: actions/checkout@v5
30
+ with:
31
+ ref: master
32
+
33
+ - name: Increment the version (carry-at-9)
34
+ id: bump
35
+ run: |
36
+ new="$(python3 tools/bump_version.py)"
37
+ echo "version=$new" >> "$GITHUB_OUTPUT"
38
+ echo "Bumped to $new"
39
+
40
+ - name: Commit and push the bump
41
+ run: |
42
+ git config user.name "github-actions[bot]"
43
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
44
+ git add pyproject.toml src/PyDiffGame/__init__.py
45
+ git commit -m "chore: bump version to ${{ steps.bump.outputs.version }} [skip ci]"
46
+ git push origin HEAD:master
47
+
48
+ release-build:
49
+ needs: bump-version
50
+ runs-on: ubuntu-latest
51
+ steps:
52
+ - uses: actions/checkout@v5
53
+ with:
54
+ ref: master # the bumped commit
55
+
56
+ - name: Install uv
57
+ uses: astral-sh/setup-uv@v6
58
+
59
+ - name: Build release distributions
60
+ run: uv build
61
+
62
+ - name: Upload distributions
63
+ uses: actions/upload-artifact@v5
64
+ with:
65
+ name: release-dists
66
+ path: dist/
67
+
68
+ pypi-publish:
69
+ needs:
70
+ - release-build
71
+ runs-on: ubuntu-latest
72
+ permissions:
73
+ # IMPORTANT: this permission is mandatory for trusted publishing
74
+ id-token: write
75
+
76
+ environment:
77
+ name: pypi
78
+ url: https://pypi.org/project/PyDiffGame/
79
+
80
+ steps:
81
+ - name: Retrieve release distributions
82
+ uses: actions/download-artifact@v5
83
+ with:
84
+ name: release-dists
85
+ path: dist/
86
+
87
+ # Authentication is via PyPI Trusted Publishing (OIDC) — no token needed.
88
+ # Trusted publisher on PyPI: owner krichelj, repo PyDiffGame,
89
+ # workflow python-publish.yml, environment pypi.
90
+ - name: Publish release distributions to PyPI
91
+ uses: pypa/gh-action-pypi-publish@release/v1
92
+ with:
93
+ packages-dir: dist/
94
+ # Don't fail if this version is already on PyPI (idempotent re-runs).
95
+ skip-existing: true
96
+
97
+ github-release:
98
+ needs:
99
+ - bump-version
100
+ - pypi-publish
101
+ runs-on: ubuntu-latest
102
+ permissions:
103
+ # Needed to create the release and its tag.
104
+ contents: write
105
+
106
+ steps:
107
+ - uses: actions/checkout@v5
108
+ with:
109
+ ref: master
110
+
111
+ - name: Retrieve release distributions
112
+ uses: actions/download-artifact@v5
113
+ with:
114
+ name: release-dists
115
+ path: dist/
116
+
117
+ - name: Create or update the GitHub Release
118
+ env:
119
+ GH_TOKEN: ${{ github.token }}
120
+ VERSION: ${{ needs.bump-version.outputs.version }}
121
+ run: |
122
+ tag="v${VERSION}"
123
+ echo "Releasing ${tag}"
124
+ if gh release view "$tag" >/dev/null 2>&1; then
125
+ echo "Release ${tag} already exists - refreshing its assets."
126
+ gh release upload "$tag" dist/* --clobber
127
+ else
128
+ gh release create "$tag" dist/* \
129
+ --title "$tag" \
130
+ --generate-notes \
131
+ --target master
132
+ fi
@@ -0,0 +1,51 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [master, main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: tests-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ test:
18
+ name: Python ${{ matrix.python-version }}
19
+ runs-on: ubuntu-latest
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
24
+
25
+ steps:
26
+ - uses: actions/checkout@v5
27
+
28
+ - name: Install uv
29
+ uses: astral-sh/setup-uv@v6
30
+ with:
31
+ enable-cache: true
32
+
33
+ - name: Set up Python ${{ matrix.python-version }}
34
+ run: uv python install ${{ matrix.python-version }}
35
+
36
+ - name: Sync the environment (locked)
37
+ run: uv sync --extra dev --python ${{ matrix.python-version }} --frozen
38
+
39
+ - name: Lint with ruff
40
+ run: uv run ruff check src/PyDiffGame tests --exclude src/PyDiffGame/examples
41
+
42
+ - name: Check formatting with ruff
43
+ run: uv run ruff format --check src/PyDiffGame tests
44
+
45
+ - name: Type-check with mypy
46
+ run: uv run mypy src/PyDiffGame --exclude 'examples'
47
+
48
+ - name: Run the test suite
49
+ env:
50
+ MPLBACKEND: Agg
51
+ run: uv run pytest -q
@@ -0,0 +1,26 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ .eggs/
7
+ build/
8
+ dist/
9
+ *.so
10
+
11
+ # Virtual environments
12
+ .venv*/
13
+ venv/
14
+ env/
15
+
16
+ # Test / coverage
17
+ .pytest_cache/
18
+ .coverage
19
+ htmlcov/
20
+ .mypy_cache/
21
+ .ruff_cache/
22
+
23
+ # OS / editors
24
+ .DS_Store
25
+ .idea/
26
+ .vscode/
@@ -0,0 +1,29 @@
1
+ # Pre-commit hooks for PyDiffGame.
2
+ # Install once with: pre-commit install
3
+ # Run on everything: pre-commit run --all-files
4
+ repos:
5
+ - repo: https://github.com/pre-commit/pre-commit-hooks
6
+ rev: v5.0.0
7
+ hooks:
8
+ - id: trailing-whitespace
9
+ - id: end-of-file-fixer
10
+ - id: check-yaml
11
+ - id: check-toml
12
+ - id: check-added-large-files
13
+ - id: check-merge-conflict
14
+
15
+ - repo: https://github.com/astral-sh/ruff-pre-commit
16
+ rev: v0.8.4
17
+ hooks:
18
+ # Linter (with autofix), then the black-compatible formatter.
19
+ - id: ruff
20
+ args: [--fix]
21
+ - id: ruff-format
22
+
23
+ - repo: https://github.com/pre-commit/mirrors-mypy
24
+ rev: v1.13.0
25
+ hooks:
26
+ - id: mypy
27
+ files: ^src/PyDiffGame/
28
+ exclude: ^src/PyDiffGame/examples/
29
+ additional_dependencies: [numpy]
@@ -0,0 +1,32 @@
1
+ # PyDiffGame — repository guide for Claude
2
+
3
+ ## Python tooling (uv-first)
4
+ - Use **uv** for everything; pip is only a documented fallback.
5
+ - `uv sync --extra dev`, `uv run pytest`, `uv run ruff check`, `uv run ruff format`,
6
+ `uv run mypy src/PyDiffGame`, `uv build`.
7
+ - Keep the quality gates green before committing: ruff format, ruff check, mypy on
8
+ `src/PyDiffGame`, and the pytest suite — all via `uv run`.
9
+
10
+ ## Versioning (carry-at-9)
11
+ - The version is `X.Y.Z` with single-digit components that roll over at 9:
12
+ `2.0.9 -> 2.1.0`, `2.9.9 -> 3.0.0` (the major keeps growing).
13
+ - Increment **only** via `tools/bump_version.py`, which updates the version in both
14
+ `pyproject.toml` and `src/PyDiffGame/__init__.py`. Never hand-edit version strings.
15
+ - The version is bumped **automatically** by the publish workflow on each release, so
16
+ do not bump it in ordinary PRs — the release run does it.
17
+
18
+ ## Releasing
19
+ - `Actions -> Upload Python Package -> Run workflow` (on `master`). The workflow
20
+ auto-increments the version, commits it to `master`, builds with `uv build`,
21
+ publishes to PyPI via Trusted Publishing (OIDC, no tokens), and creates the matching
22
+ `v<version>` GitHub Release with notes and the built dists attached. It is idempotent
23
+ (`skip-existing`).
24
+
25
+ ## Docs
26
+ - `README.md` is the single canonical readme and is also the PyPI long-description
27
+ (`pyproject.toml: readme = "README.md"`), so its image/file links must be **absolute**
28
+ (`raw.githubusercontent.com/.../master/...` for images, `github.com/.../blob/master/...`
29
+ for files) so they render on PyPI.
30
+ - Keep `docs/README.md` identical to `README.md`.
31
+ - README figures are generated from the live solver:
32
+ `uv run python tools/generate_readme_figures.py`.
@@ -60,7 +60,7 @@ representative at an online or offline event.
60
60
 
61
61
  Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
62
  reported to the community leaders responsible for enforcement at
63
- .
63
+ skricheli2@gmail.com.
64
64
  All complaints will be reviewed and investigated promptly and fairly.
65
65
 
66
66
  All community leaders are obligated to respect the privacy and security of the
@@ -0,0 +1,67 @@
1
+ # Contribution Guidelines
2
+
3
+ This repo is part of a research conducted at Ben Gurion University,
4
+ and is thus open source. We would love to receive your input!
5
+
6
+ Please ensure your pull request adheres to the following guidelines:
7
+
8
+ - Search previous suggestions before making a new one, as yours may be a duplicate.
9
+ - Make an individual pull request for each suggestion.
10
+ - New categories or improvements to the existing categorization are welcome.
11
+ - Check your spelling and grammar.
12
+ - Make sure your text editor is set to remove trailing whitespace.
13
+ - The pull request and commit should have a useful title.
14
+
15
+ ## Development setup
16
+
17
+ PyDiffGame requires **Python >= 3.11** and uses [uv](https://docs.astral.sh/uv/)
18
+ for environment and dependency management. Install uv, sync the locked
19
+ development environment, and enable the pre-commit hooks so the code-quality
20
+ tools run automatically on every commit:
21
+
22
+ ```bash
23
+ # install uv: https://docs.astral.sh/uv/getting-started/installation/
24
+ uv sync --extra dev
25
+ uv run pre-commit install
26
+ ```
27
+
28
+ `uv sync` creates the virtual environment and installs the exact, locked
29
+ dependencies. Run the tooling through `uv run`:
30
+
31
+ ```bash
32
+ uv run ruff format src/PyDiffGame tests # auto-format (black-compatible)
33
+ uv run ruff check src/PyDiffGame tests # lint
34
+ uv run mypy src/PyDiffGame # type-check
35
+ uv run pytest # test suite
36
+ ```
37
+
38
+ Continuous integration runs the formatter check, the linter, the type checker
39
+ and the full suite (all via uv) across Python 3.11–3.14, so please make sure
40
+ they pass locally.
41
+
42
+ ## Releasing
43
+
44
+ Publishing a new version is a single automated step — just run the publish
45
+ workflow: **Actions -> Upload Python Package -> Run workflow** (on `master`).
46
+
47
+ The run automatically:
48
+
49
+ 1. **Increments the version** with `tools/bump_version.py`, which rolls each
50
+ component over at 9 (`2.0.9 -> 2.1.0`, `2.9.9 -> 3.0.0`), updating both
51
+ `pyproject.toml` and `src/PyDiffGame/__init__.py`, and commits the bump to
52
+ `master`.
53
+ 2. Builds the distributions with `uv build`.
54
+ 3. Uploads them to PyPI via
55
+ [Trusted Publishing](https://docs.pypi.org/trusted-publishers/) (OIDC — no
56
+ tokens or secrets).
57
+ 4. Creates a `v<version>` GitHub Release with auto-generated notes and the built
58
+ wheels/sdist attached.
59
+
60
+ You normally never edit the version by hand. To bump it locally (e.g. to test),
61
+ run `uv run python tools/bump_version.py` (`--dry-run` to preview, `--current`
62
+ to print the current version). The PyPI upload is idempotent (`skip-existing`),
63
+ so re-running the workflow is safe.
64
+
65
+ Thank you for your contribution!
66
+
67
+ Joshua Shay Kricheli