Skip to content

Commit aa9630e

Browse files
committed
adds changes to test_problem with parametrize
1 parent 25c01c4 commit aa9630e

2 files changed

Lines changed: 27 additions & 83 deletions

File tree

CLAUDE.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ prob.solve(nlp=True, solver=cp.IPOPT, best_of=5)
6565

6666
| Solver | License | Installation |
6767
|--------|---------|--------------|
68-
| [IPOPT](https://github.com/coin-or/Ipopt) | EPL-2.0 | `conda install -c conda-forge cyipopt` |
68+
| [IPOPT](https://github.com/coin-or/Ipopt) | EPL-2.0 | `conda install -c conda-forge cyipopt` (conda only — pip install is unreliable) |
6969
| [Knitro](https://www.artelys.com/solvers/knitro/) | Commercial | `pip install knitro` (requires license) |
7070
| [COPT](https://www.copt.de/) | Commercial | Requires license |
7171
| [Uno](https://github.com/cuter-testing/uno) | Open source | See Uno documentation |
@@ -129,9 +129,9 @@ Key reduction classes in `cvxpy/reductions/`:
129129
- `Chain` composes multiple reductions
130130
- `SolvingChain` orchestrates the full solve process
131131

132-
For DNLP: `CvxAttr2Constr``Dnlp2Smooth``NLPSolver`
132+
For DNLP: `FlipObjective` (if Maximize) → `CvxAttr2Constr``Dnlp2Smooth``NLPSolver`
133133

134-
Note: The standard `SolvingChain` in `solving_chain.py` handles DCP/DGP/DQCP solver selection automatically. NLP solving is triggered explicitly via `prob.solve(nlp=True)` and bypasses the standard chain.
134+
Note: The standard `SolvingChain` in `solving_chain.py` handles DCP/DGP/DQCP solver selection automatically. NLP solving is triggered explicitly via `prob.solve(nlp=True)` and bypasses the standard chain`problem.py` delegates to `solve_nlp()` in `cvxpy/reductions/solvers/nlp_solving_chain.py`, which builds the chain, handles initial point construction (via `_set_nlp_initial_point`), and orchestrates the `best_of` multi-start logic. Solver algorithm variants (e.g., `"knitro_sqp"`) are mapped via `NLP_SOLVER_VARIANTS` in `nlp_solving_chain.py`.
135135

136136
### Solver Categories
137137

@@ -215,6 +215,10 @@ class TestMyFeature(BaseTest):
215215

216216
NLP tests are in `cvxpy/tests/nlp_tests/` with Jacobian and Hessian verification tests.
217217

218+
## Build System
219+
220+
Uses a custom build backend (`setup/build_meta.py`) that re-exports `setuptools.build_meta`. The `setup/` directory handles C extensions (cvxcore, sparsecholesky) and version management. Solver registration is in `cvxpy/reductions/solvers/defines.py` (`SOLVER_MAP_CONIC`, `SOLVER_MAP_QP`, `SOLVER_MAP_NLP`).
221+
218222
## Benchmarks
219223

220224
Benchmarks use [Airspeed Velocity](https://asv.readthedocs.io/) and live in the `benchmarks/` directory. To run locally:

cvxpy/tests/nlp_tests/test_problem.py

Lines changed: 20 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,31 @@
11

22
import numpy as np
3+
import pytest
34

45
import cvxpy as cp
56
from cvxpy.reductions.solvers.nlp_solving_chain import _set_nlp_initial_point
67

78

89
class TestProblem():
9-
"""
10-
This class can be used to test internal function for Problem that have been added
11-
in the DNLP extension.
12-
"""
13-
14-
def test_set_initial_point_both_bounds_infinity(self):
15-
# when both bounds are infinity, the initial point should be zero vector
16-
17-
# test 1
18-
x = cp.Variable((3, ))
19-
prob = cp.Problem(cp.Minimize(cp.sum(x)))
20-
_set_nlp_initial_point(prob)
21-
assert (x.value == np.zeros((3, ))).all()
22-
23-
# test 2
24-
x = cp.Variable((3, ), bounds=[None, None])
25-
prob = cp.Problem(cp.Minimize(cp.sum(x)))
26-
_set_nlp_initial_point(prob)
27-
assert (x.value == np.zeros((3, ))).all()
28-
29-
# test 3
30-
x = cp.Variable((3, ), bounds=[-np.inf, np.inf])
31-
prob = cp.Problem(cp.Minimize(cp.sum(x)))
32-
_set_nlp_initial_point(prob)
33-
assert (x.value == np.zeros((3, ))).all()
34-
35-
# test 4
36-
x = cp.Variable((3, ), bounds=[None, np.inf])
37-
prob = cp.Problem(cp.Minimize(cp.sum(x)))
38-
_set_nlp_initial_point(prob)
39-
assert (x.value == np.zeros((3, ))).all()
40-
41-
# test 5
42-
x = cp.Variable((3, ), bounds=[-np.inf, None])
43-
prob = cp.Problem(cp.Minimize(cp.sum(x)))
44-
_set_nlp_initial_point(prob)
45-
assert (x.value == np.zeros((3, ))).all()
46-
47-
48-
def test_set_initial_point_lower_bound_infinity(self):
49-
# when one bound is infinity, the initial point should be one unit
50-
# away from the finite bound
51-
52-
# test 1
53-
x = cp.Variable((3, ), bounds=[None, 3.5])
54-
prob = cp.Problem(cp.Minimize(cp.sum(x)))
55-
_set_nlp_initial_point(prob)
56-
assert (x.value == 2.5 * np.ones((3, ))).all()
57-
58-
# test 2
59-
x = cp.Variable((3, ), bounds=[-np.inf, 3.5])
60-
prob = cp.Problem(cp.Minimize(cp.sum(x)))
61-
_set_nlp_initial_point(prob)
62-
assert (x.value == 2.5 * np.ones((3, ))).all()
63-
64-
def test_set_initial_point_upper_bound_infinity(self):
65-
# when one bound is infinity, the initial point should be one unit
66-
# away from the finite bound
67-
68-
# test 1
69-
x = cp.Variable((3, ), bounds=[3.5, None])
70-
prob = cp.Problem(cp.Minimize(cp.sum(x)))
71-
_set_nlp_initial_point(prob)
72-
assert (x.value == 4.5 * np.ones((3, ))).all()
73-
74-
# test 2
75-
x = cp.Variable((3, ), bounds=[3.5, np.inf])
76-
prob = cp.Problem(cp.Minimize(cp.sum(x)))
77-
_set_nlp_initial_point(prob)
78-
assert (x.value == 4.5 * np.ones((3, ))).all()
79-
80-
def test_set_initial_point_both_bounds_finite(self):
81-
# when both bounds are finite, the initial point should be the midpoint
82-
# between the two bounds
83-
84-
# test 1
85-
x = cp.Variable((3, ), bounds=[3.5, 4.5])
86-
prob = cp.Problem(cp.Minimize(cp.sum(x)))
87-
_set_nlp_initial_point(prob)
88-
assert (x.value == 4.0 * np.ones((3, ))).all()
10+
"""Tests for internal NLP functions in the DNLP extension."""
11+
12+
@pytest.mark.parametrize("bounds, expected", [
13+
(None, 0.0),
14+
([None, None], 0.0),
15+
([-np.inf, np.inf], 0.0),
16+
([None, np.inf], 0.0),
17+
([-np.inf, None], 0.0),
18+
([None, 3.5], 2.5),
19+
([-np.inf, 3.5], 2.5),
20+
([3.5, None], 4.5),
21+
([3.5, np.inf], 4.5),
22+
([3.5, 4.5], 4.0),
23+
])
24+
def test_set_initial_point_scalar_bounds(self, bounds, expected):
25+
x = cp.Variable((3, ), bounds=bounds)
26+
prob = cp.Problem(cp.Minimize(cp.sum(x)))
27+
_set_nlp_initial_point(prob)
28+
assert (x.value == expected * np.ones((3, ))).all()
8929

9030
def test_set_initial_point_mixed_inf_and_finite(self):
9131
lb = np.array([-np.inf, 3.5, -np.inf, -1.5, 2, 2.5])

0 commit comments

Comments
 (0)