Skip to content

Stack constraint and hstack Jacobians with vstack_matrices_* - #165

Merged
dance858 merged 1 commit into
mainfrom
linalg-vstack-adoption
Oct 13, 2026
Merged

dance858 merged 1 commit into
mainfrom
linalg-vstack-adoption

Conversation

@dance858

Copy link
Copy Markdown
Collaborator

Stacked on #164. Its base is bump-linalg-v0.5.0; retarget it to main once #164 merges.

Summary

This PR adopts the library's vstack_matrices_* (sparsediff_linalg #25) and finishes the left_matmul cleanup from #27.

  • problem.c: the constraint Jacobian is now jac_stack = vstack_matrices_alloc(jac_ops, n_constraints), and prob->jacobian is its CSR view, so SparseDiffPy and jacobian_coo are unchanged. problem_jacobian evaluates the constraints and calls vstack_matrices_fill_values, which copies only the Jacobians whose values_version changed. This replaces constraint_jac_seen and both hand-written to_csr loops. With no constraints, jac_stack is an empty 0 × n_vars sparse matrix, because vstack needs at least one operand.
  • hstack.c: the Jacobian is a vstack of the children's Jacobians (new field child_jac), so children whose values didn't change are no longer recopied on every eval.
  • Fewer copies: vstack reads each operand's own storage. A stacked_pd Jacobian is now copied once per change instead of twice (once into its CSR view, then once into the stack), and no CSR cache is kept for it.
  • left_matmul: removes Jchild_CSC, J_CSC, csc_to_csr_work and the kron-only workspace. All of them have been dead since the kron branch moved to BA_sparse_kron_matrices_*. subexpr.h no longer includes CSC_matrix.h.

Testing

  • New test: test_jacobian_hstack_stacked_pd_child builds hstack(A @ exp(X), sin(X)). The left_matmul child's Jacobian is a stacked_pd, and the test checks the result against finite differences at two points, so the refill is exercised.
  • Existing tests also cover the new paths:
    • test_problem_jacobian_memcpy_skip still passes. It writes into the affine slice directly and checks that it isn't recopied.
    • So does test_problem_jacobian_spd_constraint_interleaved.
  • Builds: Debug and Release run 304 engine tests (303 plus the new one) and 201 library tests, all passing. PROFILE_ONLY=ON builds, the warnings are the same 5 as on main, and clang-format is clean.
  • SparseDiffPy smoke test: I built SparseDiffPy against this branch in a throwaway venv. A problem with hstack, diag_vec and affine constraints gave a 28×4 Jacobian that matches finite differences at two points (max error 2e-10). Its own pytest suite can't run locally: the tests need a scope fixture that isn't defined anywhere in the repo.

🤖 Generated with Claude Code

- problem.c: the global constraint Jacobian is a vstack of the constraint
  Jacobians (jac_stack over jac_ops); prob->jacobian becomes its CSR view.
  The fill copies only constraints whose values_version changed, which
  replaces constraint_jac_seen and both hand-written to_csr loops. With no
  constraints, jac_stack is an empty 0 x n_vars sparse matrix.
- hstack.c: the Jacobian is a vstack of the children's Jacobians
  (child_jac), so unchanged children are no longer recopied on each eval.
- Both read each operand's own storage: a stacked_pd Jacobian is copied
  once per change instead of twice through a to_csr view, and no CSR cache
  is created for it.
- left_matmul: drop Jchild_CSC / J_CSC / csc_to_csr_work and the kron-only
  workspace, dead since the kron branch moved to BA_sparse_kron_matrices_*.
  subexpr.h no longer needs CSC_matrix.h.
- New test test_jacobian_hstack_stacked_pd_child: hstack with a stacked_pd
  child, checked against finite differences at two points (refill).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dance858
dance858 force-pushed the linalg-vstack-adoption branch from 5234565 to 575ff78 Compare October 13, 2026 14:20
@dance858
dance858 changed the base branch from bump-linalg-v0.5.0 to main October 13, 2026 14:20
@dance858
dance858 merged commit fda43ed into main Oct 13, 2026
15 checks passed
@dance858
dance858 deleted the linalg-vstack-adoption branch October 15, 2026 05:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant