Skip to content

Add in-place LinearOperator update support#413

Open
arnavk23 wants to merge 14 commits intoJuliaSmoothOptimizers:mainfrom
arnavk23:fix-issue-196-copyto
Open

Add in-place LinearOperator update support#413
arnavk23 wants to merge 14 commits intoJuliaSmoothOptimizers:mainfrom
arnavk23:fix-issue-196-copyto

Conversation

@arnavk23
Copy link
Contributor

@arnavk23 arnavk23 commented Feb 27, 2026

Fixes #196 by implementing safe in-place update methods for LinearOperator objects.

This PR adds three methods:

  1. copyto!(dest, src) - Explicit in-place copy for compatible operators
  2. copy!(dest, src) - Alias for copyto! following Base conventions
  3. Broadcast assignment op1 .= op2 - Convenient syntax via materialize! hook

The implementation:

  • Treats operators as scalar-like objects for broadcasting (via broadcastable(op) = Ref(op))
  • Requires exact type compatibility between source and destination operators (same T, S, I, F, Ft, Fct parameters)
  • Copies all operator fields including closures (prod!, tprod!, ctprod!)
  • Throws informative errors for incompatible types or invalid broadcast operations

@tmigot As my previous pr is from the main branch, I plan to get that merged before this pr.

arnavk23 and others added 8 commits October 12, 2025 06:44
…at.jl consistently (tests still pass functionally; only the known two tiny allocation assertions remain).
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Remove _select_storage_type function that was silently falling back to
alternative storage types when promotion failed. This implicit behavior
could cause severe performance degradation (e.g., GPU->CPU fallback).

Now throws a helpful LinearOperatorException when storage types cannot
be promoted to a concrete type, guiding users to ensure compatible
storage types across operators.

This aligns with Julia's philosophy of making performance characteristics
explicit and prevents mysterious performance issues.
Copilot AI review requested due to automatic review settings February 27, 2026 17:19
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements in-place update support for LinearOperator instances to address broadcast-style operator replacement (Issue #196), and improves error messaging when composing operators with incompatible storage types.

Changes:

  • Add copyto!/copy! for in-place updates between type-compatible LinearOperators, plus a materialize! hook to support op .= new_op.
  • Treat AbstractLinearOperator as scalar-like in broadcasting via broadcastable.
  • Improve error messages in * and + when storage_type promotion fails, and add tests for the new in-place update behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/abstract.jl Adds broadcasting hooks and in-place update APIs (copyto!, copy!, materialize!) for LinearOperator.
src/operations.jl Enhances error messages for non-concrete promoted storage types in operator multiplication/addition.
test/test_linop.jl Adds test coverage for copyto!, copy!, .=, and expected failure modes.
Comments suppressed due to low confidence (1)

src/abstract.jl:257

  • copyto! assigns dest.Mv5 / dest.Mtu5 directly from src, which makes the two operators share mutable workspace buffers. Those buffers are written to in mul!/allocate_vectors_args3! (see src/operations.jl), so using dest and src independently (especially from different tasks/threads) can lead to interference and data races. Consider allocating fresh buffers for dest (and copying contents if needed), or resetting them (e.g., empty + allocated5=false) so dest owns its workspace after the update; also preserve the Mv5 === Mtu5 aliasing relationship within dest without sharing with src.
Return the size of a linear operator as a tuple.
"""
size(op::AbstractLinearOperator) = (op.nrow, op.ncol)

"""

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

The recent struct changes added const modifiers to LinearOperator fields
for performance. However, this makes copyto! impossible since const fields
cannot be modified after construction.

This commit removes const from the struct fields to enable the in-place
update feature requested in issue JuliaSmoothOptimizers#196. While this may have minor
performance implications, it is necessary for the .= syntax to work.

Also updated copyto! implementation to match current struct fields
(Mv/Mtu instead of Mv5/Mtu5/args5/use_prod5/allocated5).
After struct changes, operations.jl was calling the old CompositeLinearOperator
constructor with args5 parameter which no longer exists. Updated to use the
simplified LinearOperator{T,S} constructor.
@arnavk23
Copy link
Contributor Author

@tmigot Whenever you are free, take a look at this also. Thanks!

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.

Broadcast LinearOperators

2 participants