Skip to content

Commit 4844a20

Browse files
authored
Add pivot tolerance option (#76)
* Add option to set pivot tolerance * Test pivot tolerance option * Bump minor version
1 parent f08e1bb commit 4844a20

3 files changed

Lines changed: 43 additions & 4 deletions

File tree

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "PureKLU"
22
uuid = "0c0d3e7f-3a8b-4f7e-b6f1-9a4d2e7c1f01"
33
authors = ["Chris Rackauckas <accounts@chrisrackauckas.com> and contributors"]
4-
version = "1.3.0"
4+
version = "1.4.0"
55

66
[deps]
77
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

src/PureKLU.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,10 @@ Compute a KLU sparse LU factorization.
515515
- `fully_preallocated = nothing`: select automatic workspace preallocation;
516516
pass `true` or `false` to override it.
517517
- `detect_banded = true`: detect narrow BTF blocks and use natural ordering.
518+
- `tol = 0.001`: Pivot on a column's diagonal instead of largest entry if it is
519+
at least `tol` times larger in magnitude. Set `tol = 1.0` for partial pivoting,
520+
and `tol = 0.0` to always use the diagonal. Only applies to the numeric
521+
factorization; `klu!` reuses the existing pivot ordering.
518522
519523
# Returns
520524
- A `KLUFactorization` that implements `LinearAlgebra.Factorization`.
@@ -536,11 +540,12 @@ function klu(
536540
check::Bool = true, allowsingular::Bool = false,
537541
full_factor::Bool = true, use_fma = true,
538542
fully_preallocated::Union{Bool, Nothing} = nothing,
539-
detect_banded::Bool = true,
543+
detect_banded::Bool = true, tol::Float64 = 0.001,
540544
) where {Ti <: KLUITypes, Tv <: KLUGenericTypes}
541545
K = KLUFactorization(n, colptr, rowval, nzval)
542546
K.common.use_fma = _as_val(use_fma)
543547
K.common.detect_banded = detect_banded
548+
K.common.tol = tol
544549
if fully_preallocated isa Bool
545550
K.common.fully_preallocated = fully_preallocated
546551
return full_factor ? klu_factor!(K; check, allowsingular) : klu_analyze!(K; check)
@@ -554,13 +559,14 @@ function klu(
554559
A::SparseMatrixCSC{Tv, Ti}; check::Bool = true,
555560
allowsingular::Bool = false, full_factor::Bool = true,
556561
use_fma = true, fully_preallocated::Union{Bool, Nothing} = nothing,
557-
detect_banded::Bool = true,
562+
detect_banded::Bool = true, tol::Float64 = 0.001,
558563
) where {Tv <: KLUGenericTypes, Ti <: KLUITypes}
559564
n = size(A, 1)
560565
n == size(A, 2) || throw(DimensionMismatch())
561566
return klu(
562567
n, decrement(A.colptr), decrement(A.rowval), A.nzval;
563-
check, allowsingular, full_factor, use_fma, fully_preallocated, detect_banded
568+
check, allowsingular, full_factor, use_fma, fully_preallocated,
569+
detect_banded, tol
564570
)
565571
end
566572

test/test_tol.jl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Trivial test that the `tol` kwarg (diagonal-vs-partial pivoting threshold)
2+
# is actually honored, not just accepted and ignored.
3+
using Test
4+
using SparseArrays
5+
using LinearAlgebra
6+
using PureKLU
7+
8+
@testset "tol kwarg: stored on common, solves correctly" begin
9+
A = sparse([2.0 1.0; 1.0 3.0])
10+
b = [1.0, 2.0]
11+
for tol in (0.0, 0.001, 0.5, 1.0)
12+
K = PureKLU.klu(A; tol)
13+
@test K.common.tol == tol
14+
@test A * (K \ b) b
15+
end
16+
end
17+
18+
@testset "tol kwarg: extreme values change pivot choice" begin
19+
# Column 1 has a tiny diagonal entry (0.001) and a much larger
20+
# off-diagonal entry (1.0) in row 2. tol = 0.0 always pivots on the
21+
# diagonal; tol = 1.0 is full partial pivoting and must pick the larger
22+
# entry instead, so the two runs choose different row pivots.
23+
A = sparse([0.001 1.0; 1.0 1.0])
24+
b = [1.0, 1.0]
25+
26+
K_diag = PureKLU.klu(A; tol = 0.0, detect_banded = false)
27+
K_partial = PureKLU.klu(A; tol = 1.0, detect_banded = false)
28+
29+
@test K_diag.p == [1, 2] # diagonal pivot kept despite tiny magnitude
30+
@test K_partial.p == [2, 1] # partial pivoting swaps to the larger entry
31+
@test A * (K_diag \ b) b
32+
@test A * (K_partial \ b) b
33+
end

0 commit comments

Comments
 (0)