Skip to content

Commit b1d73dc

Browse files
committed
use deterministic RNG initial state
1 parent 6af7d5e commit b1d73dc

File tree

10 files changed

+57
-27
lines changed

10 files changed

+57
-27
lines changed

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "IterativeSolvers"
22
uuid = "42fd0dbc-a981-5370-80f2-aaf504508153"
3-
version = "0.9.1"
3+
version = "0.9.2"
44

55
[deps]
66
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
@@ -11,4 +11,4 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
1111

1212
[compat]
1313
RecipesBase = "0.6, 0.7, 0.8, 1.0"
14-
julia = "1.3"
14+
julia = "1.4"

docs/src/eigenproblems/lobpcg.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ lobpcg!
1313

1414
A `LOBPCGIterator` is created to pre-allocate all the memory required by the method using the constructor `LOBPCGIterator(A, B, largest, X, P, C)` where `A` and `B` are the matrices from the generalized eigenvalue problem, `largest` indicates if the problem is a maximum or minimum eigenvalue problem, `X` is the initial eigenbasis, randomly sampled if not input, where `size(X, 2)` is the block size `bs`. `P` is the preconditioner, `nothing` by default, and `C` is the constraints matrix. The desired `k` eigenvalues are found `bs` at a time.
1515

16+
A deterministic seed is used for generating pseudo-random initial
17+
data for the algorithm; this can be controlled by passing a
18+
different pseudorandom number generator (an [`AbstractRNG`](https://docs.julialang.org/en/v1/stdlib/Random/#Random.AbstractRNG)) via
19+
the `rng` keyword argument.
1620

1721
## References
1822
Implementation is based on [^Knyazev1993] and [^Scipy].

docs/src/linear_systems/bicgstabl.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,16 @@ The method is based on the original article [^Sleijpen1993], but does not implem
1515

1616
The `r` and `u` factors are pre-allocated as matrices of size $n \times (l + 1)$, so that BLAS2 methods can be used. Also the random shadow residual is pre-allocated as a vector. Hence the storage costs are approximately $2l + 3$ vectors.
1717

18+
A deterministic seed is used for generating pseudo-random initial
19+
data for the algorithm; this can be controlled by passing a
20+
different pseudorandom number generator (an [`AbstractRNG`](https://docs.julialang.org/en/v1/stdlib/Random/#Random.AbstractRNG)) via
21+
the `rng` keyword argument.
22+
1823
!!! tip
1924
BiCGStabl(l) can be used as an [iterator](@ref Iterators).
2025

21-
[^Sleijpen1993]:
26+
[^Sleijpen1993]:
2227

23-
Sleijpen, Gerard LG, and Diederik R. Fokkema. "BiCGstab(l) for
24-
linear equations involving unsymmetric matrices with complex spectrum."
28+
Sleijpen, Gerard LG, and Diederik R. Fokkema. "BiCGstab(l) for
29+
linear equations involving unsymmetric matrices with complex spectrum."
2530
Electronic Transactions on Numerical Analysis 1.11 (1993): 2000.

docs/src/linear_systems/idrs.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,9 @@ idrs!
1414
The current implementation is based on the [MATLAB version](http://ta.twi.tudelft.nl/nw/users/gijzen/idrs.m) by Van Gijzen and Sonneveld. For background see [^Sonneveld2008], [^VanGijzen2011] and [the IDR(s) webpage](http://ta.twi.tudelft.nl/nw/users/gijzen/IDR.html).
1515

1616
[^Sonneveld2008]: IDR(s): a family of simple and fast algorithms for solving large nonsymmetric linear systems. P. Sonneveld and M. B. van Gijzen SIAM J. Sci. Comput. Vol. 31, No. 2, pp. 1035--1062, 2008
17-
[^VanGijzen2011]: Algorithm 913: An Elegant IDR(s) Variant that Efficiently Exploits Bi-orthogonality Properties. M. B. van Gijzen and P. Sonneveld ACM Trans. Math. Software,, Vol. 38, No. 1, pp. 5:1-5:19, 2011
17+
[^VanGijzen2011]: Algorithm 913: An Elegant IDR(s) Variant that Efficiently Exploits Bi-orthogonality Properties. M. B. van Gijzen and P. Sonneveld ACM Trans. Math. Software,, Vol. 38, No. 1, pp. 5:1-5:19, 2011
18+
19+
A deterministic seed is used for generating pseudo-random initial
20+
data for the algorithm; this can be controlled by passing a
21+
different pseudorandom number generator (an [`AbstractRNG`](https://docs.julialang.org/en/v1/stdlib/Random/#Random.AbstractRNG)) via
22+
the `rng` keyword argument.

docs/src/svd/svdl.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,10 @@ The implementation of thick restarting follows closely that of SLEPc as describe
1414

1515
The singular vectors are computed directly by forming the Ritz vectors from the product of the Lanczos vectors `L.P`/`L.Q` and the singular vectors of `L.B`. Additional accuracy in the singular triples can be obtained using inverse iteration.
1616

17+
A deterministic seed is used for generating pseudo-random initial
18+
data for the algorithm; this can be controlled by passing a
19+
different pseudorandom number generator (an [`AbstractRNG`](https://docs.julialang.org/en/v1/stdlib/Random/#Random.AbstractRNG)) via
20+
the `rng` keyword argument, or by passing an initial `v0` vector
21+
directly.
22+
1723
[^Hernandez2008]: Vicente Hernández, José E. Román, and Andrés Tomás. "A robust and efficient parallel SVD solver based on restarted Lanczos bidiagonalization." Electronic Transactions on Numerical Analysis 31 (2008): 68-85.

src/bicgstabl.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export bicgstabl, bicgstabl!, bicgstabl_iterator, bicgstabl_iterator!, BiCGStabIterable
2-
using Printf
2+
using Printf, Random
33
import Base: iterate
44

55
mutable struct BiCGStabIterable{precT, matT, solT, vecT <: AbstractVector, smallMatT <: AbstractMatrix, realT <: Real, scalarT <: Number}
@@ -29,13 +29,14 @@ function bicgstabl_iterator!(x, A, b, l::Int = 2;
2929
max_mv_products = size(A, 2),
3030
abstol::Real = zero(real(eltype(b))),
3131
reltol::Real = sqrt(eps(real(eltype(b)))),
32+
rng::AbstractRNG=MersenneTwister(0),
3233
initial_zero = false)
3334
T = eltype(x)
3435
n = size(A, 1)
3536
mv_products = 0
3637

3738
# Large vectors.
38-
r_shadow = rand(T, n)
39+
r_shadow = rand(rng, T, n)
3940
rs = Matrix{T}(undef, n, l + 1)
4041
us = zeros(T, n, l + 1)
4142

@@ -156,6 +157,7 @@ bicgstabl(A, b, l = 2; kwargs...) = bicgstabl!(zerox(A, b), A, b, l; initial_zer
156157
- `max_mv_products::Int = size(A, 2)`: maximum number of matrix vector products.
157158
For BiCGStab(l) this is a less dubious term than "number of iterations";
158159
- `Pl = Identity()`: left preconditioner of the method;
160+
- `rng::AbstractRNG`: generator for pseudorandom initialization
159161
- `abstol::Real = zero(real(eltype(b)))`,
160162
`reltol::Real = sqrt(eps(real(eltype(b))))`: absolute and relative
161163
tolerance for the stopping condition

src/idrs.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ shadow space.
3232
is the residual in the `k`th iteration;
3333
- `maxiter::Int = size(A, 2)`: maximum number of iterations;
3434
- `log::Bool`: keep track of the residual norm in each iteration;
35+
- `rng::AbstractRNG`: generator for pseudorandom initialization
3536
- `verbose::Bool`: print convergence information during the iterations.
3637
3738
# Return values
@@ -80,8 +81,8 @@ end
8081
end
8182

8283
function idrs_method!(log::ConvergenceHistory, X, A, C::T,
83-
s::Number, Pl::precT, abstol::Real, reltol::Real, maxiter::Number; smoothing::Bool=false, verbose::Bool=false
84-
) where {T, precT}
84+
s::Number, Pl::precT, abstol::Real, reltol::Real, maxiter::Number; smoothing::Bool=false, verbose::Bool=false,
85+
rng::AbstractRNG=MersenneTwister(0)) where {T, precT}
8586

8687
verbose && @printf("=== idrs ===\n%4s\t%7s\n","iter","resnorm")
8788
R = C - A*X
@@ -102,7 +103,7 @@ function idrs_method!(log::ConvergenceHistory, X, A, C::T,
102103

103104
Z = zero(C)
104105

105-
P = T[rand!(copy(C)) for k in 1:s]
106+
P = T[rand!(rng, copy(C)) for k in 1:s]
106107
U = T[copy(Z) for k in 1:s]
107108
G = T[copy(Z) for k in 1:s]
108109
Q = copy(Z)

src/lobpcg.jl

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -787,8 +787,8 @@ Finds the `nev` extremal eigenvalues and their corresponding eigenvectors satisf
787787
function lobpcg(A, largest::Bool, nev::Int; kwargs...)
788788
lobpcg(A, nothing, largest, nev; kwargs...)
789789
end
790-
function lobpcg(A, B, largest::Bool, nev::Int; kwargs...)
791-
lobpcg(A, B, largest, rand(eltype(A), size(A, 1), nev); not_zeros=true, kwargs...)
790+
function lobpcg(A, B, largest::Bool, nev::Int; rng::AbstractRNG=MersenneTwister(0), kwargs...)
791+
lobpcg(A, B, largest, rand(rng, eltype(A), size(A, 1), nev); not_zeros=true, rng=rng, kwargs...)
792792
end
793793

794794
"""
@@ -804,6 +804,7 @@ end
804804
## Keywords
805805
806806
- `not_zeros`: default is `false`. If `true`, `X0` will be assumed to not have any all-zeros column.
807+
- `rng::AbstractRNG`: generator for pseudorandom initialization
807808
808809
- `log::Bool`: default is `false`; if `true`, `results.trace` will store iterations
809810
states; if `false` only `results.trace` will be empty;
@@ -826,6 +827,7 @@ function lobpcg(A, largest::Bool, X0; kwargs...)
826827
end
827828
function lobpcg(A, B, largest, X0;
828829
not_zeros=false, log=false, P=nothing, maxiter=200,
830+
rng::AbstractRNG=MersenneTwister(0),
829831
C=nothing, tol::Real=default_tolerance(eltype(X0)))
830832
X = copy(X0)
831833
n = size(X, 1)
@@ -835,7 +837,7 @@ function lobpcg(A, B, largest, X0;
835837

836838
iterator = LOBPCGIterator(A, B, largest, X, P, C)
837839

838-
return lobpcg!(iterator, log=log, tol=tol, maxiter=maxiter, not_zeros=not_zeros)
840+
return lobpcg!(iterator, rng=rng, log=log, tol=tol, maxiter=maxiter, not_zeros=not_zeros)
839841
end
840842

841843
"""
@@ -849,6 +851,7 @@ end
849851
## Keywords
850852
851853
- `not_zeros`: default is `false`. If `true`, the initial Ritz vectors will be assumed to not have any all-zeros column.
854+
- `rng::AbstractRNG`: generator for pseudorandom initialization
852855
853856
- `log::Bool`: default is `false`; if `true`, `results.trace` will store iterations
854857
states; if `false` only `results.trace` will be empty;
@@ -863,21 +866,22 @@ end
863866
864867
"""
865868
function lobpcg!(iterator::LOBPCGIterator; log=false, maxiter=200, not_zeros=false,
869+
rng::AbstractRNG=MersenneTwister(0),
866870
tol::Real=default_tolerance(eltype(iterator.XBlocks.block)))
867871
X = iterator.XBlocks.block
868872
iterator.constr!(iterator.XBlocks.block, iterator.tempXBlocks.block)
869873
if !not_zeros
870874
@views for j in 1:size(X,2)
871875
if all(x -> x==0, X[:, j])
872-
@inbounds X[:,j] .= rand.()
876+
@inbounds X[:,j] .= rand.(rng)
873877
end
874878
end
875879
iterator.constr!(iterator.XBlocks.block, iterator.tempXBlocks.block)
876880
end
877881
n = size(X, 1)
878882
sizeX = size(X, 2)
879883
iterator.iteration[] = 1
880-
while iterator.iteration[] <= maxiter
884+
while iterator.iteration[] <= maxiter
881885
state = iterator(tol, log)
882886
if log
883887
push!(iterator.trace, state)
@@ -927,6 +931,7 @@ function lobpcg(A, largest::Bool, X0, nev::Int; kwargs...)
927931
end
928932
function lobpcg(A, B, largest::Bool, X0, nev::Int;
929933
not_zeros=false, log=false, P=nothing, maxiter=200,
934+
rng::AbstractRNG=MersenneTwister(0),
930935
C=nothing, tol::Real=default_tolerance(eltype(X0)))
931936
n = size(X0, 1)
932937
sizeX = size(X0, 2)
@@ -946,13 +951,13 @@ function lobpcg(A, B, largest::Bool, X0, nev::Int;
946951
cutoff = sizeX-(nev-converged_x)
947952
update!(iterator.constr!, iterator.XBlocks.block[:, 1:cutoff], iterator.XBlocks.B_block[:, 1:cutoff])
948953
X[:, 1:sizeX-cutoff] .= X[:, cutoff+1:sizeX]
949-
rand!(X[:, cutoff+1:sizeX])
954+
rand!(rng, X[:, cutoff+1:sizeX])
950955
rnext = lobpcg!(iterator, log=log, tol=tol, maxiter=maxiter, not_zeros=true)
951956
append!(r, rnext, converged_x, sizeX-cutoff)
952957
converged_x += sizeX-cutoff
953958
else
954959
update!(iterator.constr!, iterator.XBlocks.block, iterator.XBlocks.B_block)
955-
rand!(X)
960+
rand!(rng, X)
956961
rnext = lobpcg!(iterator, log=log, tol=tol, maxiter=maxiter, not_zeros=true)
957962
append!(r, rnext, converged_x)
958963
converged_x += sizeX

src/simple.jl

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,14 @@ function powm_iterable!(A, x; tol = eps(real(eltype(A))) * size(A, 2) ^ 3, maxit
5656
end
5757

5858
"""
59-
powm(B; kwargs...) -> λ, x, [history]
59+
powm(B; rng, kwargs...) -> λ, x, [history]
6060
6161
See [`powm!`](@ref). Calls `powm!(B, x0; kwargs...)` with
62-
`x0` initialized as a random, complex unit vector.
62+
`x0` initialized as a random, complex unit vector using
63+
`rng::AbstractRNG`.
6364
"""
64-
function powm(B; kwargs...)
65-
x0 = rand(Complex{real(eltype(B))}, size(B, 1))
65+
function powm(B; rng::AbstractRNG=MersenneTwister(0), kwargs...)
66+
x0 = rand(rng, Complex{real(eltype(B))}, size(B, 1))
6667
rmul!(x0, one(eltype(B)) / norm(x0))
6768
powm!(B, x0; kwargs...)
6869
end
@@ -149,13 +150,13 @@ function powm!(B, x;
149150
end
150151

151152
"""
152-
invpowm(B; shift = σ, kwargs...) -> λ, x, [history]
153+
invpowm(B; shift = σ, rng, kwargs...) -> λ, x, [history]
153154
154155
Find the approximate eigenpair `(λ, x)` of ``A`` near `shift`, where `B`
155156
is a linear map that has the effect `B * v = inv(A - σI) * v`.
156157
157158
The method calls `powm!(B, x0; inverse = true, shift = σ)` with
158-
`x0` a random, complex unit vector. See [`powm!`](@ref)
159+
`x0` a random, complex unit vector using `rng::AbstractRNG`. See [`powm!`](@ref)
159160
160161
# Examples
161162
@@ -168,8 +169,8 @@ Fmap = LinearMap{ComplexF64}((y, x) -> ldiv!(y, F, x), 50, ismutating = true)
168169
λ, x = invpowm(Fmap, shift = σ, tol = 1e-4, maxiter = 200)
169170
```
170171
"""
171-
function invpowm(B; kwargs...)
172-
x0 = rand(Complex{real(eltype(B))}, size(B, 1))
172+
function invpowm(B; rng::AbstractRNG=MersenneTwister(0), kwargs...)
173+
x0 = rand(rng, Complex{real(eltype(B))}, size(B, 1))
173174
rmul!(x0, one(eltype(B)) / norm(x0))
174175
invpowm!(B, x0; kwargs...)
175176
end

src/svdl.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ If `log` is set to `true` is given, method will output a tuple `X, L, ch`. Where
101101
102102
- `nsv::Int = 6`: number of singular values requested;
103103
- `v0 = random unit vector`: starting guess vector in the domain of `A`.
104+
- `rng::AbstractRNG`: generator for pseudorandom initialization of `v0`
104105
The length of `q` should be the number of columns in `A`;
105106
- `k::Int = 2nsv`: maximum number of Lanczos vectors to compute before restarting;
106107
- `j::Int = nsv`: number of vectors to keep at the end of the restart.
@@ -175,7 +176,7 @@ end
175176
#########################
176177

177178
function svdl_method!(log::ConvergenceHistory, A, l::Int=min(6, size(A,1)); k::Int=2l,
178-
j::Int=l, v0::AbstractVector = Vector{eltype(A)}(randn(size(A, 2))) |> x->rmul!(x, inv(norm(x))),
179+
j::Int=l, rng::AbstractRNG=MersenneTwister(0), v0::AbstractVector = Vector{eltype(A)}(randn(rng, size(A, 2))) |> x->rmul!(x, inv(norm(x))),
179180
maxiter::Int=minimum(size(A)), tol::Real=eps(), reltol::Real=eps(),
180181
verbose::Bool=false, method::Symbol=:ritz, vecs=:none, dolock::Bool=false)
181182

0 commit comments

Comments
 (0)