You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Remove redundant refresh_param_values calls from eval_jacobian and
eval_wsum_hess in left_matmul (forward always runs first)
- Use memcpy in problem_register_params for pointer array copy
- Add PARAM_FIXED guard in problem_update_params to skip fixed constants
- Remove unused right_matmul_expr struct from subexpr.h
- Add test_param_fixed_skip_in_update covering mixed fixed/updatable params
- Add CLAUDE.md for Claude Code guidance
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+
## Project Overview
6
+
7
+
SparseDiffEngine is a C library implementing the differentiation engine for CVXPY's DNLP extension. It computes sparse Jacobians and Hessians for nonlinear programming solvers. Used as a backend via Python bindings in the parent SparseDiffPy package.
Type-specific nodes use C struct inheritance: embed `expr base` as the first field, then cast. Defined in `include/subexpr.h` (e.g., `parameter_expr`, `scalar_mult_expr`).
42
+
43
+
All node constructors call `init_expr()` to wire up the dispatch table. Children are owned via `left`/`right` pointers with reference counting (`expr_retain`/`free_expr`).
44
+
45
+
### Parameter System
46
+
47
+
`parameter_expr` (in `subexpr.h`) unifies constants and updatable parameters:
48
+
-`param_id == PARAM_FIXED (-1)`: fixed constant, not updatable
49
+
-`param_id >= 0`: offset into the parameter vector `theta`
50
+
51
+
Bivariate ops that involve parameters (scalar_mult, vector_mult, left_matmul, right_matmul) store a `param_source` pointer and read values during forward/jacobian/hessian evaluation.
52
+
53
+
**Workflow**: `new_parameter()` → `problem_register_params()` → `problem_update_params(prob, theta)` copies from `theta` into each parameter node's `value` array using `param_id` as offset.
54
+
55
+
### Problem Interface (`include/problem.h`)
56
+
57
+
The `problem` struct owns an objective, constraints array, and parameter nodes. Key lifecycle:
CSR is primary. CSC is intermediate during computation. COO for Python interop; lower-triangular COO for symmetric Hessians.
68
+
69
+
## Adding a New Operation
70
+
71
+
1. Create `src/<category>/new_op.c` implementing the function pointer interface
72
+
2. Add constructor declaration to the appropriate `include/<category>.h`
73
+
3. Write test as a `.h` file in `tests/<test_category>/`
74
+
4. Register test in `tests/all_tests.c` with `mu_run_test(test_name, tests_run)`
75
+
76
+
## Test Framework
77
+
78
+
Uses minunit.h (header-only). Tests are `const char *test_name(void)` functions returning NULL on success. Tolerance: `ABS_TOL=1e-6, REL_TOL=1e-6` via `cmp_double_array()` in `test_helpers.c`. No built-in test filtering — all tests run via single `all_tests` binary.
0 commit comments