Skip to content

Commit 40dc560

Browse files
authored
Merge LPGD into diffcp (#67)
* Update README.md * Add LPGD * Update Readme * simplify argument passing * add more lpgd examples * Catch error if perturbed problem infeasible * Give better error message on infeasibility * fix docstrings * minor changes * cosmetic changes * update readme * move perturbed solution computation to utils * cosmetics * resolve domments on pull request + minor edits * add differentiation w.r.t. P * add examples for differentiating w.r.t. P * minor cosmetic change * mention in docstring that return_dP is currently only possible in LPGD mode * Update readme for for quadratic objectives, specify when differentiation wrt P is possible. * Testing merged version, examples run but remove some ununsed imports
1 parent 52f313b commit 40dc560

14 files changed

+801
-139
lines changed

README.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ MARCH_NATIVE=1 OPENMP_FLAG="-fopenmp" pip install diffcp
4747
`diffcp` differentiates through a primal-dual cone program pair. The primal problem must be expressed as
4848

4949
```
50-
minimize c'x
50+
minimize c'x + x'Px
5151
subject to Ax + s = b
5252
s in K
5353
```
54-
where `x` and `s` are variables, `A`, `b` and `c` are the user-supplied problem data, and `K` is a user-defined convex cone. The corresponding dual problem is
54+
where `x` and `s` are variables, `A`, `b`, `c` and `P` (optional) are the user-supplied problem data, and `K` is a user-defined convex cone. The corresponding dual problem is
5555

5656
```
57-
minimize b'y
58-
subject to A'y + c == 0
57+
minimize b'y + x'Px
58+
subject to Px + A'y + c == 0
5959
y in K^*
6060
```
6161

@@ -66,25 +66,26 @@ with dual variable `y`.
6666
`diffcp` exposes the function
6767

6868
```python
69-
solve_and_derivative(A, b, c, cone_dict, warm_start=None, solver=None, **kwargs).
69+
solve_and_derivative(A, b, c, cone_dict, warm_start=None, solver=None, P=None, **kwargs).
7070
```
7171

7272
This function returns a primal-dual solution `x`, `y`, and `s`, along with
7373
functions for evaluating the derivative and its adjoint (transpose).
7474
These functions respectively compute right and left multiplication of the derivative
75-
of the solution map at `A`, `b`, and `c` by a vector.
75+
of the solution map at `A`, `b`, `c` and `P` by a vector.
7676
The `solver` argument determines which solver to use; the available solvers
7777
are `solver="SCS"`, `solver="ECOS"`, and `solver="Clarabel"`.
7878
If no solver is specified, `diffcp` will choose the solver itself.
7979
In the case that the problem is not solved, i.e. the solver fails for some reason, we will raise
8080
a `SolverError` Exception.
8181

8282
#### Arguments
83-
The arguments `A`, `b`, and `c` correspond to the problem data of a cone program.
83+
The arguments `A`, `b`, `c` and `P` correspond to the problem data of a cone program.
8484
* `A` must be a [SciPy sparse CSC matrix](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.csc_matrix.html).
8585
* `b` and `c` must be NumPy arrays.
8686
* `cone_dict` is a dictionary that defines the convex cone `K`.
8787
* `warm_start` is an optional tuple `(x, y, s)` at which to warm-start. (Note: this is only available for the SCS solver).
88+
* `P` is an optional [SciPy sparse CSC matrix](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.csc_matrix.html). (Note: this is currently only available for the Clarabel and SCS solvers, paired with LPGD differentiation mode).
8889
* `**kwargs` are keyword arguments to forward to the solver (e.g., `verbose=False`).
8990

9091
These inputs must conform to the [SCS convention](https://github.com/bodono/scs-python) for problem data. The keys in `cone_dict` correspond to the cones, with
@@ -96,6 +97,8 @@ These inputs must conform to the [SCS convention](https://github.com/bodono/scs-
9697

9798
The values in `cone_dict` denote the sizes of each cone; the values of `diffcp.SOC`, `diffcp.PSD`, and `diffcp.EXP` should be lists. The order of the rows of `A` must match the ordering of the cones given above. For more details, consult the [SCS documentation](https://github.com/cvxgrp/scs/blob/master/README.md).
9899

100+
To enable [Lagrangian Proximal Gradient Descent (LPGD)](https://arxiv.org/abs/2407.05920) differentiation of the conic program based on efficient finite-differences, provide one of the `mode=[lpgd, lpgd_left, lpgd_right]` options along with the argument `derivative_kwargs=dict(tau=0.1, rho=0.1)` to specify the perturbation and regularization strength. Alternatively, the derivative kwargs can also be passed directly to the returned `derivative` and `adjoint_derivative` function.
101+
99102
#### Return value
100103
The function `solve_and_derivative` returns a tuple
101104

@@ -105,11 +108,11 @@ The function `solve_and_derivative` returns a tuple
105108

106109
* `x`, `y`, and `s` are a primal-dual solution.
107110

108-
* `derivative` is a function that applies the derivative at `(A, b, c)` to perturbations `dA`, `db`, `dc`. It has the signature
109-
```derivative(dA, db, dc) -> dx, dy, ds```, where `dA` is a SciPy sparse CSC matrix with the same sparsity pattern as `A`, and `db` and `dc` are NumPy arrays. `dx`, `dy`, and `ds` are NumPy arrays, approximating the change in the primal-dual solution due to the perturbation.
111+
* `derivative` is a function that applies the derivative at `(A, b, c, P)` to perturbations `dA`, `db`, `dc` and `dP` (optional). It has the signature
112+
```derivative(dA, db, dc, dP=None) -> dx, dy, ds```, where `dA` is a SciPy sparse CSC matrix with the same sparsity pattern as `A`, `db` and `dc` are NumPy arrays, and `dP` is an optional SciPy sparse CSC matrix with the same sparsity pattern as `P` (Note: currently only supported for LPGD differentiation mode). `dx`, `dy`, and `ds` are NumPy arrays, approximating the change in the primal-dual solution due to the perturbation.
110113

111114
* `adjoint_derivative` is a function that applies the adjoint of the derivative to perturbations `dx`, `dy`, `ds`. It has the signature
112-
```adjoint_derivative(dx, dy, ds) -> dA, db, dc```, where `dx`, `dy`, and `ds` are NumPy arrays.
115+
```adjoint_derivative(dx, dy, ds, return_dP=False) -> dA, db, dc, (dP)```, where `dx`, `dy`, and `ds` are NumPy arrays. `dP` is only returned when setting `return_dP=True` (Note: currently only supported for LPGD differentiation mode).
113116

114117
#### Example
115118
```python
@@ -157,7 +160,7 @@ ds = np.zeros(m)
157160
dA, db, dc = DT(dx, dy, ds)
158161
```
159162

160-
For more examples, including the SDP example described in the paper, see the [`examples`](examples/) directory.
163+
For more examples, including the SDP example described in the paper, and examples of using LPGD differentiation, see the [`examples`](examples/) directory.
161164

162165
### Citing
163166
If you wish to cite `diffcp`, please use the following BibTex:

0 commit comments

Comments
 (0)