Skip to content

Commit 4bc2a79

Browse files
Transurgeonclaude
andauthored
Sync convolve and matmul convention (#13)
* sync SparseDiffEngine and adapt dense matmul bindings Bump SparseDiffEngine submodule to origin/main (45f88d0), which pulls in the new convolve atom plus dance858's cleanup of the dense matmul constructor data-pointer convention. new_left_matmul_dense / new_right_matmul_dense now require exactly one of param_node / data to be non-NULL (constants: (NULL, data); parameters: (capsule, NULL)) — the engine fprintf/exit(1)s otherwise. Update the dense branches of make_left_matmul and make_right_matmul bindings to match: drop the PARAM_FIXED wrapper we were building for the constant case, and forward data=NULL when a real parameter capsule is supplied. DNLP's helpers.py still hands in A.flatten() in both cases; the binding absorbs the new convention so no DNLP-side change is needed. Verified: SparseDiffEngine ctest (267/267), DNLP nlp_tests (217 passed, 77 skipped), DNLP test_convolution + test_atoms (119 passed). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * trim comments on dense matmul bindings Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 4d16086 commit 4bc2a79

3 files changed

Lines changed: 25 additions & 50 deletions

File tree

sparsediffpy/_bindings/atoms/left_matmul.h

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ static PyObject *py_make_left_matmul(PyObject *self, PyObject *args)
119119
}
120120
else if (strcmp(fmt, "dense") == 0)
121121
{
122-
/* Parse: param_or_none, child, "dense", A_data_flat, m, n */
122+
/* Engine requires (param_node, data) to be mutually exclusive;
123+
* drop the caller's A_data when a parameter capsule is supplied. */
123124
PyObject *data_obj;
124125
int m, n;
125126
if (!PyArg_ParseTuple(args, "OOsOii", &param_obj, &child_capsule,
@@ -128,48 +129,34 @@ static PyObject *py_make_left_matmul(PyObject *self, PyObject *args)
128129
return NULL;
129130
}
130131

131-
PyArrayObject *data_array = (PyArrayObject *) PyArray_FROM_OTF(
132-
data_obj, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
133-
if (!data_array)
134-
{
135-
return NULL;
136-
}
137-
138-
double *A_data = (double *) PyArray_DATA(data_array);
139-
140-
expr *param_node = NULL;
132+
expr *node;
141133
if (param_obj == Py_None)
142134
{
143-
param_node = new_parameter(m * n, 1, PARAM_FIXED,
144-
child->n_vars, A_data);
145-
if (!param_node)
135+
PyArrayObject *data_array = (PyArrayObject *) PyArray_FROM_OTF(
136+
data_obj, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
137+
if (!data_array)
146138
{
147-
Py_DECREF(data_array);
148-
PyErr_SetString(PyExc_RuntimeError,
149-
"failed to create parameter node");
150139
return NULL;
151140
}
141+
double *A_data = (double *) PyArray_DATA(data_array);
142+
node = new_left_matmul_dense(NULL, child, m, n, A_data);
143+
Py_DECREF(data_array);
152144
}
153145
else
154146
{
155-
param_node = (expr *) PyCapsule_GetPointer(param_obj,
156-
EXPR_CAPSULE_NAME);
147+
expr *param_node = (expr *) PyCapsule_GetPointer(
148+
param_obj, EXPR_CAPSULE_NAME);
157149
if (!param_node)
158150
{
159-
Py_DECREF(data_array);
160151
PyErr_SetString(PyExc_ValueError,
161152
"invalid parameter capsule");
162153
return NULL;
163154
}
155+
node = new_left_matmul_dense(param_node, child, m, n, NULL);
164156
}
165157

166-
expr *node =
167-
new_left_matmul_dense(param_node, child, m, n, A_data);
168-
Py_DECREF(data_array);
169-
170158
if (!node)
171159
{
172-
if (param_obj == Py_None) free_expr(param_node);
173160
PyErr_SetString(PyExc_RuntimeError,
174161
"failed to create dense left_matmul node");
175162
return NULL;

sparsediffpy/_bindings/atoms/right_matmul.h

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ static PyObject *py_make_right_matmul(PyObject *self, PyObject *args)
115115
}
116116
else if (strcmp(fmt, "dense") == 0)
117117
{
118+
/* Engine requires (param_node, data) to be mutually exclusive;
119+
* drop the caller's A_data when a parameter capsule is supplied. */
118120
PyObject *data_obj;
119121
int m, n;
120122
if (!PyArg_ParseTuple(args, "OOsOii", &param_obj, &child_capsule,
@@ -123,48 +125,34 @@ static PyObject *py_make_right_matmul(PyObject *self, PyObject *args)
123125
return NULL;
124126
}
125127

126-
PyArrayObject *data_array = (PyArrayObject *) PyArray_FROM_OTF(
127-
data_obj, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
128-
if (!data_array)
129-
{
130-
return NULL;
131-
}
132-
133-
double *A_data = (double *) PyArray_DATA(data_array);
134-
135-
expr *param_node = NULL;
128+
expr *node;
136129
if (param_obj == Py_None)
137130
{
138-
param_node = new_parameter(m * n, 1, PARAM_FIXED,
139-
child->n_vars, A_data);
140-
if (!param_node)
131+
PyArrayObject *data_array = (PyArrayObject *) PyArray_FROM_OTF(
132+
data_obj, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
133+
if (!data_array)
141134
{
142-
Py_DECREF(data_array);
143-
PyErr_SetString(PyExc_RuntimeError,
144-
"failed to create parameter node");
145135
return NULL;
146136
}
137+
double *A_data = (double *) PyArray_DATA(data_array);
138+
node = new_right_matmul_dense(NULL, child, m, n, A_data);
139+
Py_DECREF(data_array);
147140
}
148141
else
149142
{
150-
param_node = (expr *) PyCapsule_GetPointer(param_obj,
151-
EXPR_CAPSULE_NAME);
143+
expr *param_node = (expr *) PyCapsule_GetPointer(
144+
param_obj, EXPR_CAPSULE_NAME);
152145
if (!param_node)
153146
{
154-
Py_DECREF(data_array);
155147
PyErr_SetString(PyExc_ValueError,
156148
"invalid parameter capsule");
157149
return NULL;
158150
}
151+
node = new_right_matmul_dense(param_node, child, m, n, NULL);
159152
}
160153

161-
expr *node =
162-
new_right_matmul_dense(param_node, child, m, n, A_data);
163-
Py_DECREF(data_array);
164-
165154
if (!node)
166155
{
167-
if (param_obj == Py_None) free_expr(param_node);
168156
PyErr_SetString(PyExc_RuntimeError,
169157
"failed to create dense right_matmul node");
170158
return NULL;

0 commit comments

Comments
 (0)