Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/src/literate/howtos/gpu.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ LinearOperators.storage_type(fop) == typeof(storage)

# ## Moving an Operator to Another Backend
# Operators that support [Adapt.jl](https://github.com/JuliaGPU/Adapt.jl) can be moved to another array backend with `Adapt.adapt(target, op)`.
# Which backends are supported depends on the operator and the target, and not every operator in LinearOperatorCollection implements Adapt.
# Which backends are supported depends on the operator and the target. The following operators implement Adapt:
# * `FFTOp`, `NFFTOp` (including its Toeplitz normal operator) and `RadonOp`
# * `GradientOp`, `SamplingOp` and `WeightingOp`
# * `DiagOp`, `ProdOp`, `RowBlockOp` and `NormalOp`, and the normal operators of `DiagOp`, `ProdOp` and `RowBlockOp`. These are built from other operators and adapt them, so the target must also be supported by each of those operators.
# Other operators, such as `WaveletOp`, `DCTOp` and `DSTOp`, do not implement Adapt.

# The target is the backing array type without element-type parameters, such as `Array`, `CuArray` or `ROCArray`.
# LinearOperatorCollection does not support element-typed targets such as `Array{ComplexF64}` or `CuArray{Float32}`, even when the element type matches the operator.
Expand Down
3 changes: 2 additions & 1 deletion ext/LinearOperatorFFTWExt/FFTOp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ returns an operator which performs an FFT on Arrays of type T
`Adapt.adapt(target, op)` preserves the shape, shift, and normalization
convention, planner options, and rebuilds the plans, workspaces, and closures
for `target`. If `cache=false`, adapting the operator raises an explicit
`ArgumentError` because the planner options were not retained.
`ArgumentError` because the planner options were not retained. See
[Moving an Operator to Another Backend](@ref) for the supported targets.
"""
function LinearOperatorCollection.FFTOp(T::Type; shape::NTuple{D,Int64}, shift::Bool=true, unitary::Bool=true, S = Vector{Complex{real(T)}}, cache::Bool=true, kwargs...) where D

Expand Down
6 changes: 4 additions & 2 deletions ext/LinearOperatorNFFTExt/NFFTOp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ generates a `NFFTOpImpl` which evaluates the MRI Fourier signal encoding operato
settings, and `toeplitz`; it replays the cached constructor arguments with
target-backed nodes and rebuilds plans, workspaces, and closures for the
target. If `cache=false`, adapting the operator raises an explicit
`ArgumentError` because the constructor arguments were not retained.
`ArgumentError` because the constructor arguments were not retained. See
[Moving an Operator to Another Backend](@ref) for the supported targets.
"""
function LinearOperatorCollection.NFFTOp(::Type{T};
shape::Tuple, nodes::AbstractMatrix{U}, toeplitz=false, oversamplingFactor=1.25,
Expand Down Expand Up @@ -195,7 +196,8 @@ Construct a Toeplitz normal operator for an NFFT. `Adapt.adapt(target, op)`
keeps the shape, weights, Toeplitz kernel `λ`, and FFT planner options, and
rebuilds the FFT plans, workspaces, and closures on the target. Set
`cache=false` when constructing the operator to opt out of retaining planner
kwargs; adapting such an operator raises an explicit `ArgumentError`.
kwargs; adapting such an operator raises an explicit `ArgumentError`. See
[Moving an Operator to Another Backend](@ref) for the supported targets.
"""
function LinearOperatorCollection.NFFTToeplitzNormalOp(shape, W, fftplan, ifftplan,
λ, xL1::matT, xL2::matT,
Expand Down
3 changes: 2 additions & 1 deletion ext/LinearOperatorRadonKAExt/RadonOp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ Generates a `RadonOp` which evaluates the Radon transform operator and its adjoi
* `S` - storage type for internal vectors (default: `Vector{T}`)

`Adapt.adapt(target, op)` rebuilds the operator for `target` with the same shape and
geometry; array `angles` and `μ` are adapted to `target`, ranges and scalars are kept.
geometry; array `angles` and `μ` are adapted to `target`, ranges and scalars are kept. See
[Moving an Operator to Another Backend](@ref) for the supported targets.
"""
function LinearOperatorCollection.RadonOp(::Type{T}; shape::NTuple{N, Int}, angles,
geometry = RadonParallelCircle(shape[1], -(shape[1]-1)÷2:(shape[1]-1)÷2), μ = nothing, S = Vector{T}) where {T, N}
Expand Down
22 changes: 8 additions & 14 deletions src/GradientOp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,14 @@ directional gradient operator along the dimensions `dims` for an array of size `

# Moving to another array backend

Adapt.adapt(CuArray, op)

returns a new gradient operator for the target backend, and `copy(op)` returns a new one with
the same storage type. The target is the backing array type without element-type parameters
(e.g. `Array`, `JLArray`, `CuArray` or `ROCArray`). Unlike `S`, which takes a parameterized type
such as `CuArray{T, 1}`, an element-typed target such as `Array{Float64}` is not supported, even
when its element type matches `op`. Adapting does not change the precision: choose `T` at
construction. Both rebuild the operator and its temporary storage from `shape` and the
directions taken from `dims` at construction; a later change of the vector passed as `dims`, or
an iterator consumed by the construction, has no effect. `op` itself is not modified. The
directions stay on the host. An element-typed target whose element type differs from `op`, such
as `CuArray{Float32}` for a `Float64` operator, throws an `ArgumentError`. An operator built with
an `S` of another element type cannot be adapted to any target and throws an `ArgumentError`;
`copy` keeps it as it is.
`Adapt.adapt(target, op)`, and `copy(op)` with the same storage type, rebuild the operator and
its temporary storage from `shape` and the directions taken from `dims` at construction; a later
change of the vector passed as `dims`, or an iterator consumed by the construction, has no
effect. `op` itself is not modified. The directions stay on the host. A target whose storage
element type differs from `op`, such as `CuArray{Float32}` for a `Float64` operator, throws an
`ArgumentError`. An operator built with an `S` of another element type cannot be adapted to any
target and throws an `ArgumentError`; `copy` keeps it as it is. See
[Moving an Operator to Another Backend](@ref) for the supported targets.
"""
function GradientOp(::Type{T}; shape::NTuple{N,Int}, dims=1:length(shape), kwargs...) where {T <: Number, N}
return GradientOpImpl(T, shape, dims; kwargs...)
Expand Down
5 changes: 3 additions & 2 deletions src/RowBlockOp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ of the blocks applied to their rows. The products of the blocks run in parallel
the adjoint sums the blocks one after the other.

Blocks with contiguous rows (`UnitRange`s) work on views of the data; other rows are gathered into and scattered
from a buffer per block (with index vectors on the device of the blocks, see `Adapt.adapt`). Reordering the data
such that every block is contiguous avoids these copies.
from a buffer per block (with index vectors on the device of the blocks, see
[Moving an Operator to Another Backend](@ref)). Reordering the data such that every block is contiguous avoids these
copies.

The third form splits the rows of a matrix into `nblocks` blocks, as copies of the rows: `:interleaved` takes every
`nblocks`-th row (`k:nblocks:m`), `:contiguous` consecutive rows, `:random` a random partition drawn with `rng`.
Expand Down
5 changes: 3 additions & 2 deletions src/SamplingOp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ Two modes are supported:
* Boolean mask without `shape`: multiplies the input elementwise with a copy of
`pattern` stored on the backend of `S`.

`Adapt.adapt(to, op)` rebuilds the operator for the storage type `to` from its
`Adapt.adapt(to, op)` rebuilds the operator for the target `to` from its
effective pattern. Integer indices are copied and stay host arrays; the Boolean
mask is copied to the target backend.
mask is copied to the target backend. See
[Moving an Operator to Another Backend](@ref) for the supported targets.

# Arguments
* `pattern` - integer indices or Boolean mask
Expand Down
Loading