Equilibration algorithm

The equilibration algorithm scales a matrix so that its rows and columns have an infinite norm of 1.

using LinearAlgebra, SparseArrays
using OperatorScaling
T = Float64
ϵ = 1.0e-4 # tolerance
m, n = 7, 5
A = sprand(T, m, n, 0.6)
A_scaled, D1, D2 = equilibrate(A, ϵ = ϵ)
norm(D1 * A * D2 - A_scaled) ≤ sqrt(eps(T)) * norm(A)
true

Display of the input matrix A:

A
7×5 SparseArrays.SparseMatrixCSC{Float64, Int64} with 24 stored entries:
  ⋅         ⋅        0.191601  0.41821   0.359767
 0.222009  0.467676   ⋅        0.167912  0.347202
 0.549691  0.909353  0.803885   ⋅        0.772499
  ⋅         ⋅        0.828975  0.987188   ⋅ 
  ⋅        0.828249  0.29727   0.81902   0.507742
 0.860259   ⋅        0.5879     ⋅        0.361506
 0.885582   ⋅        0.466837  0.135045  0.390669

Display of the scaled matrix A_scaled:

A_scaled
7×5 SparseArrays.SparseMatrixCSC{Float64, Int64} with 24 stored entries:
  ⋅         ⋅        0.512453  0.949043  1.0
 0.480996  0.999919   ⋅        0.344561  0.87268
 0.612546  1.0       0.999981   ⋅        0.998663
  ⋅         ⋅        0.989705  1.0        ⋅ 
  ⋅        0.999989  0.40599   0.949062  0.720661
 0.999996   ⋅        0.762871   ⋅        0.487514
 1.0        ⋅        0.588458  0.144432  0.511779

The in-place version uses storage diagonal matrices, and updates A, D1 and D2 in-place.

D1, R_k = Diagonal(Vector{T}(undef, m)), Diagonal(Vector{T}(undef, m))
D2, C_k = Diagonal(Vector{T}(undef, n)), Diagonal(Vector{T}(undef, n))
A_scaled2 = copy(A)
equilibrate!(A_scaled2, D1, D2, R_k, C_k, ϵ = ϵ)
# A_scaled2, D1 and D2 are now updated
norm(D1 * A * D2 - A_scaled2) ≤ sqrt(eps(T)) * norm(A)
true

This packages also features an implementation for symmetric matrices:

A = sprand(Float64, m, m, 0.3)
Q = Symmetric(tril(A + A'), :L)
Q_scaled, D = equilibrate(Q, ϵ = ϵ)
norm(D * Q * D - Q_scaled) ≤ sqrt(eps(T)) * norm(Q)
true

Display of the input matrix Q:

Q
7×7 LinearAlgebra.Symmetric{Float64, SparseArrays.SparseMatrixCSC{Float64, Int64}}:
 0.0       0.0       0.0       0.109324   0.7919     0.0        0.0
 0.0       1.01896   1.23837   0.723549   0.0        0.0        1.15952
 0.0       1.23837   1.22586   0.0        0.289815   0.0        0.0
 0.109324  0.723549  0.0       0.0        0.0        0.0        0.0775407
 0.7919    0.0       0.289815  0.0        0.0        0.0989077  0.0
 0.0       0.0       0.0       0.0        0.0989077  0.0        0.0
 0.0       1.15952   0.0       0.0775407  0.0        0.0        0.126391

Display of the scaled matrix Q_scaled:

Q_scaled
7×7 LinearAlgebra.Symmetric{Float64, SparseArrays.SparseMatrixCSC{Float64, Int64}}:
 0.0       0.0       0.0       0.188943  1.0       0.0       0.0
 0.0       0.822822  1.0       0.999984  0.0       0.0       0.999998
 0.0       1.0       0.989899  0.0       0.292658  0.0       0.0
 0.188943  0.999984  0.0       0.0       0.0       0.0       0.114452
 1.0       0.0       0.292658  0.0       0.0       0.999937  0.0
 0.0       0.0       0.0       0.0       0.999937  0.0       0.0
 0.0       0.999998  0.0       0.114452  0.0       0.0       0.116414
Q_scaled2 = copy(Q)
# D diagonal matrix and storage diagonal matrix (same size as Q)
D, C_k = Diagonal(Vector{T}(undef, m)), Diagonal(Vector{T}(undef, m))
equilibrate!(Q_scaled2, D, C_k, ϵ = ϵ)
norm(D * Q * D - Q_scaled2) ≤ sqrt(eps(T)) * norm(Q)
true