Repository navigation
Add OrthAdjoint for left_orth, right_orth
#465
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
a2c55da
Add `LQAdjoint` for `right_orth`
Yue-Zhengyuan 7f148ad
Address test timeout
Yue-Zhengyuan 6e6d95b
Merge remote-tracking branch 'upstream/main' into codex/lq-adjoint
Yue-Zhengyuan acff61f
Merge remote-tracking branch 'upstream/main' into codex/lq-adjoint
Yue-Zhengyuan ddef98d
Unified `OrthAdjoint`
Yue-Zhengyuan 694e5bc
Merge remote-tracking branch 'upstream/main' into codex/lq-adjoint
Yue-Zhengyuan 5455b89
Match docstring of `right_orth`
Yue-Zhengyuan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| """ | ||
| $(TYPEDEF) | ||
|
|
||
| Wrapper for an orthogonalization algorithm `fwd_alg` with a defined reverse rule `rrule_alg`. | ||
| Use the same instance with `left_orth(!)` for QR decomposition and `right_orth(!)` for LQ decomposition. | ||
|
|
||
| ## Fields | ||
|
|
||
| $(TYPEDFIELDS) | ||
|
|
||
| ## Constructors | ||
|
|
||
| OrthAdjoint(; kwargs...) | ||
|
|
||
| Construct an `OrthAdjoint` algorithm struct based on the following keyword arguments: | ||
|
|
||
| * `fwd_alg::Union{Algorithm,NamedTuple}=(; alg::Symbol=$(Defaults.orth_fwd_alg))`: Orthogonalization algorithm of the forward pass which can either be passed as an `Algorithm` instance or a `NamedTuple` where the algorithm is specified by the `alg` keyword. | ||
| The available algorithms are provided through MatrixAlgebraKit and include: | ||
| - `:DefaultAlgorithm` : MatrixAlgebraKit's [default orthogonalization algorithm](@extref MatrixAlgebraKit.DefaultAlgorithm) for a given matrix type. | ||
| - `:Householder` : MatrixAlgebraKit's [`Householder`](@extref MatrixAlgebraKit.Householder) | ||
| * `rrule_alg::Union{Algorithm,NamedTuple}=(; alg::Symbol=$(Defaults.orth_rrule_alg))`: Reverse-rule algorithm for differentiating the QR or LQ decomposition. | ||
| Can be supplied by an `Algorithm` instance directly or as a `NamedTuple` where `alg` is one of the following: | ||
| - `:FullPullback` : MatrixAlgebraKit's [`qr_pullback!`](@extref MatrixAlgebraKit.qr_pullback!) or [`lq_pullback!`](@extref MatrixAlgebraKit.lq_pullback!), selected by the orthogonalization direction. | ||
|
|
||
| !!! note | ||
| Manually specifying a `rrule_alg` is considered expert-mode usage, and should only be done when full control over the implementation is desired. | ||
| For all regular use cases, the default reverse rule algorithms, automatically chosen based on the forward algorithm, should be sufficient. | ||
| """ | ||
| struct OrthAdjoint{F, R} | ||
| fwd_alg::F | ||
| rrule_alg::R | ||
| end | ||
|
|
||
| """Compatibility alias for [`OrthAdjoint`](@ref), supporting both QR and LQ decompositions.""" | ||
| const QRAdjoint = OrthAdjoint | ||
|
|
||
| const ORTH_FWD_SYMBOLS = IdDict{Symbol, Any}( | ||
| :DefaultAlgorithm => DefaultAlgorithm, | ||
| :Householder => Householder, | ||
| ) | ||
| const ORTH_RRULE_SYMBOLS = IdDict{Symbol, Type{<:Any}}( | ||
| :FullPullback => FullPullback | ||
| ) | ||
|
|
||
| function OrthAdjoint(; fwd_alg = (;), rrule_alg = (;)) | ||
| # parse forward algorithm | ||
| fwd_algorithm = if fwd_alg isa NamedTuple | ||
| fwd_kwargs = (; | ||
| alg = Defaults.orth_fwd_alg, | ||
| positive = Defaults.orth_fwd_positive, | ||
| fwd_alg..., | ||
| ) # overwrite with specified kwargs | ||
| haskey(ORTH_FWD_SYMBOLS, fwd_kwargs.alg) || | ||
| throw(ArgumentError("unknown forward algorithm: $(fwd_kwargs.alg)")) | ||
| fwd_type = ORTH_FWD_SYMBOLS[fwd_kwargs.alg] | ||
| fwd_kwargs = Base.structdiff(fwd_kwargs, (; alg = nothing)) # remove `alg` keyword argument | ||
| fwd_type(; fwd_kwargs...) | ||
| else | ||
| fwd_alg | ||
| end | ||
|
|
||
| # parse reverse-rule algorithm | ||
| rrule_algorithm = if rrule_alg isa NamedTuple | ||
| rrule_kwargs = (; | ||
| alg = Defaults.orth_rrule_alg, | ||
| verbosity = Defaults.orth_rrule_verbosity, | ||
| rrule_alg..., | ||
| ) # overwrite with specified kwargs | ||
|
|
||
| haskey(ORTH_RRULE_SYMBOLS, rrule_kwargs.alg) || | ||
| throw(ArgumentError("unknown rrule algorithm: $(rrule_kwargs.alg)")) | ||
| rrule_type = ORTH_RRULE_SYMBOLS[rrule_kwargs.alg] | ||
| rrule_type() | ||
| else | ||
| rrule_alg | ||
| end | ||
|
|
||
| return OrthAdjoint(fwd_algorithm, rrule_algorithm) | ||
| end | ||
|
|
||
| """ | ||
| left_orth(t, alg::OrthAdjoint) | ||
| left_orth!(t, alg::OrthAdjoint) | ||
|
|
||
| Wrapper around `left_orth(!)` which dispatches on the `OrthAdjoint` algorithm. | ||
| This is needed since a custom adjoint may be defined, depending on the `alg`. | ||
| """ | ||
| MatrixAlgebraKit.left_orth(t, alg::OrthAdjoint) = left_orth!(copy(t), alg) | ||
| MatrixAlgebraKit.left_orth!(t, alg::OrthAdjoint) = left_orth!(t, alg.fwd_alg) | ||
|
|
||
| # left_orth! rrule wrapping MatrixAlgebraKit's qr_pullback! | ||
| # https://github.com/QuantumKitHub/MatrixAlgebraKit.jl/blob/b76c7bb60014ecfead6925d0df6cb4b8d7c2668a/src/pullbacks/qr.jl#L49 | ||
| function ChainRulesCore.rrule( | ||
| ::typeof(left_orth!), | ||
| t::AbstractTensorMap, | ||
| alg::OrthAdjoint{F, R}, | ||
| ) where {F <: MatrixAlgebraKit.Algorithm, R <: FullPullback} | ||
| QR = left_orth(t, alg) | ||
| gtol = _get_pullback_gauge_tol(alg.rrule_alg.verbosity) | ||
|
|
||
| """Propagate QR cotangents with the configured gauge-sensitivity tolerance.""" | ||
| function left_orth!_pullback(ΔQR) | ||
| Δt = zeros(storagetype(t), space(t)) | ||
| MatrixAlgebraKit.qr_pullback!(Δt, t, QR, unthunk.(ΔQR); gauge_atol = gtol(ΔQR)) | ||
| return NoTangent(), Δt, NoTangent() | ||
| end | ||
| function left_orth!_pullback(::Tuple{ZeroTangent, ZeroTangent}) | ||
| return NoTangent(), ZeroTangent(), NoTangent() | ||
| end | ||
|
|
||
| return QR, left_orth!_pullback | ||
| end | ||
|
|
||
| """ | ||
| right_orth(t, alg::OrthAdjoint) | ||
| right_orth!(t, alg::OrthAdjoint) | ||
|
|
||
| Wrapper around `right_orth(!)` which dispatches on the `OrthAdjoint` algorithm. | ||
| This is needed since a custom adjoint may be defined, depending on the `alg`. | ||
| """ | ||
| MatrixAlgebraKit.right_orth(t, alg::OrthAdjoint) = right_orth!(copy(t), alg) | ||
| MatrixAlgebraKit.right_orth!(t, alg::OrthAdjoint) = right_orth!(t, alg.fwd_alg) | ||
|
|
||
| # right_orth! rrule wrapping MatrixAlgebraKit's lq_pullback! | ||
| function ChainRulesCore.rrule( | ||
| ::typeof(right_orth!), | ||
| t::AbstractTensorMap, | ||
| alg::OrthAdjoint{F, R}, | ||
| ) where {F <: MatrixAlgebraKit.Algorithm, R <: FullPullback} | ||
| LQ = right_orth(t, alg) | ||
| gtol = _get_pullback_gauge_tol(alg.rrule_alg.verbosity) | ||
|
|
||
| """Propagate LQ cotangents with the configured gauge-sensitivity tolerance.""" | ||
| function right_orth!_pullback(ΔLQ) | ||
| Δt = zeros(storagetype(t), space(t)) | ||
| MatrixAlgebraKit.lq_pullback!(Δt, t, LQ, unthunk.(ΔLQ); gauge_atol = gtol(ΔLQ)) | ||
| return NoTangent(), Δt, NoTangent() | ||
| end | ||
| function right_orth!_pullback(::Tuple{ZeroTangent, ZeroTangent}) | ||
| return NoTangent(), ZeroTangent(), NoTangent() | ||
| end | ||
|
|
||
| return LQ, right_orth!_pullback | ||
| end |
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.