MatrixPerspective.jl
versioninfo()
Julia Version 1.5.1
Commit 697e782ab8 (2020-08-25 20:08 UTC)
Platform Info:
OS: macOS (x86_64-apple-darwin19.5.0)
CPU: Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-9.0.1 (ORCJIT, skylake)
Timing
The following code compares the three methods, interior point method (by using MOSEK, for $p < 100$), bisection, and semismooth Newton, for finding the unique root of the semismooth function
\[f(\mu) = 1 - \mathbf{e}^T(\bar{\mathbf{X}} - \mu \mathbf{e}\mathbf{e}^T)_{+}\mathbf{e}\]
where $\mathbf{e}=(0, \dotsc, 0, 1)^T$ and
\[\bar{\mathbf{X}} = \begin{bmatrix} -\mathbf{X} & \frac{1}{\sqrt{2}}\mathbf{y} \\ \frac{1}{\sqrt{2}}\mathbf{y}^T & 1 \end{bmatrix}\]
for given input $(\mathbf{X}, \mathbf{y})$. From this root the prox operator
\[\mathrm{prox}_{\phi}(\mathbf{X}, \mathbf{y}), \quad \phi(\boldsymbol{\Omega}, \boldsymbol{\eta}) = \begin{cases} \frac{1}{2}\boldsymbol{\eta}^T\boldsymbol{\Omega}^{\dagger}\boldsymbol{\eta}, & \boldsymbol{\Omega} \succeq \mathbf{0},~\boldsymbol{\eta} \in \mathcal{R}(\boldsymbol{\Omega}) \\ \infty, & \text{otherwise} \end{cases}\]
can be computed in a closed form.
The first table reports the mean of the performance measures, and the second table contains the standard deviation. The $p=5$ case (especially for MOSEK) should be ignored since there is an overhead of JIT compilation of the code.
;cat timing.jl
using MatrixPerspective
using LinearAlgebra
import LinearAlgebra.BLAS.BlasInt
using Random
using DataFrames, Statistics
Random.seed!(1234);
reps = 10 #reps = 100
tol = 1e-8 # default
# KKT measures |g'(mu)|
df = DataFrame(p=Int[], Method=String[], Iters=Float64[], Secs=Float64[], KKT=Float64[], Obj=Float64[])
# MOSEK stalls if p > 30
dims = [5, 10, 30, 50, 100, 500, 1000, 2000]
#dims = [10, 30] #dims = [100] #dims = [1000]
nummethods = 2
Means = zeros(nummethods, length(dims), size(df)[2]);
mosek_maxdim = 100
for i = 1:length(dims)
p = dims[i]
n = p + 2
e = zeros(p + 1) # last elementary unit vector
e[end] = 1
# workspaces
Q = Matrix{Float64}(undef, n, n)
evec = Vector{Float64}(undef, n)
d = Vector{Float64}(undef, n)
indxq = Vector{BlasInt}(undef, n)
z = Vector{Float64}(undef, n)
dlambda = Vector{Float64}(undef, n)
w = Vector{Float64}(undef, n)
Q2 = Vector{Float64}(undef, n * n)
indx = Vector{BlasInt}(undef, n + 1)
indxc = Vector{BlasInt}(undef, n)
indxp = Vector{BlasInt}(undef, n)
coltyp = Vector{BlasInt}(undef, n)
S = Vector{Float64}(undef, n * n )
M = zeros(n - 1, n - 1) # for second derivative
alph = Vector{Bool}(undef, n - 1)
gam = similar(alph)
bet = similar(alph)
println("p = ", p)
for rep=1:reps
X = Matrix(Symmetric(randn(p, p)))
y = randn(p)
while !(minimum(eigvals(X + 0.5 * y * y')) < 0)
X = Diagonal(randn(p))
y = randn(p)
end
G = [X -y/sqrt(2); -y'/sqrt(2) 1]
if p <= mosek_maxdim
secs = @elapsed optval, primal, dual = mosek_ls_cov_adj(Matrix(G))
mu = dual[2].dual
lam2, P2 = eigen(G + mu * e * e')
Lam2 = P2 * Diagonal(max.(lam2, 0)) * P2'
mosek_deriv1 = 1 - Lam2[end, end]
else
(optval, mu) = (NaN, NaN) # if MOSEK stalls
mosek_deriv1 = NaN
secs = NaN
end
push!(df, [p, "MOSEK", NaN, secs, abs(mosek_deriv1), optval])
secs = @elapsed nu, C, convhist = bisect!(Matrix(G), Q, evec, d,
indxq, z, dlambda, w, Q2,
indx, indxc, indxp, coltyp, S,
M, alph, bet, gam; maxiter=50)
# reconstruct the dual optimal value
dualval = -0.5 * norm(C, 2)^2 + nu + 0.5 * norm(G, 2)^2
deriv1 = 1 - C[end, end]
push!(df, [p, "Bisection", convhist.iters, secs, abs(deriv1), dualval])
secs = @elapsed nu, C, convhist = dual_ls_cov_adj!(Matrix(G), Q, evec, d,
indxq, z, dlambda, w, Q2,
indx, indxc, indxp, coltyp, S,
M, alph, bet, gam; maxiter=50)
# reconstruct the dual optimal value
dualval = -0.5 * norm(C, 2)^2 + nu + 0.5 * norm(G, 2)^2
deriv1 = 1 - C[end, end]
push!(df, [p, "Newton", convhist.iters, secs, abs(deriv1), dualval])
end
end
gdf = groupby(df, [:p, :Method])
mdf = combine(gdf, names(gdf)[3:end] .=> mean)
println(mdf)
sdf = combine(gdf, names(gdf)[3:end] .=> std)
println(sdf)
include("timing.jl")
p = 5
p = 10
p = 30
p = 50
┌ Warning: Problem status SLOW_PROGRESS; solution may be inaccurate.
└ @ Convex /Users/jhwon/.julia/packages/Convex/aYxJA/src/solution.jl:252
p = 100
┌ Warning: Problem status SLOW_PROGRESS; solution may be inaccurate.
└ @ Convex /Users/jhwon/.julia/packages/Convex/aYxJA/src/solution.jl:252
┌ Warning: Problem status SLOW_PROGRESS; solution may be inaccurate.
└ @ Convex /Users/jhwon/.julia/packages/Convex/aYxJA/src/solution.jl:252
┌ Warning: Problem status SLOW_PROGRESS; solution may be inaccurate.
└ @ Convex /Users/jhwon/.julia/packages/Convex/aYxJA/src/solution.jl:252
┌ Warning: Problem status SLOW_PROGRESS; solution may be inaccurate.
└ @ Convex /Users/jhwon/.julia/packages/Convex/aYxJA/src/solution.jl:252
┌ Warning: Problem status SLOW_PROGRESS; solution may be inaccurate.
└ @ Convex /Users/jhwon/.julia/packages/Convex/aYxJA/src/solution.jl:252
┌ Warning: Problem status SLOW_PROGRESS; solution may be inaccurate.
└ @ Convex /Users/jhwon/.julia/packages/Convex/aYxJA/src/solution.jl:252
┌ Warning: Problem status SLOW_PROGRESS; solution may be inaccurate.
└ @ Convex /Users/jhwon/.julia/packages/Convex/aYxJA/src/solution.jl:252
p = 500
p = 1000
p = 2000
24×6 DataFrame
│ Row │ p │ Method │ Iters_mean │ Secs_mean │ KKT_mean │ Obj_mean │
│ │ Int64 │ String │ Float64 │ Float64 │ Float64 │ Float64 │
├─────┼───────┼───────────┼────────────┼─────────────┼─────────────┼───────────┤
│ 1 │ 5 │ MOSEK │ NaN │ 2.49323 │ 1.21816e-5 │ 6.53939 │
│ 2 │ 5 │ Bisection │ 28.4 │ 0.157635 │ 5.97528e-9 │ 6.53939 │
│ 3 │ 5 │ Newton │ 4.2 │ 0.0943318 │ 5.58998e-12 │ 6.53939 │
│ 4 │ 10 │ MOSEK │ NaN │ 0.00983312 │ 1.828e-5 │ 27.5118 │
│ 5 │ 10 │ Bisection │ 29.4 │ 0.000295918 │ 4.56144e-9 │ 27.5118 │
│ 6 │ 10 │ Newton │ 4.9 │ 0.000165922 │ 2.34184e-10 │ 27.5118 │
│ 7 │ 30 │ MOSEK │ NaN │ 0.102232 │ 4.92603e-6 │ 225.301 │
│ 8 │ 30 │ Bisection │ 31.8 │ 0.001258 │ 5.44707e-9 │ 225.301 │
│ 9 │ 30 │ Newton │ 5.7 │ 0.000554437 │ 1.18062e-9 │ 225.301 │
│ 10 │ 50 │ MOSEK │ NaN │ 0.657758 │ 7.47059e-6 │ 654.111 │
│ 11 │ 50 │ Bisection │ 33.2 │ 0.00311099 │ 4.26987e-9 │ 654.111 │
│ 12 │ 50 │ Newton │ 5.8 │ 0.00112343 │ 5.79867e-10 │ 654.111 │
│ 13 │ 100 │ MOSEK │ NaN │ 21.2737 │ 6.95149e-6 │ 2496.79 │
│ 14 │ 100 │ Bisection │ 34.5 │ 0.0123491 │ 5.21449e-9 │ 2496.79 │
│ 15 │ 100 │ Newton │ 6.5 │ 0.00433008 │ 2.44491e-9 │ 2496.79 │
│ 16 │ 500 │ MOSEK │ NaN │ NaN │ NaN │ NaN │
│ 17 │ 500 │ Bisection │ 36.9 │ 0.331822 │ 4.0035e-9 │ 62564.1 │
│ 18 │ 500 │ Newton │ 7.9 │ 0.109068 │ 9.81724e-10 │ 62564.1 │
│ 19 │ 1000 │ MOSEK │ NaN │ NaN │ NaN │ NaN │
│ 20 │ 1000 │ Bisection │ 37.8 │ 2.19949 │ 4.43912e-9 │ 2.50248e5 │
│ 21 │ 1000 │ Newton │ 8.0 │ 0.740104 │ 3.05567e-12 │ 2.50248e5 │
│ 22 │ 2000 │ MOSEK │ NaN │ NaN │ NaN │ NaN │
│ 23 │ 2000 │ Bisection │ 39.6 │ 14.6615 │ 5.84813e-9 │ 1.00103e6 │
│ 24 │ 2000 │ Newton │ 8.0 │ 4.32247 │ 2.88162e-9 │ 1.00103e6 │
24×6 DataFrame
│ Row │ p │ Method │ Iters_std │ Secs_std │ KKT_std │ Obj_std │
│ │ Int64 │ String │ Float64 │ Float64 │ Float64 │ Float64 │
├─────┼───────┼───────────┼───────────┼─────────────┼─────────────┼─────────┤
│ 1 │ 5 │ MOSEK │ NaN │ 7.8583 │ 1.28047e-5 │ 3.22705 │
│ 2 │ 5 │ Bisection │ 0.966092 │ 0.498075 │ 3.69496e-9 │ 3.22705 │
│ 3 │ 5 │ Newton │ 0.632456 │ 0.298139 │ 9.18807e-12 │ 3.22705 │
│ 4 │ 10 │ MOSEK │ NaN │ 0.000569673 │ 1.72334e-5 │ 5.87331 │
│ 5 │ 10 │ Bisection │ 1.95505 │ 3.38437e-5 │ 3.18761e-9 │ 5.87331 │
│ 6 │ 10 │ Newton │ 0.316228 │ 4.13268e-5 │ 4.37243e-10 │ 5.87331 │
│ 7 │ 30 │ MOSEK │ NaN │ 0.012398 │ 7.51272e-6 │ 25.0831 │
│ 8 │ 30 │ Bisection │ 1.0328 │ 4.06005e-5 │ 3.51572e-9 │ 25.0831 │
│ 9 │ 30 │ Newton │ 0.483046 │ 2.50481e-5 │ 3.14195e-9 │ 25.0831 │
│ 10 │ 50 │ MOSEK │ NaN │ 0.110312 │ 9.48564e-6 │ 28.42 │
│ 11 │ 50 │ Bisection │ 0.918937 │ 8.7696e-5 │ 2.88447e-9 │ 28.42 │
│ 12 │ 50 │ Newton │ 0.421637 │ 6.49869e-5 │ 1.49951e-9 │ 28.42 │
│ 13 │ 100 │ MOSEK │ NaN │ 4.43358 │ 6.50369e-6 │ 60.6632 │
│ 14 │ 100 │ Bisection │ 0.707107 │ 0.000243857 │ 3.36907e-9 │ 60.6632 │
│ 15 │ 100 │ Newton │ 0.527046 │ 0.000303794 │ 3.5232e-9 │ 60.6632 │
│ 16 │ 500 │ MOSEK │ NaN │ NaN │ NaN │ NaN │
│ 17 │ 500 │ Bisection │ 0.875595 │ 0.00846495 │ 2.54059e-9 │ 436.492 │
│ 18 │ 500 │ Newton │ 0.316228 │ 0.00451969 │ 3.10448e-9 │ 436.492 │
│ 19 │ 1000 │ MOSEK │ NaN │ NaN │ NaN │ NaN │
│ 20 │ 1000 │ Bisection │ 1.61933 │ 0.0865994 │ 3.93659e-9 │ 618.872 │
│ 21 │ 1000 │ Newton │ 0.0 │ 0.0137851 │ 2.3702e-12 │ 618.872 │
│ 22 │ 2000 │ MOSEK │ NaN │ NaN │ NaN │ NaN │
│ 23 │ 2000 │ Bisection │ 0.966092 │ 0.378565 │ 3.164e-9 │ 1197.17 │
│ 24 │ 2000 │ Newton │ 0.0 │ 0.152881 │ 5.28822e-10 │ 1197.17 │
PDHG
The following code illustrates how to use prox_matrixperspective!()
for the PDHG algorithm for Gaussian joint likelihood estimation.
;cat gaussianmle.jl
using MatrixPerspective
using LinearAlgebra
import LinearAlgebra.BLAS.BlasInt
using IterativeSolvers
# Joint MLE of multivariate Gaussian natural parameters
# PDHG code based on http://proximity-operator.net/tutorial.html
function gaussianmle(X::Matrix{T}, cvec::Array{Vector{T},1};
ep::T = 10 / size(X)[2]^2,
init::Matrix{T} = Array{Float64}(undef, 0, 0),
maxiter::Integer = 1000,
opttol::T = 1e-4,
log::Bool = false
) where T <: Float64
n, p = size(X) # sample size, dimension
m = length(cvec)
# workspaces
_n = p + 2
_Q = Matrix{Float64}(undef, _n, _n)
_evec = Vector{Float64}(undef, _n)
_d = Vector{Float64}(undef, _n)
_indxq = Vector{BlasInt}(undef, _n)
_z = Vector{Float64}(undef, _n)
_dlambda = Vector{Float64}(undef, _n)
_w = Vector{Float64}(undef, _n)
_Q2 = Vector{Float64}(undef, _n * _n)
_indx = Vector{BlasInt}(undef, _n + 1)
_indxc = Vector{BlasInt}(undef, _n)
_indxp = Vector{BlasInt}(undef, _n)
_coltyp = Vector{BlasInt}(undef, _n)
_S = Vector{Float64}(undef, _n * _n )
_M = zeros(_n - 1, _n - 1) # for second derivative
_alph = Vector{Bool}(undef, _n - 1)
_gam = similar(_alph)
_bet = similar(_alph)
symmetrize!(A) = begin
for c in 1:size(A, 2)
for r in c:size(A, 1)
A[r, c] += A[c, r]
A[r, c] *= 0.5
A[c, r] = A[r, c]
end
end
A
end
# select the step-sizes
L_f = 0.0 # Lipschitz modulus of $f$
L_K = m # |K'K|_2
tau = 2 / (L_f + 2)
sigma = (1/tau - L_f/2) / L_K
S = X' * X / n # second moment
mu = reshape(sum(X, dims=1) / n, p) # sample mean
# initialize the primal solution
if isempty(init)
#Omega = 1.0 * Matrix(I, p, p) # identity matrix
Omega = Matrix(Symmetric(inv(S - mu * mu' + 1e-2 * I)))
else
Omega = init
end
Omega_old = similar(Omega)
#Omega_old = Omega
#eta = zeros(p)
eta = Omega * mu
#eta_old = similar(eta)
eta_old = similar(eta)
# initialize the dual solution
Y = [copy(Omega) for i=1:m+1]
zeta = copy(eta)
# execute the algorithm
history = ConvergenceHistory(partial = !log)
history[:tol] = opttol
IterativeSolvers.reserve!(T, history, :objval, maxiter)
IterativeSolvers.reserve!(Float64, history, :itertime, maxiter)
IterativeSolvers.nextiter!(history)
for it = 1:maxiter
tic = time()
if it % 100 == 0
println("it = ", it)
end
# primal forward-backward step
copyto!(Omega_old, Omega)
copyto!(eta_old, eta)
## prox opertor of -logdet
M = (Omega - tau * (sum(Y) + S)) ./ ( 1 + ep * tau)
OmD, OmP = eigen!(Symmetric(M))
evals = 0.5 * (OmD + sqrt.(OmD.^2 .+ 4 * tau / (1 + ep * tau)))
fill!(Omega, zero(T))
@inbounds for k=1:length(evals)
@views pvec = OmP[:, k]
BLAS.gemm!('N', 'T', evals[k], pvec, pvec, 1.0, Omega)
end
## eta update
eta -= tau * (zeta - 2 * mu)
# primal adjustment
Omega_tilde = 2 * Omega - Omega_old
eta_tilde = 2 * eta - eta_old
# dual forward-backward step
for i=1:m
#Y_tilde = cvec[i] * cvec[i]' - Y[i] ./ sigma - Omega_tilde
#getPSDpart!(Y_tilde)
#Y[i] = -sigma * Y_tilde
## less allocation using low-level matrix functions
#Y[i] .+= sigma * Omega_tilde
BLAS.axpy!(sigma, Omega_tilde, Y[i])
# Y[i] .= sigma * cvec[i] * cvex[i]' - Y[i]
BLAS.gemm!('N', 'T', sigma, cvec[i], cvec[i], -1.0, Y[i])
# ([Y[i])_+
getPSDpart!(Y[i])
# Y[i] .*= -1.0
rmul!(Y[i], -1.0)
end
# prox operator of $\phi^*$
M = Y[m + 1] + sigma * Omega_tilde
symmetrize!(M)
z = zeta + sigma * eta_tilde
# the following puts *primal* variables to Y[m + 1] and zeta
prox_matrixperspective!( Y[m + 1], zeta,
M, z, 1.0,
_Q, _evec, _d,
_indxq, _z, _dlambda, _w, _Q2,
_indx, _indxc, _indxp, _coltyp, _S,
_M, _alph, _bet, _gam
)
## restore dual variables
# Y[m + 1] .= M - Y[m + 1]
BLAS.axpy!(-1.0, M, Y[m + 1]) # Y[m + 1] .= -M + Y[m + 1]
rmul!(Y[m + 1], -1.0) # Y[m + 1] .*= -1.0
# zeta .= z - zeta
BLAS.axpy!(-1.0, z, zeta) # zeta .= -z + zeta
rmul!(zeta, -1.0) # zeta .*= -1.0
# objective value
D, P = eigen(Symmetric(Omega))
objval = -sum(Base.log.(max.(D, 1e-15))) + tr(Omega * S) - 2 * dot(mu, eta) + (eta' * P) * (pinv(Diagonal(D)) * P' * eta) * 0.5 + 0.5 * ep * sum(abs2.(D))
if it % 100 == 1
println("objval = ", objval)
end
toc = time()
push!(history, :objval, objval)
push!(history, :itertime, toc - tic)
# stopping rule
if norm(vec(Omega - Omega_old)) < opttol * norm(vec(Omega_old)) &&
norm(eta - eta_old) < opttol * norm(eta_old) && it > 10
IterativeSolvers.setconv(history, true)
break
end
IterativeSolvers.nextiter!(history)
end # end for
log && IterativeSolvers.shrink!(history)
eta, Omega, Y, history
end # end of function
Function gaussianmle()
is called as follows.
;cat testgaussianmle.jl
include("gaussianmle.jl")
using Random, LinearAlgebra, SparseArrays
Random.seed!(123)
n, p = 60, 100
# data matrix
pcov = 0.3 * ones(p, p) + 0.7 * I # covariance matrix
pchol = cholesky(pcov)
X = randn(n, p) * pchol.U # correlated predictors
S = X' * X / n # second monent
mu = reshape(sum(X, dims=1) / n , p ) # sample mean
# Variance constraints
# cvec should be scaled so that
# cvec[i]' * (Omega \ cvec[i]) <= 1
cvec = Array{Vector{Float64}, 1}()
m = 5
for i=1:m
e = zeros(p)
e[i] = 1.0
push!(cvec, e)
end
maxit = 5000
@time eta, Omega, Y, history = gaussianmle(X, cvec, maxiter=maxit, opttol=1e-5)
include("testgaussianmle.jl")
objval = 824.1079588444118
it = 100
objval = -68.55345451618902
it = 200
objval = -90.7432608163429
it = 300
objval = -106.47412453177637
it = 400
objval = -119.48174383805825
it = 500
objval = -130.905231884441
it = 600
objval = -141.24124058414466
it = 700
objval = -150.75060287270733
it = 800
objval = -159.58819651238332
it = 900
objval = -167.8548291740341
it = 1000
objval = -175.62112227294827
it = 1100
objval = -182.93963829174476
it = 1200
objval = -189.85149972890522
it = 1300
objval = -196.39020970969847
it = 1400
objval = -202.58396017158287
it = 1500
objval = -208.45708168793593
it = 1600
objval = -214.03098642732363
it = 1700
objval = -219.32480171804784
it = 1800
objval = -224.3558092685453
it = 1900
objval = -229.13975914037536
it = 2000
objval = -233.6911010552277
it = 2100
objval = -238.02315987101295
it = 2200
objval = -242.1482724796969
it = 2300
objval = -246.07789742449864
it = 2400
objval = -249.82270476506264
it = 2500
objval = -253.39265129471005
it = 2600
objval = -256.7970446309472
it = 2700
objval = -260.0445986525942
it = 2800
objval = -263.14348205382316
it = 2900
objval = -266.1013613073703
it = 3000
objval = -268.92543899954114
it = 3100
objval = -271.62248826913253
it = 3200
objval = -274.1988839186122
it = 3300
objval = -276.660630647678
it = 3400
objval = -279.0133887725162
it = 3500
objval = -281.2624977290658
it = 3600
objval = -283.41299760919617
it = 3700
objval = -285.46964894025103
it = 3800
objval = -287.4369508881293
it = 3900
objval = -289.3191580396211
it = 4000
objval = -291.12029589988504
it = 4100
objval = -292.8441752243772
it = 4200
objval = -294.4944052907238
it = 4300
objval = -296.0744062042605
it = 4400
objval = -297.58742032087287
it = 4500
objval = -299.0365228620533
it = 4600
objval = -300.42463178951584
it = 4700
objval = -301.75451700000485
it = 4800
objval = -303.0288088951596
it = 4900
objval = -304.25000637601295
it = 5000
118.756086 seconds (13.64 M allocations: 17.783 GiB, 2.01% gc time)
([-116.11434098621383, 48.95213796995712, 90.65112808590104, 74.88200654160379, -109.65229977959252, -98.84490753993417, -30.09665095952194, 136.9517017393632, -104.99144451079381, -18.399580485564563 … -49.91108946571656, 117.59080136676128, -68.00851618779222, -94.5335199879541, 74.52083217154109, 90.99154106488278, 108.42836157637981, 133.7807753285948, -48.671229175687735, -102.01022091106664], [21.33766714582228 -2.6238047353834855 … 0.6781649941396397 4.81120439765941; -2.6238047353834855 12.248940051450315 … -2.527585193176585 -3.467548444667807; … ; 0.6781649941396397 -2.527585193176585 … 17.906439248985176 3.2836072748514855; 4.81120439765941 -3.467548444667807 … 3.2836072748514855 21.367264541224216], [[-0.14575876261675827 -0.03563277907757659 … -0.03404245270484068 -0.06075941502196815; -0.03563277907757659 -0.008710933888275197 … -0.008322156244423087 -0.014853493357741087; … ; -0.03404245270484068 -0.008322156244423087 … -0.007950730133517705 -0.014190567175007886; -0.06075941502196815 -0.014853493357741087 … -0.014190567175007886 -0.025327509972888063], [-0.008689324794789004 -0.03553955835073861 … -0.006459451495274717 -0.01291964301956979; -0.03553955835073861 -0.14535769321489891 … -0.026419320114234028 -0.05284166696589258; … ; -0.006459451495274717 -0.026419320114234028 … -0.00480181309885309 -0.009604176318880721; -0.01291964301956979 -0.05284166696589258 … -0.009604176318880721 -0.01920945294313533], [-0.0007944588520018045 -0.0017130282012015343 … -0.0008562326215157404 -0.0015634040994131277; -0.0017130282012015343 -0.003693665959813736 … -0.001846226049026201 -0.00337104345356667; … ; -0.0008562326215157404 -0.001846226049026201 … -0.0009228096588016267 -0.0016849678081576932; -0.0015634040994131277 -0.00337104345356667 … -0.0016849678081576932 -0.0030766003448800656], [-0.0 -0.0 … -0.0 -0.0; -0.0 -0.0 … -0.0 -0.0; … ; -0.0 -0.0 … -0.0 -0.0; -0.0 -0.0 … -0.0 -0.0], [-0.03234378615574314 -0.020965129193548145 … -0.011242839572479554 -0.026884814875212406; -0.020965129193548145 -0.013589523501846373 … -0.007287569334164546 -0.017426643080354694; … ; -0.011242839572479554 -0.007287569334164546 … -0.0039080595278443535 -0.00934527760981235; -0.026884814875212406 -0.017426643080354694 … -0.00934527760981235 -0.02234720658224793], [-0.010322316049599323 0.01708816716554684 … 0.00295235387583076 -0.008294524720988461; 0.01708816716554684 -0.028288753771398945 … -0.004887499696737629 0.013731242514756659; … ; 0.00295235387583076 -0.004887499696737629 … -0.0008444222562311587 0.002372371867952583; -0.008294524720988461 0.013731242514756659 … 0.002372371867952583 -0.006665087565281169]], Not converged after 5001 iterations.)