diff --git a/.gitignore b/.gitignore index 22b0fc821..3e6da32ea 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ __pycache__ .ipynb* *Manifest.toml +*LocalPreferences.toml .vscode experimental refs diff --git a/Project.toml b/Project.toml index 65345342b..2b1a4750b 100644 --- a/Project.toml +++ b/Project.toml @@ -57,7 +57,7 @@ FiniteDifferences = "0.12" GPUArrays = "11.4.1" LRUCache = "1.6" LinearAlgebra = "1" -MatrixAlgebraKit = "0.6.13" +MatrixAlgebraKit = "0.6.14" Mooncake = "0.5.27" OhMyThreads = "0.8.0" PrecompileTools = "1" diff --git a/docs/src/man/factorizations.md b/docs/src/man/factorizations.md index da0069730..d1fa593df 100644 --- a/docs/src/man/factorizations.md +++ b/docs/src/man/factorizations.md @@ -44,3 +44,20 @@ P ≈ P * P t′ = permute(t, ((1,), (2, 3))); t′ ≈ t′ * P ``` + +To compute only the `R` or `L` factor with QR/LQ-based `left_orth!` and `right_orth!`, pass a zero-dimensional tensor map as the basis output. + +```julia +V = infimum(fuse(codomain(t)), fuse(domain(t))) +V0 = zerospace(spacetype(t)) +Q0 = similar(t, V0 ← V0) + +R = similar(t, V ← domain(t)) +_, R = left_orth!(copy(t), (Q0, R)) + +L = similar(t, codomain(t) ← V) +L, _ = right_orth!(copy(t), (L, Q0)) +``` + +For a `DiagonalTensorMap`, use an empty `DiagonalTensorMap` as the basis output instead. +Differentiation of these R/L-only paths is not yet supported. diff --git a/test/factorizations/ortho.jl b/test/factorizations/ortho.jl index 170d596a2..05f272d80 100644 --- a/test/factorizations/ortho.jl +++ b/test/factorizations/ortho.jl @@ -52,6 +52,19 @@ for V in spacelist @test Q * R ≈ t @test isisometric(Q) + # Compute only R by passing an empty basis output. + V0 = zerospace(spacetype(t)) + Q0 = t isa DiagonalTensorMap ? DiagonalTensorMap(T[], V0) : similar(t, V0 ← V0) + for positive in (false, true), alg in ((; positive), DefaultAlgorithm(; positive)) + Q, R = @constinferred left_orth(t; positive) + R0 = similar(R) + Q2, R2 = @constinferred left_orth!(copy(t), (Q0, R0); alg) + @test dim(Q2) == 0 + @test space(R2) == space(R) + @test R2 ≈ R + @test Q * R2 ≈ t + end + N = @constinferred qr_null(t) @test isisometric(N) @test norm(N' * t) ≈ 0 atol = 100 * eps(norm(t)) @@ -146,6 +159,19 @@ for V in spacelist @test L * Q ≈ t @test isisometric(Q; side = :right) + # Compute only L by passing an empty basis output. + V0 = zerospace(spacetype(t)) + Q0 = t isa DiagonalTensorMap ? DiagonalTensorMap(T[], V0) : similar(t, V0 ← V0) + for positive in (false, true), alg in ((; positive), DefaultAlgorithm(; positive)) + L, Q = @constinferred right_orth(t; positive) + L0 = similar(L) + L2, Q2 = @constinferred right_orth!(copy(t), (L0, Q0); alg) + @test dim(Q2) == 0 + @test space(L2) == space(L) + @test L2 ≈ L + @test L2 * Q ≈ t + end + Nᴴ = @constinferred lq_null(t) @test isisometric(Nᴴ; side = :right) @test norm(t * Nᴴ') ≈ 0 atol = 100 * eps(norm(t))