Conversation
Add parameter node type and parameter-aware variants of scalar mult, vector mult, and left matmul. Parameters store an offset into a global theta vector and can be updated via problem_update_params without rebuilding the expression tree. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
n_params (total scalar parameter count) can be computed from n_param_nodes and each node's size, making the field redundant. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These dimensions are always equal to param_node->d1 and param_node->d2, which are set during make_parameter. Read them from the node directly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Precompute total parameter size in problem_register_params, mirroring how total_constraint_size is computed in new_problem. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Exercises param_scalar_mult, param_vector_mult, and left_param_matmul with problem_register_params/problem_update_params to verify objective, gradient, constraint, and Jacobian values update correctly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The retained param_node was never released because free_type_data was NULL. Add free_param_type_data to match const_vector_mult and left_matmul. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
This looks great! Two comments:
|
Sync parameter-support with main's left matmul 100x perf improvements (PR #44) and right matmul refactor (PR #46). Simplify param matmul to store only the small A matrix instead of block-diagonal — block_left_multiply_* functions handle the rest. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge the separate Constant and Parameter leaf nodes into a unified parameter_expr with PARAM_FIXED sentinel (-1) for constants. This eliminates duplicate code paths and consolidates 7 bivariate constructors into 3 unified ones: - new_const_scalar_mult / new_param_scalar_mult -> new_scalar_mult - new_const_vector_mult / new_param_vector_mult -> new_vector_mult - new_left_matmul (CSR) / new_left_param_matmul -> new_left_matmul (param node) Key changes: - Add PARAM_FIXED define and extend new_parameter() to accept initial values - Delete constant.c (absorbed by parameter.c) - Remove direct value storage (double a, double *a) from scalar/vector mult structs; always read from param_source - left_matmul builds sparse CSR for fixed params (preserving sparsity) and dense CSR for updatable params - right_matmul internally creates a fixed parameter node from transposed A - problem_update_params skips PARAM_FIXED nodes - Update all test callers to use new_parameter with PARAM_FIXED Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
528e1c1 to
9700344
Compare
…ents Post-refactor cleanup after the Constant→Parameter merge: - Remove dead NULL assignments in free_type_data (quad_form, hstack, index, linear_op, left_matmul, scalar_mult, vector_mult) - Rename const_scalar_mult/const_vector_mult source and test files to drop const_ prefix - Rename test_variable_constant.h → test_variable_parameter.h and test_constant → test_fixed_parameter - Update stale comments in multiply.c and bivariate.h - Rename const_scalar_mult_expr/const_vector_mult_expr structs to scalar_mult_expr/vector_mult_expr - Update left_matmul param_source comment Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Transurgeon
left a comment
There was a problem hiding this comment.
@dance858 some progress on the parameter feature.
I also renamed tests and functions to remove the const_ text, I hope that's okay.
For example, now we have scalar_mult instead of const_scalar_mult.
| free(lin_node->b); | ||
| lin_node->b = NULL; | ||
| } | ||
|
|
||
| lin_node->A_csr = NULL; | ||
| lin_node->A_csc = NULL; |
There was a problem hiding this comment.
claude noticed that these NULL assignments were not necessary. please confirm if that's accurate.
src/affine/parameter.c
Outdated
| init_expr(&pnode->base, d1, d2, n_vars, forward, jacobian_init, eval_jacobian, | ||
| is_affine, wsum_hess_init, eval_wsum_hess, NULL); |
There was a problem hiding this comment.
is this correct declaration for a parameter expression? I am not sure about the first argument being &pnode->base but it seems to form a base parameter expression?
…anching - Change signature to (expr *param_node, expr *child, const CSR_Matrix *A) - Constructor copies A with new_csr() instead of rebuilding from dense values - Remove src_m/src_n fields from left_matmul_expr (use A->m directly) - Allow param_node=NULL for fixed constants (no-op in refresh_param_values) - Update all tests to pass CSR directly; fixed-constant tests use NULL param Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
e13ce04 to
36864d4
Compare
- left_matmul: replace col-major loop in refresh_param_values with memcpy of nnz doubles (values now arrive in CSR data order) - right_matmul: pass AT->x directly to new_parameter(nnz, 1, ...), remove col-major round-trip allocation - test_param_prob: update theta arrays to CSR data order Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
src/bivariate/right_matmul.c
Outdated
| /* Parameter stores CSR data order (same as AT->x) */ | ||
| expr *u_transpose = new_transpose(u); | ||
| expr *left_matmul = new_left_matmul(u_transpose, AT); | ||
| expr *node = new_transpose(left_matmul); | ||
| expr *param_node = new_parameter(AT->nnz, 1, PARAM_FIXED, u->n_vars, AT->x); | ||
| expr *left_matmul_node = new_left_matmul(param_node, u_transpose, AT); | ||
| expr *node = new_transpose(left_matmul_node); |
There was a problem hiding this comment.
I also changed right matmul to use parameters now.
There was a problem hiding this comment.
@dance858 I might have gone a bit crazy tonight, but good progress nonetheless.
Let me know what you think about supporting sparse parameters with a fixed pattern.
I feel like the PR is in a good state, but definitely want you to take your time with reviewing and asking me questions about the implementation.
Eventually we can make new constructors for dense Parameters (and constants).. and have some super fast BLAS operations done there to separate the two code paths.
P.S. you might need to try this code on this DNLP branch with this SparseDiffPy PR.
This PR adds support for parameters entering in affine functions.
The semantics of parameter creation are similar to that of variables.
We take the parameter offset data from the
InverseDatain cvxpy and create equivalent parameters in C.Then we form a parameter vector theta which stacks all parameters, this theta can be updated on every iteration.
After calling
update_paramswe just need to recompute the values of the jacobian, since the sparsity pattern will be fixed. This pattern is computed once using the exact same technique as before.One thing that is nice with our abstraction is that all affine operators require no changes; they simply manipulate the arrays from their children, which are irrespective of if the expression has parameters or not.
The main change ends up adding new functionality in bivariate affine operators where parameters can appear.
These include scalar multiplication, vector (elementwise) multiplication and matrix multiplication.
I have checked carefully the first two implementations, but I must admit I don't fully get the matrix mult one (but this also probably stems from me not understanding the original implementation). @dance858 please verify that this looks good.
Overall I think this is a very clean and simple addition to support affine parameters in the diff-engine, I am happy to hear any feedback on the design and implementation.