From e347028017d2ebf2283d3378893af2c25048f29e Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 15 May 2025 10:39:33 -0400 Subject: [PATCH 1/8] Support unsorted spectrum in TruncationKeepAbove/TruncationKeepBelow --- src/implementations/truncation.jl | 42 ++++++++++++++++++++++++++++++- test/truncate.jl | 22 +++++++++++++--- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/implementations/truncation.jl b/src/implementations/truncation.jl index 1898a010..8fe033f2 100644 --- a/src/implementations/truncation.jl +++ b/src/implementations/truncation.jl @@ -166,9 +166,20 @@ end # specific implementations for finding truncated values findtruncated(values::AbstractVector, ::NoTruncation) = Colon() +function findtruncated(values::AbstractVector, strategy::TruncationKeepSorted) + if issorted(values; by=strategy.sortby, rev=strategy.rev) + return findtruncated_sorted(values, strategy) + else + return findtruncated_unsorted(values, strategy) + end +end +function findtruncated_sorted(values::AbstractVector, strategy::TruncationKeepSorted) + howmany = min(strategy.howmany, length(values)) + return 1:howmany +end # TODO: this may also permute the eigenvalues, decide if we want to allow this or not # can be solved by going to simply sorting the resulting `ind` -function findtruncated(values::AbstractVector, strategy::TruncationKeepSorted) +function findtruncated_unsorted(values::AbstractVector, strategy::TruncationKeepSorted) sorted = sortperm(values; by=strategy.sortby, rev=strategy.rev) howmany = min(strategy.howmany, length(sorted)) ind = sorted[1:howmany] @@ -182,15 +193,44 @@ function findtruncated(values::AbstractVector, strategy::TruncationKeepFiltered) end function findtruncated(values::AbstractVector, strategy::TruncationKeepBelow) + if issorted(values; by=abs, rev=true) + return findtruncated_sorted(values, strategy) + else + return findtruncated_unsorted(values, strategy) + end +end +function findtruncated_sorted(values::AbstractVector, strategy::TruncationKeepBelow) atol = max(strategy.atol, strategy.rtol * first(values)) i = @something findfirst(≤(atol), values) length(values) + 1 return i:length(values) end +function findtruncated_unsorted(values::AbstractVector, strategy::TruncationKeepBelow) + atol = max(strategy.atol, strategy.rtol * first(values)) + sorted = sortperm(values; by=abs, rev=true) + i = @something findfirst(≤(atol), values[sorted]) length(values) + 1 + ind = sorted[i:length(values)] + return ind # TODO: consider sort!(ind) +end + function findtruncated(values::AbstractVector, strategy::TruncationKeepAbove) + if issorted(values; by=abs, rev=true) + return findtruncated_sorted(values, strategy) + else + return findtruncated_unsorted(values, strategy) + end +end +function findtruncated_sorted(values::AbstractVector, strategy::TruncationKeepAbove) atol = max(strategy.atol, strategy.rtol * first(values)) i = @something findlast(≥(atol), values) 0 return 1:i end +function findtruncated_unsorted(values::AbstractVector, strategy::TruncationKeepAbove) + atol = max(strategy.atol, strategy.rtol * first(values)) + sorted = sortperm(values; by=abs, rev=true) + i = @something findlast(≥(atol), values[sorted]) 0 + ind = sorted[1:i] + return ind # TODO: consider sort!(ind) +end function findtruncated(values::AbstractVector, strategy::TruncationIntersection) inds = map(Base.Fix1(findtruncated, values), strategy.components) diff --git a/test/truncate.jl b/test/truncate.jl index 2e67b894..de5a0ef6 100644 --- a/test/truncate.jl +++ b/test/truncate.jl @@ -2,7 +2,7 @@ using MatrixAlgebraKit using Test using TestExtras using MatrixAlgebraKit: NoTruncation, TruncationIntersection, TruncationKeepAbove, - TruncationStrategy, findtruncated + TruncationKeepBelow, TruncationStrategy, findtruncated @testset "truncate" begin trunc = @constinferred TruncationStrategy() @@ -28,7 +28,21 @@ using MatrixAlgebraKit: NoTruncation, TruncationIntersection, TruncationKeepAbov @test trunc.components[2] == TruncationKeepAbove(1e-2, 1e-3) values = [1, 0.9, 0.5, 0.3, 0.01] - @test @constinferred(findtruncated(values, truncrank(2))) == [1, 2] - @test @constinferred(findtruncated(values, truncrank(2; rev=false))) == [5, 4] - @test @constinferred(findtruncated(values, truncrank(2; by=-))) == [5, 4] + @test @constinferred(Vector{Int}, findtruncated(values, truncrank(2))) === 1:2 + @test @constinferred(UnitRange{Int}, findtruncated(values, truncrank(2; rev=false))) == + [5, 4] + @test @constinferred(UnitRange{Int}, findtruncated(values, truncrank(2; by=-))) == + [5, 4] + + values = [1, 0.9, 0.5, 0.3, 0.01] + @test @constinferred(Vector{Int}, + findtruncated(values, TruncationKeepAbove(0.4, 0.0))) === 1:3 + @test @constinferred(Vector{Int}, + findtruncated(values, TruncationKeepBelow(0.4, 0.0))) === 4:5 + + values = [0.01, 1, 0.9, 0.3, 0.5] + @test @constinferred(UnitRange{Int}, + findtruncated(values, TruncationKeepAbove(0.4, 0.0))) == [2, 3, 5] + @test @constinferred(UnitRange{Int}, + findtruncated(values, TruncationKeepBelow(0.4, 0.0))) == [4, 1] end From bd727d1d51750e9f8fb142af0d578085f9af3efb Mon Sep 17 00:00:00 2001 From: Matt Fishman Date: Fri, 16 May 2025 09:57:30 -0400 Subject: [PATCH 2/8] Use `maximum` instead of `first` when unsorted Co-authored-by: Jutho --- src/implementations/truncation.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/implementations/truncation.jl b/src/implementations/truncation.jl index 8fe033f2..35c3c3b8 100644 --- a/src/implementations/truncation.jl +++ b/src/implementations/truncation.jl @@ -205,7 +205,7 @@ function findtruncated_sorted(values::AbstractVector, strategy::TruncationKeepBe return i:length(values) end function findtruncated_unsorted(values::AbstractVector, strategy::TruncationKeepBelow) - atol = max(strategy.atol, strategy.rtol * first(values)) + atol = max(strategy.atol, strategy.rtol * maximum(values)) sorted = sortperm(values; by=abs, rev=true) i = @something findfirst(≤(atol), values[sorted]) length(values) + 1 ind = sorted[i:length(values)] @@ -225,7 +225,7 @@ function findtruncated_sorted(values::AbstractVector, strategy::TruncationKeepAb return 1:i end function findtruncated_unsorted(values::AbstractVector, strategy::TruncationKeepAbove) - atol = max(strategy.atol, strategy.rtol * first(values)) + atol = max(strategy.atol, strategy.rtol * maximum(values)) sorted = sortperm(values; by=abs, rev=true) i = @something findlast(≥(atol), values[sorted]) 0 ind = sorted[1:i] From e06f0e29b0735ca8fb4a25abf029ba0c9c3834c7 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Fri, 16 May 2025 09:59:53 -0400 Subject: [PATCH 3/8] Simplify with findall --- src/implementations/truncation.jl | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/implementations/truncation.jl b/src/implementations/truncation.jl index 35c3c3b8..5d20aaec 100644 --- a/src/implementations/truncation.jl +++ b/src/implementations/truncation.jl @@ -206,10 +206,7 @@ function findtruncated_sorted(values::AbstractVector, strategy::TruncationKeepBe end function findtruncated_unsorted(values::AbstractVector, strategy::TruncationKeepBelow) atol = max(strategy.atol, strategy.rtol * maximum(values)) - sorted = sortperm(values; by=abs, rev=true) - i = @something findfirst(≤(atol), values[sorted]) length(values) + 1 - ind = sorted[i:length(values)] - return ind # TODO: consider sort!(ind) + return findall(≤(atol), values) end function findtruncated(values::AbstractVector, strategy::TruncationKeepAbove) @@ -226,10 +223,7 @@ function findtruncated_sorted(values::AbstractVector, strategy::TruncationKeepAb end function findtruncated_unsorted(values::AbstractVector, strategy::TruncationKeepAbove) atol = max(strategy.atol, strategy.rtol * maximum(values)) - sorted = sortperm(values; by=abs, rev=true) - i = @something findlast(≥(atol), values[sorted]) 0 - ind = sorted[1:i] - return ind # TODO: consider sort!(ind) + return findall(≥(atol), values) end function findtruncated(values::AbstractVector, strategy::TruncationIntersection) From 55c0a077c22e62c813e83654d22a54c3a36b0c96 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Fri, 16 May 2025 11:17:47 -0400 Subject: [PATCH 4/8] Type stability --- src/implementations/truncation.jl | 6 +++--- test/truncate.jl | 20 +++++++------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/implementations/truncation.jl b/src/implementations/truncation.jl index 5d20aaec..e04af990 100644 --- a/src/implementations/truncation.jl +++ b/src/implementations/truncation.jl @@ -168,7 +168,7 @@ findtruncated(values::AbstractVector, ::NoTruncation) = Colon() function findtruncated(values::AbstractVector, strategy::TruncationKeepSorted) if issorted(values; by=strategy.sortby, rev=strategy.rev) - return findtruncated_sorted(values, strategy) + return convert(Vector{Int}, findtruncated_sorted(values, strategy)) else return findtruncated_unsorted(values, strategy) end @@ -194,7 +194,7 @@ end function findtruncated(values::AbstractVector, strategy::TruncationKeepBelow) if issorted(values; by=abs, rev=true) - return findtruncated_sorted(values, strategy) + return convert(Vector{Int}, findtruncated_sorted(values, strategy)) else return findtruncated_unsorted(values, strategy) end @@ -211,7 +211,7 @@ end function findtruncated(values::AbstractVector, strategy::TruncationKeepAbove) if issorted(values; by=abs, rev=true) - return findtruncated_sorted(values, strategy) + return convert(Vector{Int}, findtruncated_sorted(values, strategy)) else return findtruncated_unsorted(values, strategy) end diff --git a/test/truncate.jl b/test/truncate.jl index de5a0ef6..bc5452fb 100644 --- a/test/truncate.jl +++ b/test/truncate.jl @@ -28,21 +28,15 @@ using MatrixAlgebraKit: NoTruncation, TruncationIntersection, TruncationKeepAbov @test trunc.components[2] == TruncationKeepAbove(1e-2, 1e-3) values = [1, 0.9, 0.5, 0.3, 0.01] - @test @constinferred(Vector{Int}, findtruncated(values, truncrank(2))) === 1:2 - @test @constinferred(UnitRange{Int}, findtruncated(values, truncrank(2; rev=false))) == - [5, 4] - @test @constinferred(UnitRange{Int}, findtruncated(values, truncrank(2; by=-))) == - [5, 4] + @test @constinferred(findtruncated(values, truncrank(2))) == 1:2 + @test @constinferred(findtruncated(values, truncrank(2; rev=false))) == [5, 4] + @test @constinferred(findtruncated(values, truncrank(2; by=-))) == [5, 4] values = [1, 0.9, 0.5, 0.3, 0.01] - @test @constinferred(Vector{Int}, - findtruncated(values, TruncationKeepAbove(0.4, 0.0))) === 1:3 - @test @constinferred(Vector{Int}, - findtruncated(values, TruncationKeepBelow(0.4, 0.0))) === 4:5 + @test @constinferred(findtruncated(values, TruncationKeepAbove(0.4, 0.0))) == 1:3 + @test @constinferred(findtruncated(values, TruncationKeepBelow(0.4, 0.0))) == 4:5 values = [0.01, 1, 0.9, 0.3, 0.5] - @test @constinferred(UnitRange{Int}, - findtruncated(values, TruncationKeepAbove(0.4, 0.0))) == [2, 3, 5] - @test @constinferred(UnitRange{Int}, - findtruncated(values, TruncationKeepBelow(0.4, 0.0))) == [4, 1] + @test @constinferred(findtruncated(values, TruncationKeepAbove(0.4, 0.0))) == [2, 3, 5] + @test @constinferred(findtruncated(values, TruncationKeepBelow(0.4, 0.0))) == [1, 4] end From 0dfad35bde22cb62367f6027b69a6912366a6ebf Mon Sep 17 00:00:00 2001 From: mtfishman Date: Wed, 21 May 2025 19:16:42 -0400 Subject: [PATCH 5/8] Simplify implementation of findtruncated --- src/implementations/truncation.jl | 56 +++++++++++-------------------- test/truncate.jl | 2 +- 2 files changed, 20 insertions(+), 38 deletions(-) diff --git a/src/implementations/truncation.jl b/src/implementations/truncation.jl index e04af990..5b2ff789 100644 --- a/src/implementations/truncation.jl +++ b/src/implementations/truncation.jl @@ -48,13 +48,13 @@ end # since these are implicitly discarded by selecting compact/full """ - TruncationKeepSorted(howmany::Int, sortby::Function, rev::Bool) + TruncationKeepSorted(howmany::Int, by::Function, rev::Bool) -Truncation strategy to keep the first `howmany` values when sorted according to `sortby` or the last `howmany` if `rev` is true. +Truncation strategy to keep the first `howmany` values when sorted according to `by` or the last `howmany` if `rev` is true. """ struct TruncationKeepSorted{F} <: TruncationStrategy howmany::Int - sortby::F + by::F rev::Bool end @@ -137,7 +137,7 @@ Generic interface for post-truncating a decomposition, specified in `out`. """ truncate! # TODO: should we return a view? function truncate!(::typeof(svd_trunc!), (U, S, Vᴴ), strategy::TruncationStrategy) - ind = findtruncated(diagview(S), strategy) + ind = findtruncated_sorted(diagview(S), strategy) return U[:, ind], Diagonal(diagview(S)[ind]), Vᴴ[ind, :] end function truncate!(::typeof(eig_trunc!), (D, V), strategy::TruncationStrategy) @@ -166,25 +166,16 @@ end # specific implementations for finding truncated values findtruncated(values::AbstractVector, ::NoTruncation) = Colon() +# TODO: this may also permute the eigenvalues, decide if we want to allow this or not +# can be solved by going to simply sorting the resulting `ind` function findtruncated(values::AbstractVector, strategy::TruncationKeepSorted) - if issorted(values; by=strategy.sortby, rev=strategy.rev) - return convert(Vector{Int}, findtruncated_sorted(values, strategy)) - else - return findtruncated_unsorted(values, strategy) - end + howmany = min(strategy.howmany, length(values)) + return partialsortperm(values, 1:howmany; by=strategy.by, rev=strategy.rev) end function findtruncated_sorted(values::AbstractVector, strategy::TruncationKeepSorted) howmany = min(strategy.howmany, length(values)) return 1:howmany end -# TODO: this may also permute the eigenvalues, decide if we want to allow this or not -# can be solved by going to simply sorting the resulting `ind` -function findtruncated_unsorted(values::AbstractVector, strategy::TruncationKeepSorted) - sorted = sortperm(values; by=strategy.sortby, rev=strategy.rev) - howmany = min(strategy.howmany, length(sorted)) - ind = sorted[1:howmany] - return ind # TODO: consider sort!(ind) -end # TODO: consider if worth using that values are sorted when filter is `<` or `>`. function findtruncated(values::AbstractVector, strategy::TruncationKeepFiltered) @@ -193,44 +184,35 @@ function findtruncated(values::AbstractVector, strategy::TruncationKeepFiltered) end function findtruncated(values::AbstractVector, strategy::TruncationKeepBelow) - if issorted(values; by=abs, rev=true) - return convert(Vector{Int}, findtruncated_sorted(values, strategy)) - else - return findtruncated_unsorted(values, strategy) - end + atol = max(strategy.atol, strategy.rtol * maximum(values)) + return findall(≤(atol), values) end function findtruncated_sorted(values::AbstractVector, strategy::TruncationKeepBelow) atol = max(strategy.atol, strategy.rtol * first(values)) - i = @something findfirst(≤(atol), values) length(values) + 1 + i = searchsortedfirst(values, atol; by=abs, rev=true) return i:length(values) end -function findtruncated_unsorted(values::AbstractVector, strategy::TruncationKeepBelow) - atol = max(strategy.atol, strategy.rtol * maximum(values)) - return findall(≤(atol), values) -end function findtruncated(values::AbstractVector, strategy::TruncationKeepAbove) - if issorted(values; by=abs, rev=true) - return convert(Vector{Int}, findtruncated_sorted(values, strategy)) - else - return findtruncated_unsorted(values, strategy) - end + atol = max(strategy.atol, strategy.rtol * maximum(values)) + return findall(≥(atol), values) end function findtruncated_sorted(values::AbstractVector, strategy::TruncationKeepAbove) atol = max(strategy.atol, strategy.rtol * first(values)) - i = @something findlast(≥(atol), values) 0 + i = searchsortedlast(values, atol; by=abs, rev=true) return 1:i end -function findtruncated_unsorted(values::AbstractVector, strategy::TruncationKeepAbove) - atol = max(strategy.atol, strategy.rtol * maximum(values)) - return findall(≥(atol), values) -end function findtruncated(values::AbstractVector, strategy::TruncationIntersection) inds = map(Base.Fix1(findtruncated, values), strategy.components) return intersect(inds...) end +# Generic fallback. +function findtruncated_sorted(values::AbstractVector, strategy::TruncationStrategy) + return findtruncated(values, strategy) +end + """ TruncatedAlgorithm(alg::AbstractAlgorithm, trunc::TruncationAlgorithm) diff --git a/test/truncate.jl b/test/truncate.jl index bc5452fb..5c2aedfc 100644 --- a/test/truncate.jl +++ b/test/truncate.jl @@ -18,7 +18,7 @@ using MatrixAlgebraKit: NoTruncation, TruncationIntersection, TruncationKeepAbov @test trunc isa TruncationKeepSorted @test trunc == truncrank(10) @test trunc.howmany == 10 - @test trunc.sortby == abs + @test trunc.by == abs @test trunc.rev == true trunc = @constinferred TruncationStrategy(; atol=1e-2, rtol=1e-3, maxrank=10) From 891b289376c5532ca901d9368637407873f90075 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Wed, 21 May 2025 19:22:03 -0400 Subject: [PATCH 6/8] Allow specifying the norm --- src/implementations/truncation.jl | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/implementations/truncation.jl b/src/implementations/truncation.jl index 5b2ff789..7fbba990 100644 --- a/src/implementations/truncation.jl +++ b/src/implementations/truncation.jl @@ -70,14 +70,20 @@ end struct TruncationKeepAbove{T<:Real} <: TruncationStrategy atol::T rtol::T + p::Int +end +function TruncationKeepAbove(atol::Real, rtol::Real, p::Int=2) + return TruncationKeepAbove(promote(atol, rtol)..., p) end -TruncationKeepAbove(atol::Real, rtol::Real) = TruncationKeepAbove(promote(atol, rtol)...) struct TruncationKeepBelow{T<:Real} <: TruncationStrategy atol::T rtol::T + p::Int +end +function TruncationKeepBelow(atol::Real, rtol::Real, p::Int=2) + return TruncationKeepBelow(promote(atol, rtol)..., p) end -TruncationKeepBelow(atol::Real, rtol::Real) = TruncationKeepBelow(promote(atol, rtol)...) # TODO: better names for these functions of the above types """ @@ -184,21 +190,21 @@ function findtruncated(values::AbstractVector, strategy::TruncationKeepFiltered) end function findtruncated(values::AbstractVector, strategy::TruncationKeepBelow) - atol = max(strategy.atol, strategy.rtol * maximum(values)) + atol = max(strategy.atol, strategy.rtol * norm(values, strategy.p)) return findall(≤(atol), values) end function findtruncated_sorted(values::AbstractVector, strategy::TruncationKeepBelow) - atol = max(strategy.atol, strategy.rtol * first(values)) + atol = max(strategy.atol, strategy.rtol * norm(values, strategy.p)) i = searchsortedfirst(values, atol; by=abs, rev=true) return i:length(values) end function findtruncated(values::AbstractVector, strategy::TruncationKeepAbove) - atol = max(strategy.atol, strategy.rtol * maximum(values)) + atol = max(strategy.atol, strategy.rtol * norm(values, strategy.p)) return findall(≥(atol), values) end function findtruncated_sorted(values::AbstractVector, strategy::TruncationKeepAbove) - atol = max(strategy.atol, strategy.rtol * first(values)) + atol = max(strategy.atol, strategy.rtol * norm(values, strategy.p)) i = searchsortedlast(values, atol; by=abs, rev=true) return 1:i end From 3438ec0c1ffd4e08e88ad1c3ad039ff901d2fcf2 Mon Sep 17 00:00:00 2001 From: Matt Fishman Date: Thu, 22 May 2025 11:25:44 -0400 Subject: [PATCH 7/8] Update docstring Co-authored-by: Jutho --- src/implementations/truncation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/implementations/truncation.jl b/src/implementations/truncation.jl index 7fbba990..98a55b09 100644 --- a/src/implementations/truncation.jl +++ b/src/implementations/truncation.jl @@ -50,7 +50,7 @@ end """ TruncationKeepSorted(howmany::Int, by::Function, rev::Bool) -Truncation strategy to keep the first `howmany` values when sorted according to `by` or the last `howmany` if `rev` is true. +Truncation strategy to keep the first `howmany` values when sorted according to `by` in increasing (decreasing) order if `rev` is false (true). """ struct TruncationKeepSorted{F} <: TruncationStrategy howmany::Int From ee4ea74ec37db393bf7b85c37cfbc56053d9d6bd Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 22 May 2025 11:44:00 -0400 Subject: [PATCH 8/8] Add docs for findtruncated --- docs/src/dev_interface.md | 2 ++ src/MatrixAlgebraKit.jl | 3 ++- src/implementations/truncation.jl | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/docs/src/dev_interface.md b/docs/src/dev_interface.md index 4482a5c6..52d44ca1 100644 --- a/docs/src/dev_interface.md +++ b/docs/src/dev_interface.md @@ -10,4 +10,6 @@ MatrixAlgebraKit.jl provides a developer interface for specifying custom algorit ```@docs; canonical=false MatrixAlgebraKit.default_algorithm MatrixAlgebraKit.select_algorithm +MatrixAlgebraKit.findtruncated +MatrixAlgebraKit.findtruncated_sorted ``` diff --git a/src/MatrixAlgebraKit.jl b/src/MatrixAlgebraKit.jl index a9f48393..54207e60 100644 --- a/src/MatrixAlgebraKit.jl +++ b/src/MatrixAlgebraKit.jl @@ -31,7 +31,8 @@ export LAPACK_HouseholderQR, LAPACK_HouseholderLQ, export truncrank, trunctol, truncabove, TruncationKeepSorted, TruncationKeepFiltered VERSION >= v"1.11.0-DEV.469" && - eval(Expr(:public, :default_algorithm, :select_algorithm)) + eval(Expr(:public, :default_algorithm, :findtruncated, :findtruncated_sorted, + :select_algorithm)) include("common/defaults.jl") include("common/initialization.jl") diff --git a/src/implementations/truncation.jl b/src/implementations/truncation.jl index 98a55b09..38af507e 100644 --- a/src/implementations/truncation.jl +++ b/src/implementations/truncation.jl @@ -170,6 +170,27 @@ end # findtruncated # ------------- # specific implementations for finding truncated values +@doc """ + MatrixAlgebraKit.findtruncated(values::AbstractVector, strategy::TruncationStrategy) + +Generic interface for finding truncated values of the spectrum of a decomposition +based on the `strategy`. The output should be a collection of indices specifying +which values to keep. `MatrixAlgebraKit.findtruncated` is used inside of the default +implementation of [`truncate!`](@ref) to perform the truncation. It does not assume that the +values are sorted. For a version that assumes the values are reverse sorted by +absolute value (which is the standard case for SVD) see +[`MatrixAlgebraKit.findtruncated_sorted`](@ref). +""" findtruncated + +@doc """ + MatrixAlgebraKit.findtruncated_sorted(values::AbstractVector, strategy::TruncationStrategy) + +Like [`MatrixAlgebraKit.findtruncated`](@ref) but assumes that the values are sorted in reverse order by +absolute value. However, note that this assumption is not checked, so passing values that are not sorted +in that way can silently give unexpected results. This is used in the default implementation of +[`svd_trunc!`](@ref). +""" findtruncated_sorted + findtruncated(values::AbstractVector, ::NoTruncation) = Colon() # TODO: this may also permute the eigenvalues, decide if we want to allow this or not