Skip to content

Commit b116724

Browse files
committed
Pre-publish v0.1.0
1 parent 8c3a69a commit b116724

38 files changed

Lines changed: 412 additions & 400 deletions

.github/workflows/ci.yaml

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Continuous Integration
33
on:
44
pull_request:
55
push:
6-
branches: [ master ]
6+
branches: [ main ]
77

88
concurrency:
99
# github.workflow: name of the workflow
@@ -14,22 +14,23 @@ concurrency:
1414
cancel-in-progress: true
1515

1616
jobs:
17-
precommit:
18-
name: Pre-commit checks
17+
pre-commit-checks:
18+
name: Pre-commit Hooks
1919
runs-on: ubuntu-latest
2020
steps:
21-
- uses: actions/checkout@v4
21+
- name: Checkout Repository
22+
uses: actions/checkout@v4
2223

2324
- name: Install uv
2425
uses: astral-sh/setup-uv@v5
2526

26-
- name: Pre-commit checks
27+
- name: Run Pre-commit Checks
2728
# uses: pre-commit/action@v3.0.1
2829
run: uvx --isolated --with pre-commit-uv pre-commit run --all-files --show-diff-on-failure
2930

30-
test:
31-
needs: precommit
32-
name: Tests
31+
unit-tests:
32+
needs: pre-commit-checks
33+
name: Run Tests
3334
runs-on: ubuntu-latest
3435
env:
3536
UV_COMPILE_BYTECODE: 1
@@ -51,7 +52,8 @@ jobs:
5152
- python-version: "3.11"
5253
TORCH_VERSION: "1.13.1"
5354
steps:
54-
- uses: actions/checkout@v4
55+
- name: Checkout Repository
56+
uses: actions/checkout@v4
5557

5658
- name: Intall uv & Set up Python ${{ matrix.python-version }}
5759
uses: astral-sh/setup-uv@v5
@@ -64,8 +66,53 @@ jobs:
6466
uv sync --group tests --no-install-package torch
6567
uv pip install torch==${{ matrix.TORCH_VERSION }}
6668
67-
- name: Launch tests
69+
- name: Run Unit Tests
6870
# Only run the unit tests, not the pipeline tests.
6971
# Pipeline tests are too expensive to run for every python/PyTorch version.
70-
# However, they are run as part the coverage job in the CI workflow
72+
# However, they are run as part the check-coverage job.
7173
run: uv run --no-sync pytest --ignore=tests/pipeline tests
74+
75+
check-coverage:
76+
needs: unit-tests
77+
name: Check Coverage
78+
runs-on: ubuntu-latest
79+
permissions:
80+
# Gives the action the necessary permissions for publishing new
81+
# comments in pull requests.
82+
pull-requests: write
83+
# Gives the action the necessary permissions for pushing data to the
84+
# python-coverage-comment-action branch, and for editing existing
85+
# comments (to avoid publishing multiple comments in the same PR)
86+
contents: write
87+
env:
88+
UV_COMPILE_BYTECODE: 1
89+
steps:
90+
- name: Checkout Repository
91+
uses: actions/checkout@v4
92+
93+
- name: Install uv
94+
uses: astral-sh/setup-uv@v5
95+
with:
96+
enable-cache: true
97+
98+
- name: Run Tests & Generate Coverage Report
99+
run: uv run --locked --group tests coverage run -m pytest tests
100+
101+
- name: Coverage comment
102+
id: coverage_comment
103+
uses: py-cov-action/python-coverage-comment-action@v3
104+
with:
105+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
106+
# If the coverage percentage is above or equal to this value, the badge will be green.
107+
MINIMUM_GREEN: 90
108+
# If the coverage percentage is below this value, the badge will be red.
109+
MINIMUM_ORANGE: 80
110+
111+
- name: Store Coverage Comment Artifact
112+
uses: actions/upload-artifact@v4
113+
if: steps.coverage_comment.outputs.COMMENT_FILE_WRITTEN == 'true'
114+
with:
115+
# If you use a different name, update COMMENT_ARTIFACT_NAME accordingly
116+
name: python-coverage-comment-action
117+
# If you use a different name, update COMMENT_FILENAME accordingly
118+
path: python-coverage-comment-action.txt

.github/workflows/coverage.yaml

Lines changed: 0 additions & 58 deletions
This file was deleted.
Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
name: Post coverage comment
1+
name: Post Coverage Comment
22

33
on:
44
workflow_run:
5-
workflows: [ "Coverage" ]
5+
workflows: [ "Continuous Integration" ]
66
types: [ completed ]
77

88
jobs:
99
push-coverage-comment:
10-
name: Run tests & display coverage
10+
name: Publish Coverage Comment
1111
runs-on: ubuntu-latest
1212
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
1313
permissions:
@@ -22,12 +22,8 @@ jobs:
2222
# artifact that contains the comment to be published
2323
actions: read
2424
steps:
25-
- name: Post comment
25+
- name: Post Comment
2626
uses: py-cov-action/python-coverage-comment-action@v3
2727
with:
2828
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2929
GITHUB_PR_RUN_ID: ${{ github.event.workflow_run.id }}
30-
# If the coverage percentage is above or equal to this value, the badge will be green.
31-
MINIMUM_GREEN: 90
32-
# If the coverage percentage is below this value, the badge will be red.
33-
MINIMUM_ORANGE: 80

.github/workflows/release.yaml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Publish package
1+
name: Publish Package
22

33
on:
44
workflow_dispatch:
@@ -7,31 +7,34 @@ on:
77
- 'v[0-9]+\.[0-9]+\.[0-9]+'
88

99
jobs:
10-
publish:
10+
build-and-publish:
1111
runs-on: ubuntu-latest
1212
permissions:
13-
contents: write # Needed for making GitHub releases
14-
id-token: write # Needed for trusted publishing to PyPI
13+
contents: write # Required to create GitHub releases
14+
id-token: write # Required for trusted PyPI publishing via OIDC
1515
steps:
16-
- uses: actions/checkout@v4
16+
- name: Checkout Repository
17+
uses: actions/checkout@v4
1718

1819
- name: Set up uv
1920
uses: astral-sh/setup-uv@v5
2021

21-
- name: Build package
22+
- name: Build Package
2223
id: build
2324
run: uv build
2425

25-
- name: Publish package to PyPI
26+
- name: Publish to PyPI
2627
id: pypi
2728
if: steps.build.outcome == 'success'
2829
uses: pypa/gh-action-pypi-publish@release/v1
2930
with:
3031
attestations: true
3132

32-
- name: Publish release to GitHub
33+
- name: Create GitHub Release
3334
if: steps.pypi.outcome == 'success'
3435
uses: softprops/action-gh-release@v2
3536
with:
36-
files: dist/*
37+
files: |
38+
dist/*.whl
39+
dist/*.tar.gz
3740
token: ${{ secrets.GITHUB_TOKEN }}

CITATION.cff

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ authors:
1313
given-names: Simon
1414
identifiers:
1515
- type: other
16-
value: 'arXiv:TODO:2503.xxxxx'
16+
value: 'arXiv:2504.01212'
1717
description: The ArXiv preprint of the paper
1818
repository-code: 'https://github.com/cooper-org/cooper'
1919
url: 'https://github.com/cooper-org/cooper'
@@ -32,4 +32,18 @@ keywords:
3232
- machine learning
3333
license: MIT
3434
version: 0.1.0
35-
date-released: '2025-01-01'
35+
date-released: '2025-04-01'
36+
preferred-citation:
37+
type: article
38+
title: 'Cooper: A Library for Constrained Optimization in Deep Learning'
39+
authors:
40+
- family-names: Gallego-Posada
41+
given-names: Jose
42+
- family-names: Ramirez
43+
given-names: Juan
44+
- family-names: Hashemizadeh
45+
given-names: Meraj
46+
- family-names: Lacoste-Julien
47+
given-names: Simon
48+
journal: "arXiv preprint arXiv:2504.01212"
49+
year: 2025

README.md

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# **Cooper**
22

3-
[![LICENSE](https://img.shields.io/pypi/l/cooper-optim)](https://github.com/cooper-org/cooper/tree/master/LICENSE)
3+
[![LICENSE](https://img.shields.io/pypi/l/cooper-optim)](https://github.com/cooper-org/cooper/tree/main/LICENSE)
44
[![Version](https://img.shields.io/pypi/v/cooper-optim?label=version)](https://pypi.python.org/pypi/cooper-optim)
55
[![Downloads](https://img.shields.io/pepy/dt/cooper-optim?color=blue)](https://pypi.python.org/pypi/cooper-optim)
66
[![Python](https://img.shields.io/pypi/pyversions/cooper-optim?label=Python&logo=python&logoColor=white)](https://pypi.python.org/pypi/cooper-optim)
77
[![PyTorch](https://img.shields.io/badge/PyTorch-1.13.1+-EE4C2C?logo=pytorch)](https://pytorch.org/docs/stable/index.html)
88
[![DOCS](https://img.shields.io/readthedocs/cooper)](https://cooper.readthedocs.io/en/latest/?version=latest)
99
[![Coverage badge](https://raw.githubusercontent.com/cooper-org/cooper/python-coverage-comment-action-data/badge.svg)](https://github.com/cooper-org/cooper/tree/python-coverage-comment-action-data)
10-
[![Continuous Integration](https://github.com/cooper-org/cooper/actions/workflows/ci.yml/badge.svg)](https://github.com/cooper-org/cooper/actions/workflows/ci.yml)
10+
[![Continuous Integration](https://github.com/cooper-org/cooper/actions/workflows/ci.yaml/badge.svg)](https://github.com/cooper-org/cooper/actions/workflows/ci.yaml)
1111
[![Stars](https://img.shields.io/github/stars/cooper-org/cooper)](https://github.com/cooper-org/cooper)
1212
[![HitCount](https://hits.sh/github.com/cooper-org/cooper.svg)](https://cooper.readthedocs.io/en/latest/?version=latest)
1313
[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen)](https://github.com/cooper-org/cooper/issues)
@@ -24,7 +24,7 @@ There exist other libraries for constrained optimization in PyTorch, like [CHOP]
2424

2525
You can check out **Cooper**'s FAQ [here](#faq).
2626

27-
TODO(juan43ramirez): mention Cooper MLOSS paper
27+
**Cooper**'s companion paper is available [here](https://arxiv.org/abs/2504.01212).
2828

2929
- [**Cooper**](#cooper)
3030
- [What is **Cooper**?](#what-is-cooper)
@@ -40,7 +40,7 @@ TODO(juan43ramirez): mention Cooper MLOSS paper
4040

4141
## Installation
4242

43-
To install the latest release of Cooper, use the following command:
43+
To install the latest release of **Cooper**, use the following command:
4444

4545
```bash
4646
pip install cooper-optim
@@ -49,7 +49,7 @@ pip install cooper-optim
4949
To install the latest **development** version, use the following command instead:
5050

5151
```bash
52-
pip install git+https://github.com/cooper-org/cooper@dev
52+
pip install git+https://github.com/cooper-org/cooper@main
5353
```
5454

5555
## Getting Started
@@ -59,21 +59,21 @@ pip install git+https://github.com/cooper-org/cooper@dev
5959

6060
To use **Cooper**, you need to:
6161

62-
- Implement a {py:class}`~cooper.ConstrainedMinimizationProblem` (CMP) class and its associated {py:meth}`~cooper.ConstrainedMinimizationProblem.compute_cmp_state` method. This method computes the value of the objective function and constraint violations, and packages them in a {py:class}`~cooper.CMPState` object.
63-
- The initialization of the {py:class}`CMP<cooper.cmp.ConstrainedMinimizationProblem>` must create a {py:class}`~cooper.constraints.Constraint` object for each constraint. It is necessary to specify a formulation type (e.g. {py:class}`~cooper.formulations.Lagrangian`). Finally, if the chosen formulation requires it, each constraint needs an associated {py:class}`~cooper.Multiplier` object corresponding to the Lagrange multiplier for that constraint.
64-
- Create a {py:class}`torch.optim.Optimizer` for the primal variables and a {py:class}`torch.optim.Optimizer(maximize=True)` for the dual variables (i.e. the multipliers). Then, wrap these two optimizers in a {py:class}`cooper.optim.CooperOptimizer` (such as {py:class}`~cooper.optim.constrained_optimizer.SimultaneousOptimizer` for executing simultaneous primal-dual updates).
65-
- You are now ready to perform updates on the primal and dual parameters using the {py:meth}`cooper.optim.CooperOptimizer.roll` method. This method triggers the following calls:
66-
- {py:meth}`zero_grad` on both optimizers,
67-
- {py:meth}`~cooper.ConstrainedMinimizationProblem.compute_cmp_state` on the {py:class}`CMP<cooper.cmp.ConstrainedMinimizationProblem>`,
68-
- compute the Lagrangian based on the latest {py:class}`~cooper.cmp.CMPState`,
69-
- {py:meth}`backward` on the Lagrangian,
70-
- {py:meth}`~torch.optim.Optimizer.step` on both optimizers.
71-
- To access the value of the loss, constraint violations, and Lagrangian terms, you can inspect the returned {py:class}`~cooper.optim.RollOut` object from the call to {py:meth}`~cooper.optim.CooperOptimizer.roll`.
62+
- Implement a [`ConstrainedMinimizationProblem`](https://cooper.readthedocs.io/en/latest/problem.html#cooper.ConstrainedMinimizationProblem) (CMP) class and its associated [`ConstrainedMinimizationProblem.compute_cmp_state`](https://cooper.readthedocs.io/en/latest/problem.html#cooper.ConstrainedMinimizationProblem.compute_cmp_state) method. This method computes the value of the objective function and constraint violations, and packages them in a [`CMPState`](https://cooper.readthedocs.io/en/latest/problem.html#cooper.CMPState) object.
63+
- The initialization of the [`CMP`](https://cooper.readthedocs.io/en/latest/problem.html#cooper.ConstrainedMinimizationProblem) must create a [`Constraint`](https://cooper.readthedocs.io/en/latest/problem.html#cooper.constraints.Constraint) object for each constraint. It is necessary to specify a formulation type (e.g. [`Lagrangian`](https://cooper.readthedocs.io/en/latest/formulations.html#cooper.formulations.Lagrangian)). Finally, if the chosen formulation requires it, each constraint needs an associated [`Multiplier`](https://cooper.readthedocs.io/en/latest/multipliers.html) object corresponding to the Lagrange multiplier for that constraint.
64+
- Create a [`torch.optim.Optimizer`](https://pytorch.org/docs/stable/optim.html#torch.optim.Optimizer) for the primal variables and a [`torch.optim.Optimizer(maximize=True)`](https://pytorch.org/docs/stable/optim.html#torch.optim.Optimizer) for the dual variables (i.e. the multipliers). Then, wrap these two optimizers in a [`cooper.optim.CooperOptimizer`](https://cooper.readthedocs.io/en/latest/optim.html#cooper.optim.CooperOptimizer) (such as [`SimultaneousOptimizer`](https://cooper.readthedocs.io/en/latest/optim.html#cooper.optim.SimultaneousOptimizer) for executing simultaneous primal-dual updates).
65+
- You are now ready to perform updates on the primal and dual parameters using the [`CooperOptimizer.roll()`](https://cooper.readthedocs.io/en/latest/optim.html#cooper.optim.CooperOptimizer.roll) method. This method triggers the following calls:
66+
- `zero_grad()` on both optimizers,
67+
- [`compute_cmp_state()`](https://cooper.readthedocs.io/en/latest/problem.html#cooper.ConstrainedMinimizationProblem.compute_cmp_state) on the [`CMP`](https://cooper.readthedocs.io/en/latest/problem.html#cooper.ConstrainedMinimizationProblem),
68+
- compute the Lagrangian based on the latest [`CMPState`](https://cooper.readthedocs.io/en/latest/problem.html#cooper.CMPState),
69+
- `backward()` on the Lagrangian,
70+
- [`step()`](https://pytorch.org/docs/stable/generated/torch.optim.Optimizer.step.html#torch.optim.Optimizer.step) on both optimizers.
71+
- To access the value of the loss, constraint violations, and Lagrangian terms, you can inspect the returned [`RollOut`](https://cooper.readthedocs.io/en/latest/optim.html#cooper.optim.RollOut) object from the call to [`roll()`](https://cooper.readthedocs.io/en/latest/optim.html#cooper.optim.CooperOptimizer.roll).
7272

7373
### Example
7474

7575
This is an abstract example on how to solve a constrained optimization problem with
76-
**Cooper**. You can find runnable notebooks with concrete examples in our [**Tutorials**](https://cooper.readthedocs.io/en/master/notebooks/index.html).
76+
**Cooper**. You can find runnable notebooks with concrete examples in our [**Tutorials**](https://cooper.readthedocs.io/en/latest/notebooks/index.html).
7777

7878
```python
7979
import cooper
@@ -126,28 +126,29 @@ for epoch_num in range(NUM_EPOCHS):
126126

127127
We appreciate all contributions. Please let us know if you encounter a bug by [filing an issue](https://github.com/cooper-org/cooper/issues).
128128

129-
If you plan to contribute new features, utility functions, or extensions, please first open an issue and discuss the feature with us. To learn more about making a contribution to **Cooper**, please see our [Contribution page](https://cooper.readthedocs.io/en/master/notebooks/CONTRIBUTING.html).
129+
If you plan to contribute new features, utility functions, or extensions, please first open an issue and discuss the feature with us. To learn more about making a contribution to **Cooper**, please see our [Contribution page](https://cooper.readthedocs.io/en/latest/CONTRIBUTING.html).
130130

131131

132132
## Acknowledgements
133133

134134
We thank Manuel Del Verme, Daniel Otero, and Isabel Urrego for useful discussions during the early stages of **Cooper**.
135135

136+
Many **Cooper** features arose during the development of several research papers. We would like to thank our co-authors Yoshua Bengio, Juan Elenter, Akram Erraqabi, Golnoosh Farnadi, Ignacio Hounie, Alejandro Ribeiro, Rohan Sukumaran, Motahareh Sohrabi and Tianyue (Helen) Zhang.
137+
136138
## License
137139

138140
**Cooper** is distributed under an MIT license, as found in the
139-
[LICENSE](https://github.com/cooper-org/cooper/tree/master/LICENSE) file.
141+
[LICENSE](https://github.com/cooper-org/cooper/tree/main/LICENSE) file.
140142

141143
## How to cite **Cooper**
142144

143-
To cite **Cooper**, please cite [this paper](link-to-paper):
144-
TODO: Add paper link
145+
To cite **Cooper**, please cite [this paper](https://arxiv.org/abs/2504.01212):
145146

146147
```bibtex
147-
@misc{gallegoPosada2025cooper,
148+
@article{gallegoPosada2025cooper,
148149
author={Gallego-Posada, Jose and Ramirez, Juan and Hashemizadeh, Meraj and Lacoste-Julien, Simon},
149150
title={{Cooper: A Library for Constrained Optimization in Deep Learning}},
150-
howpublished={\url{https://github.com/cooper-org/cooper}},
151+
journal={arXiv preprint arXiv:2504.01212},
151152
year={2025}
152153
}
153154
```

docs/source/CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ uv run jupytext --sync path/to/notebook.ipynb
143143
```
144144

145145
The jupytext version should match that specified in
146-
[.pre-commit-config.yaml](https://github.com/cooper-org/cooper/blob/master/.pre-commit-config.yaml).
146+
[.pre-commit-config.yaml](https://github.com/cooper-org/cooper/blob/main/.pre-commit-config.yaml).
147147

148148
To check that the markdown and ipynb files are properly synced, you may use the [pre-commit](https://pre-commit.com/) framework to perform the same check used by the GitHub CI:
149149

0 commit comments

Comments
 (0)