Skip to content

Commit

Permalink
refactor: use functionality from NonlinearSolveBase instead of `Dif…
Browse files Browse the repository at this point in the history
…fEqBase`
  • Loading branch information
avik-pal committed Oct 22, 2024
1 parent f6041af commit 0b91de7
Show file tree
Hide file tree
Showing 28 changed files with 65 additions and 122 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ BandedMatrices = "1.5"
BenchmarkTools = "1.4"
CUDA = "5.5"
ConcreteStructs = "0.2.3"
DiffEqBase = "6.155.3"
DiffEqBase = "6.158.3"
DifferentiationInterface = "0.6.1"
Enzyme = "0.13.2"
ExplicitImports = "1.5"
Expand Down
2 changes: 1 addition & 1 deletion docs/src/basics/solve.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ solve(prob::SciMLBase.NonlinearProblem, args...; kwargs...)
`real(oneunit(T)) * (eps(real(one(T))))^(4 // 5)`.
- `reltol::Number`: The relative tolerance. Defaults to
`real(oneunit(T)) * (eps(real(one(T))))^(4 // 5)`.
- `termination_condition`: Termination Condition from DiffEqBase. Defaults to
- `termination_condition`: Termination Condition from NonlinearSolveBase. Defaults to
`AbsSafeBestTerminationMode()` for `NonlinearSolve.jl` and `AbsTerminateMode()` for
`SimpleNonlinearSolve.jl`.

Expand Down
25 changes: 4 additions & 21 deletions docs/src/basics/termination_condition.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ cache = init(du, u, AbsSafeBestTerminationMode(); abstol = 1e-9, reltol = 1e-9)
If `abstol` and `reltol` are not supplied, then we choose a default based on the element
types of `du` and `u`.

We can query the `cache` using `DiffEqBase.get_termination_mode`, `DiffEqBase.get_abstol`
and `DiffEqBase.get_reltol`.

To test for termination simply call the `cache`:

```julia
Expand All @@ -28,29 +25,15 @@ terminated = cache(du, u, uprev)
```@docs
AbsTerminationMode
AbsNormTerminationMode
AbsSafeTerminationMode
AbsSafeBestTerminationMode
AbsNormSafeTerminationMode
AbsNormSafeBestTerminationMode
```

### Relative Tolerance

```@docs
RelTerminationMode
RelNormTerminationMode
RelSafeTerminationMode
RelSafeBestTerminationMode
```

### Both Absolute and Relative Tolerance

```@docs
NormTerminationMode
SteadyStateDiffEqTerminationMode
```

The following was named to match an older version of SimpleNonlinearSolve. It is currently
not used as a default anywhere.

```@docs
SimpleNonlinearSolveTerminationMode
RelNormSafeTerminationMode
RelNormSafeBestTerminationMode
```
5 changes: 3 additions & 2 deletions ext/NonlinearSolveFastLevenbergMarquardtExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module NonlinearSolveFastLevenbergMarquardtExt
using ArrayInterface: ArrayInterface
using FastClosures: @closure
using FastLevenbergMarquardt: FastLevenbergMarquardt
using NonlinearSolveBase: NonlinearSolveBase, get_tolerance
using NonlinearSolve: NonlinearSolve, FastLevenbergMarquardtJL
using SciMLBase: SciMLBase, NonlinearLeastSquaresProblem, NonlinearProblem, ReturnCode
using StaticArraysCore: SArray
Expand Down Expand Up @@ -33,8 +34,8 @@ function SciMLBase.__solve(prob::Union{NonlinearLeastSquaresProblem, NonlinearPr
else
@closure (du, u, p) -> fn(du, u)
end
abstol = NonlinearSolve.DEFAULT_TOLERANCE(abstol, eltype(u))
reltol = NonlinearSolve.DEFAULT_TOLERANCE(reltol, eltype(u))
abstol = get_tolerance(abstol, eltype(u))
reltol = get_tolerance(reltol, eltype(u))

_jac_fn = NonlinearSolve.__construct_extension_jac(
prob, alg, u, resid; alg.autodiff, can_handle_oop = Val(prob.u0 isa SArray))
Expand Down
3 changes: 2 additions & 1 deletion ext/NonlinearSolveFixedPointAccelerationExt.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module NonlinearSolveFixedPointAccelerationExt

using NonlinearSolveBase: NonlinearSolveBase, get_tolerance
using NonlinearSolve: NonlinearSolve, FixedPointAccelerationJL
using SciMLBase: SciMLBase, NonlinearProblem, ReturnCode
using FixedPointAcceleration: FixedPointAcceleration, fixed_point
Expand All @@ -13,7 +14,7 @@ function SciMLBase.__solve(prob::NonlinearProblem, alg::FixedPointAccelerationJL

f, u0, resid = NonlinearSolve.__construct_extension_f(
prob; alias_u0, make_fixed_point = Val(true), force_oop = Val(true))
tol = NonlinearSolve.DEFAULT_TOLERANCE(abstol, eltype(u0))
tol = get_tolerance(abstol, eltype(u0))

sol = fixed_point(f, u0; Algorithm = alg.algorithm, MaxIter = maxiters, MaxM = alg.m,
ConvergenceMetricThreshold = tol, ExtrapolationPeriod = alg.extrapolation_period,
Expand Down
5 changes: 3 additions & 2 deletions ext/NonlinearSolveLeastSquaresOptimExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module NonlinearSolveLeastSquaresOptimExt

using ConcreteStructs: @concrete
using LeastSquaresOptim: LeastSquaresOptim
using NonlinearSolveBase: NonlinearSolveBase, get_tolerance
using NonlinearSolve: NonlinearSolve, LeastSquaresOptimJL, TraceMinimal
using SciMLBase: SciMLBase, NonlinearLeastSquaresProblem, NonlinearProblem, ReturnCode

Expand Down Expand Up @@ -42,8 +43,8 @@ function SciMLBase.__init(prob::Union{NonlinearLeastSquaresProblem, NonlinearPro
NonlinearSolve.__test_termination_condition(termination_condition, :LeastSquaresOptim)

f!, u, resid = NonlinearSolve.__construct_extension_f(prob; alias_u0)
abstol = NonlinearSolve.DEFAULT_TOLERANCE(abstol, eltype(u))
reltol = NonlinearSolve.DEFAULT_TOLERANCE(reltol, eltype(u))
abstol = get_tolerance(abstol, eltype(u))
reltol = get_tolerance(reltol, eltype(u))

if prob.f.jac === nothing && alg.autodiff isa Symbol
lsoprob = LSO.LeastSquaresProblem(; x = u, f!, y = resid, alg.autodiff,
Expand Down
3 changes: 2 additions & 1 deletion ext/NonlinearSolveMINPACKExt.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module NonlinearSolveMINPACKExt

using MINPACK: MINPACK
using NonlinearSolveBase: NonlinearSolveBase, get_tolerance
using NonlinearSolve: NonlinearSolve, CMINPACK
using SciMLBase: SciMLBase, NonlinearLeastSquaresProblem, NonlinearProblem, ReturnCode
using FastClosures: @closure
Expand All @@ -21,7 +22,7 @@ function SciMLBase.__solve(

show_trace = ShT
tracing = StT
tol = NonlinearSolve.DEFAULT_TOLERANCE(abstol, eltype(u0))
tol = get_tolerance(abstol, eltype(u0))

if alg.autodiff === missing && prob.f.jac === nothing
original = MINPACK.fsolve(
Expand Down
5 changes: 3 additions & 2 deletions ext/NonlinearSolveNLSolversExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ using FiniteDiff: FiniteDiff
using ForwardDiff: ForwardDiff
using LinearAlgebra: norm
using NLSolvers: NLSolvers, NEqOptions, NEqProblem
using NonlinearSolveBase: NonlinearSolveBase, get_tolerance
using NonlinearSolve: NonlinearSolve, NLSolversJL
using SciMLBase: SciMLBase, NonlinearProblem, ReturnCode

Expand All @@ -14,8 +15,8 @@ function SciMLBase.__solve(prob::NonlinearProblem, alg::NLSolversJL, args...;
alias_u0::Bool = false, termination_condition = nothing, kwargs...)
NonlinearSolve.__test_termination_condition(termination_condition, :NLSolversJL)

abstol = NonlinearSolve.DEFAULT_TOLERANCE(abstol, eltype(prob.u0))
reltol = NonlinearSolve.DEFAULT_TOLERANCE(reltol, eltype(prob.u0))
abstol = get_tolerance(abstol, eltype(prob.u0))
reltol = get_tolerance(reltol, eltype(prob.u0))

options = NEqOptions(; maxiter = maxiters, f_abstol = abstol, f_reltol = reltol)

Expand Down
3 changes: 2 additions & 1 deletion ext/NonlinearSolveNLsolveExt.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module NonlinearSolveNLsolveExt

using LineSearches: Static
using NonlinearSolveBase: NonlinearSolveBase, get_tolerance
using NonlinearSolve: NonlinearSolve, NLsolveJL, TraceMinimal
using NLsolve: NLsolve, OnceDifferentiable, nlsolve
using SciMLBase: SciMLBase, NonlinearProblem, ReturnCode
Expand All @@ -27,7 +28,7 @@ function SciMLBase.__solve(
df = OnceDifferentiable(f!, jac!, vec(u0), vec(resid), J)
end

abstol = NonlinearSolve.DEFAULT_TOLERANCE(abstol, eltype(u0))
abstol = get_tolerance(abstol, eltype(u0))
show_trace = ShT
store_trace = StT
extended_trace = !(trace_level isa TraceMinimal)
Expand Down
5 changes: 3 additions & 2 deletions ext/NonlinearSolveSIAMFANLEquationsExt.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module NonlinearSolveSIAMFANLEquationsExt

using FastClosures: @closure
using NonlinearSolveBase: NonlinearSolveBase, get_tolerance
using NonlinearSolve: NonlinearSolve, SIAMFANLEquationsJL
using SciMLBase: SciMLBase, NonlinearProblem, ReturnCode
using SIAMFANLEquations: SIAMFANLEquations, aasol, nsol, nsoli, nsolsc, ptcsol, ptcsoli,
Expand Down Expand Up @@ -40,8 +41,8 @@ function SciMLBase.__solve(prob::NonlinearProblem, alg::SIAMFANLEquationsJL, arg

(; method, delta, linsolve, m, beta) = alg
T = eltype(prob.u0)
atol = NonlinearSolve.DEFAULT_TOLERANCE(abstol, T)
rtol = NonlinearSolve.DEFAULT_TOLERANCE(reltol, T)
atol = get_tolerance(abstol, T)
rtol = get_tolerance(reltol, T)

if prob.u0 isa Number
f = @closure u -> prob.f(u, prob.p)
Expand Down
3 changes: 2 additions & 1 deletion ext/NonlinearSolveSpeedMappingExt.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module NonlinearSolveSpeedMappingExt

using NonlinearSolveBase: NonlinearSolveBase, get_tolerance
using NonlinearSolve: NonlinearSolve, SpeedMappingJL
using SciMLBase: SciMLBase, NonlinearProblem, ReturnCode
using SpeedMapping: speedmapping
Expand All @@ -12,7 +13,7 @@ function SciMLBase.__solve(prob::NonlinearProblem, alg::SpeedMappingJL, args...;

m!, u, resid = NonlinearSolve.__construct_extension_f(
prob; alias_u0, make_fixed_point = Val(true))
tol = NonlinearSolve.DEFAULT_TOLERANCE(abstol, eltype(u))
tol = get_tolerance(abstol, eltype(u))

time_limit = ifelse(maxtime === nothing, 1000, maxtime)

Expand Down
2 changes: 1 addition & 1 deletion lib/NonlinearSolveBase/src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ standardize_norm(f::F) where {F} = f
norm_op(norm::N, op::OP, x, y) where {N, OP} = norm(op.(x, y))
function norm_op(::typeof(L2_NORM), op::OP, x, y) where {OP}
if fast_scalar_indexing(x, y)
return sqrt(sum(@closure((xᵢ, yᵢ)->begin
return sqrt(sum(@closure((xᵢyᵢ)->begin
xᵢ, yᵢ = xᵢyᵢ
return op(xᵢ, yᵢ)^2
end), zip(x, y)))
Expand Down
19 changes: 5 additions & 14 deletions src/NonlinearSolve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,7 @@ using PrecompileTools: @compile_workload, @setup_workload
using ArrayInterface: ArrayInterface, can_setindex, restructure, fast_scalar_indexing,
ismutable
using ConcreteStructs: @concrete
using DiffEqBase: DiffEqBase, AbstractNonlinearTerminationMode,
AbstractSafeBestNonlinearTerminationMode, AbsNormTerminationMode,
AbsSafeBestTerminationMode, AbsSafeTerminationMode, AbsTerminationMode,
NormTerminationMode, RelNormTerminationMode, RelSafeBestTerminationMode,
RelSafeTerminationMode, RelTerminationMode,
SimpleNonlinearSolveTerminationMode, SteadyStateDiffEqTerminationMode
using DiffEqBase: DiffEqBase # Needed for `init` / `solve` dispatches
using FastClosures: @closure
using LazyArrays: LazyArrays, ApplyArray, cache
using LinearAlgebra: LinearAlgebra, ColumnNorm, Diagonal, I, LowerTriangular, Symmetric,
Expand All @@ -24,7 +19,9 @@ using LinearSolve: LinearSolve, QRFactorization, needs_concrete_A, AbstractFacto
using MaybeInplace: @bb
using NonlinearSolveBase: NonlinearSolveBase, nonlinearsolve_forwarddiff_solve,
nonlinearsolve_dual_solution, nonlinearsolve_∂f_∂p,
nonlinearsolve_∂f_∂u
nonlinearsolve_∂f_∂u, L2_NORM, AbstractNonlinearTerminationMode,
AbstractSafeNonlinearTerminationMode,
AbstractSafeBestNonlinearTerminationMode
using Printf: @printf
using Preferences: Preferences, @load_preference, @set_preferences!
using RecursiveArrayTools: recursivecopy!
Expand All @@ -51,7 +48,7 @@ using SparseArrays: AbstractSparseMatrix, SparseMatrixCSC
using SparseMatrixColorings: ConstantColoringAlgorithm, GreedyColoringAlgorithm,
LargestFirst

@reexport using SciMLBase, SimpleNonlinearSolve
@reexport using SciMLBase, SimpleNonlinearSolve, NonlinearSolveBase

const DI = DifferentiationInterface

Expand Down Expand Up @@ -182,12 +179,6 @@ export LineSearch, BackTracking, NoLineSearch, RobustNonMonotoneLineSearch,
## Trust Region Algorithms
export RadiusUpdateSchemes

# Export the termination conditions from NonlinearSolveBase
export SteadyStateDiffEqTerminationMode, SimpleNonlinearSolveTerminationMode,
NormTerminationMode, RelTerminationMode, RelNormTerminationMode, AbsTerminationMode,
AbsNormTerminationMode, RelSafeTerminationMode, AbsSafeTerminationMode,
RelSafeBestTerminationMode, AbsSafeBestTerminationMode

# Tracing Functionality
export TraceAll, TraceMinimal, TraceWithJacobianConditionNumber

Expand Down
15 changes: 6 additions & 9 deletions src/abstract_types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,7 @@ Abstract Type for Damping Functions in DampedNewton.
```julia
__internal_init(
prob::AbstractNonlinearProblem, f::AbstractDampingFunction, initial_damping,
J, fu, u, args...; internal_norm = DEFAULT_NORM, kwargs...) -->
AbstractDampingFunctionCache
J, fu, u, args...; internal_norm = L2_NORM, kwargs...) --> AbstractDampingFunctionCache
```
Returns a [`AbstractDampingFunctionCache`](@ref).
Expand Down Expand Up @@ -348,7 +347,7 @@ Abstract Type for all Jacobian Initialization Algorithms used in NonlinearSolve.
```julia
__internal_init(
prob::AbstractNonlinearProblem, alg::AbstractJacobianInitialization, solver,
f::F, fu, u, p; linsolve = missing, internalnorm::IN = DEFAULT_NORM, kwargs...)
f::F, fu, u, p; linsolve = missing, internalnorm::IN = L2_NORM, kwargs...)
```
Returns a [`NonlinearSolve.InitializedApproximateJacobianCache`](@ref).
Expand Down Expand Up @@ -382,9 +381,8 @@ Abstract Type for all Approximate Jacobian Update Rules used in NonlinearSolve.j
```julia
__internal_init(
prob::AbstractNonlinearProblem, alg::AbstractApproximateJacobianUpdateRule, J,
fu, u, du, args...; internalnorm::F = DEFAULT_NORM, kwargs...) where {F} -->
AbstractApproximateJacobianUpdateRuleCache{INV}
prob::AbstractNonlinearProblem, alg::AbstractApproximateJacobianUpdateRule, J, fu, u,
du, args...; internalnorm::F = L2_NORM, kwargs...) where {F} --> AbstractApproximateJacobianUpdateRuleCache{INV}
```
"""
abstract type AbstractApproximateJacobianUpdateRule{INV} end
Expand Down Expand Up @@ -440,9 +438,8 @@ Abstract Type for all Trust Region Methods used in NonlinearSolve.jl.
```julia
__internal_init(
prob::AbstractNonlinearProblem, alg::AbstractTrustRegionMethod, f::F, fu, u,
p, args...; internalnorm::IF = DEFAULT_NORM, kwargs...) where {F, IF} -->
AbstractTrustRegionMethodCache
prob::AbstractNonlinearProblem, alg::AbstractTrustRegionMethod, f::F, fu, u, p, args...;
internalnorm::IF = L2_NORM, kwargs...) where {F, IF} --> AbstractTrustRegionMethodCache
```
"""
abstract type AbstractTrustRegionMethod end
Expand Down
2 changes: 1 addition & 1 deletion src/algorithms/broyden.jl
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ end

function __internal_init(prob::AbstractNonlinearProblem,
alg::Union{GoodBroydenUpdateRule, BadBroydenUpdateRule}, J, fu, u,
du, args...; internalnorm::F = DEFAULT_NORM, kwargs...) where {F}
du, args...; internalnorm::F = L2_NORM, kwargs...) where {F}
@bb J⁻¹dfu = similar(u)
@bb dfu = copy(fu)
if alg isa GoodBroydenUpdateRule || J isa Diagonal
Expand Down
2 changes: 1 addition & 1 deletion src/algorithms/lbroyden.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jacobian_initialized_preinverted(::BroydenLowRankInitialization) = true
function __internal_init(
prob::AbstractNonlinearProblem, alg::BroydenLowRankInitialization{T},
solver, f::F, fu, u, p; maxiters = 1000,
internalnorm::IN = DEFAULT_NORM, kwargs...) where {T, F, IN}
internalnorm::IN = L2_NORM, kwargs...) where {T, F, IN}
if u isa Number # Use the standard broyden
return __internal_init(prob, IdentityInitialization(true, FullStructure()),
solver, f, fu, u, p; maxiters, kwargs...)
Expand Down
2 changes: 1 addition & 1 deletion src/algorithms/levenberg_marquardt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ end
function __internal_init(
prob::AbstractNonlinearProblem, f::LevenbergMarquardtDampingFunction,
initial_damping, J, fu, u, ::Val{NF};
internalnorm::F = DEFAULT_NORM, kwargs...) where {F, NF}
internalnorm::F = L2_NORM, kwargs...) where {F, NF}
T = promote_type(eltype(u), eltype(fu))
DᵀD = __init_diagonal(u, T(f.min_damping))
if NF
Expand Down
2 changes: 1 addition & 1 deletion src/algorithms/pseudo_transient.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ end

function __internal_init(
prob::AbstractNonlinearProblem, f::SwitchedEvolutionRelaxation, initial_damping,
J, fu, u, args...; internalnorm::F = DEFAULT_NORM, kwargs...) where {F}
J, fu, u, args...; internalnorm::F = L2_NORM, kwargs...) where {F}
T = promote_type(eltype(u), eltype(fu))
return SwitchedEvolutionRelaxationCache(
internalnorm(fu), T(1 / initial_damping), internalnorm)
Expand Down
6 changes: 3 additions & 3 deletions src/core/approximate_jacobian.jl
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ function SciMLBase.__init(
args...; stats = empty_nlstats(), alias_u0 = false, maxtime = nothing,
maxiters = 1000, abstol = nothing, reltol = nothing,
linsolve_kwargs = (;), termination_condition = nothing,
internalnorm::F = DEFAULT_NORM, kwargs...) where {uType, iip, F}
internalnorm::F = L2_NORM, kwargs...) where {uType, iip, F}
timer = get_timer_output()
@static_timeit timer "cache construction" begin
(; f, u0, p) = prob
Expand All @@ -162,8 +162,8 @@ function SciMLBase.__init(
initialization_cache = __internal_init(prob, alg.initialization, alg, f, fu, u, p;
stats, linsolve, maxiters, internalnorm)

abstol, reltol, termination_cache = init_termination_cache(
prob, abstol, reltol, fu, u, termination_condition)
abstol, reltol, termination_cache = NonlinearSolveBase.init_termination_cache(
prob, abstol, reltol, fu, u, termination_condition, Val(:regular))
linsolve_kwargs = merge((; abstol, reltol), linsolve_kwargs)

J = initialization_cache(nothing)
Expand Down
6 changes: 3 additions & 3 deletions src/core/generalized_first_order.jl
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ function SciMLBase.__init(
prob::AbstractNonlinearProblem{uType, iip}, alg::GeneralizedFirstOrderAlgorithm,
args...; stats = empty_nlstats(), alias_u0 = false, maxiters = 1000,
abstol = nothing, reltol = nothing, maxtime = nothing,
termination_condition = nothing, internalnorm = DEFAULT_NORM,
termination_condition = nothing, internalnorm = L2_NORM,
linsolve_kwargs = (;), kwargs...) where {uType, iip}
timer = get_timer_output()
@static_timeit timer "cache construction" begin
Expand All @@ -161,8 +161,8 @@ function SciMLBase.__init(

linsolve = get_linear_solver(alg.descent)

abstol, reltol, termination_cache = init_termination_cache(
prob, abstol, reltol, fu, u, termination_condition)
abstol, reltol, termination_cache = NonlinearSolveBase.init_termination_cache(
prob, abstol, reltol, fu, u, termination_condition, Val(:regular))
linsolve_kwargs = merge((; abstol, reltol), linsolve_kwargs)

jac_cache = JacobianCache(
Expand Down
4 changes: 2 additions & 2 deletions src/core/spectral_methods.jl
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ function SciMLBase.__init(prob::AbstractNonlinearProblem, alg::GeneralizedDFSane

linesearch_cache = init(prob, alg.linesearch, fu, u; stats, kwargs...)

abstol, reltol, tc_cache = init_termination_cache(
prob, abstol, reltol, fu, u_cache, termination_condition)
abstol, reltol, tc_cache = NonlinearSolveBase.init_termination_cache(
prob, abstol, reltol, fu, u_cache, termination_condition, Val(:regular))
trace = init_nonlinearsolve_trace(prob, alg, u, fu, nothing, du; kwargs...)

if alg.σ_1 === nothing
Expand Down
Loading

0 comments on commit 0b91de7

Please sign in to comment.