Skip to content

Commit 9ed5d48

Browse files
Transurgeonclaude
andcommitted
Remove redundant n_params from diff engine API
n_params was only used for a size validation check and can be computed from n_param_nodes + each node's size. This simplifies the API by removing one argument from problem_register_params and one field to maintain. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1355159 commit 9ed5d48

6 files changed

Lines changed: 24 additions & 26 deletions

File tree

cvxpy/reductions/dcp2cone/diff_engine_param_cone_prog.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,13 @@ def __init__(
110110

111111
all_params = list({p.id: p for p in self.parameters}.values())
112112
if all_params:
113-
param_dict, param_capsules, n_params = build_parameter_dict(
113+
param_dict, param_capsules = build_parameter_dict(
114114
all_params, n_vars
115115
)
116116
else:
117-
param_dict, param_capsules, n_params = None, [], 0
117+
param_dict, param_capsules = None, []
118118

119119
self._all_params = all_params
120-
self._n_params = n_params
121120

122121
# Convert objective.
123122
c_objective = convert_expr(objective_expr, var_dict, n_vars, param_dict)
@@ -135,7 +134,7 @@ def __init__(
135134
# Register parameters.
136135
if param_capsules:
137136
_diffengine.problem_register_params(
138-
self._capsule, param_capsules, n_params
137+
self._capsule, param_capsules
139138
)
140139

141140
# Initialize derivative structures.
@@ -158,9 +157,9 @@ def is_mixed_integer(self):
158157

159158
def _update_params(self):
160159
"""Push current parameter values to the C expression tree."""
161-
if self._n_params == 0:
160+
if not self._all_params:
162161
return
163-
theta = np.empty(self._n_params)
162+
theta = np.empty(sum(p.size for p in self._all_params))
164163
offset = 0
165164
for param in self._all_params:
166165
val = np.asarray(param.value, dtype=np.float64).flatten(order='F')

cvxpy/reductions/solvers/nlp_solvers/diff_engine/_bindings/problem/register_params.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ static PyObject *py_problem_register_params(PyObject *self, PyObject *args)
77
{
88
PyObject *prob_capsule;
99
PyObject *param_list;
10-
int n_params;
1110

12-
if (!PyArg_ParseTuple(args, "OOi", &prob_capsule, &param_list, &n_params))
11+
if (!PyArg_ParseTuple(args, "OO", &prob_capsule, &param_list))
1312
{
1413
return NULL;
1514
}
@@ -54,7 +53,7 @@ static PyObject *py_problem_register_params(PyObject *self, PyObject *args)
5453
}
5554
}
5655

57-
problem_register_params(prob, param_nodes, (int) n_param_nodes, n_params);
56+
problem_register_params(prob, param_nodes, (int) n_param_nodes);
5857
free(param_nodes);
5958

6059
Py_RETURN_NONE;

cvxpy/reductions/solvers/nlp_solvers/diff_engine/_bindings/problem/update_params.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,15 @@ static PyObject *py_problem_update_params(PyObject *self, PyObject *args)
2929
}
3030

3131
int theta_size = (int) PyArray_SIZE(theta_array);
32-
if (theta_size != prob->n_params)
32+
int expected = 0;
33+
for (int i = 0; i < prob->n_param_nodes; i++)
34+
expected += prob->param_nodes[i]->size;
35+
if (theta_size != expected)
3336
{
3437
Py_DECREF(theta_array);
3538
PyErr_Format(PyExc_ValueError,
36-
"theta size %d does not match n_params %d",
37-
theta_size, prob->n_params);
39+
"theta size %d does not match expected %d",
40+
theta_size, expected);
3841
return NULL;
3942
}
4043

cvxpy/reductions/solvers/nlp_solvers/diff_engine/c_problem.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,18 @@ class C_problem:
3737
"""Wrapper around C problem struct for CVXPY problems."""
3838

3939
def __init__(self, cvxpy_problem: cp.Problem, verbose: bool = True):
40-
c_obj, c_constraints, param_capsules, n_params, all_params = (
40+
c_obj, c_constraints, param_capsules, all_params = (
4141
convert_expressions(cvxpy_problem)
4242
)
4343
self._capsule = _diffengine.make_problem(c_obj, c_constraints, verbose)
4444

4545
# Register parameters with the C problem
4646
if param_capsules:
4747
_diffengine.problem_register_params(
48-
self._capsule, param_capsules, n_params
48+
self._capsule, param_capsules
4949
)
5050

5151
self._all_params = all_params
52-
self._n_params = n_params
5352
self._jacobian_allocated = False
5453
self._hessian_allocated = False
5554

@@ -119,9 +118,9 @@ def update_params(self):
119118
without rebuilding it. After calling this, objective_forward/gradient/etc.
120119
will use the new parameter values.
121120
"""
122-
if self._n_params == 0:
121+
if not self._all_params:
123122
return
124-
theta = np.empty(self._n_params)
123+
theta = np.empty(sum(p.size for p in self._all_params))
125124
offset = 0
126125
for param in self._all_params:
127126
val = np.asarray(param.value, dtype=np.float64).flatten(order='F')

cvxpy/reductions/solvers/nlp_solvers/diff_engine/converters.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ def build_variable_dict(variables: list) -> tuple[dict, int]:
435435
return var_dict, n_vars
436436

437437

438-
def build_parameter_dict(parameters: list, n_vars: int) -> tuple[dict, list, int]:
438+
def build_parameter_dict(parameters: list, n_vars: int) -> tuple[dict, list]:
439439
"""
440440
Build dictionary mapping CVXPY parameter ids to C parameter nodes.
441441
@@ -446,9 +446,8 @@ def build_parameter_dict(parameters: list, n_vars: int) -> tuple[dict, list, int
446446
Returns:
447447
param_dict: {param.id: c_param_node} mapping
448448
param_capsules: list of C capsules for registration
449-
n_params: total scalar parameter count
450449
"""
451-
id_map, _, n_params, param_shapes = InverseData.get_param_offsets(parameters)
450+
id_map, _, _, param_shapes = InverseData.get_param_offsets(parameters)
452451

453452
param_dict = {}
454453
param_capsules = []
@@ -458,7 +457,7 @@ def build_parameter_dict(parameters: list, n_vars: int) -> tuple[dict, list, int
458457
c_param = _diffengine.make_parameter(d1, d2, offset, n_vars)
459458
param_dict[param.id] = c_param
460459
param_capsules.append(c_param)
461-
return param_dict, param_capsules, n_params
460+
return param_dict, param_capsules
462461

463462

464463
def convert_expr(expr, var_dict: dict, n_vars: int, param_dict: dict = None):
@@ -529,17 +528,16 @@ def convert_expressions(problem: cp.Problem) -> tuple:
529528
c_objective: C expression for objective
530529
c_constraints: list of C expressions for constraints
531530
param_capsules: list of parameter capsules (empty if no params)
532-
n_params: total scalar parameter count
533531
all_params: list of unique CVXPY Parameter objects
534532
"""
535533
var_dict, n_vars = build_variable_dict(problem.variables())
536534

537535
# Collect unique parameters
538536
all_params = list({p.id: p for p in problem.parameters()}.values())
539537
if all_params:
540-
param_dict, param_capsules, n_params = build_parameter_dict(all_params, n_vars)
538+
param_dict, param_capsules = build_parameter_dict(all_params, n_vars)
541539
else:
542-
param_dict, param_capsules, n_params = None, [], 0
540+
param_dict, param_capsules = None, []
543541

544542
# Convert objective
545543
c_objective = convert_expr(problem.objective.expr, var_dict, n_vars, param_dict)
@@ -550,4 +548,4 @@ def convert_expressions(problem: cp.Problem) -> tuple:
550548
c_expr = convert_expr(constr.expr, var_dict, n_vars, param_dict)
551549
c_constraints.append(c_expr)
552550

553-
return c_objective, c_constraints, param_capsules, n_params, all_params
551+
return c_objective, c_constraints, param_capsules, all_params

diff_engine_core

0 commit comments

Comments
 (0)