@@ -87,7 +87,7 @@ Construct the half-infinite projector algorithm based on the following keyword a
8787 - `:notrunc` : No singular values are truncated and the performed SVDs are exact
8888 - `:truncerr` : Additionally supply error threshold `η`; truncate to the maximal virtual dimension of `η`
8989 - `:truncdim` : Additionally supply truncation dimension `η`; truncate such that the 2-norm of the truncated values is smaller than `η`
90- - `:truncspace` : Additionally supply truncation space `η`; truncate according to the supplied vector space
90+ - `:truncspace` : Additionally supply truncation space `η`; truncate according to the supplied vector space
9191 - `:truncbelow` : Additionally supply singular value cutoff `η`; truncate such that every retained singular value is larger than `η`
9292* `verbosity::Int=$(Defaults. projector_verbosity) ` : Projector output verbosity which can be:
9393 0. Suppress output information
@@ -125,7 +125,7 @@ Construct the full-infinite projector algorithm based on the following keyword a
125125 - `:notrunc` : No singular values are truncated and the performed SVDs are exact
126126 - `:truncerr` : Additionally supply error threshold `η`; truncate to the maximal virtual dimension of `η`
127127 - `:truncdim` : Additionally supply truncation dimension `η`; truncate such that the 2-norm of the truncated values is smaller than `η`
128- - `:truncspace` : Additionally supply truncation space `η`; truncate according to the supplied vector space
128+ - `:truncspace` : Additionally supply truncation space `η`; truncate according to the supplied vector space
129129 - `:truncbelow` : Additionally supply singular value cutoff `η`; truncate such that every retained singular value is larger than `η`
130130* `verbosity::Int=$(Defaults. projector_verbosity) ` : Projector output verbosity which can be:
131131 0. Suppress output information
@@ -148,7 +148,7 @@ PROJECTOR_SYMBOLS[:fullinfinite] = FullInfiniteProjector
148148Determine left and right projectors at the bond given determined by the enlarged corners
149149and the given coordinate using the specified `alg`.
150150"""
151- function compute_projector(enlarged_corners, coordinate, alg:: HalfInfiniteProjector )
151+ function compute_projector(enlarged_corners, coordinate, last_space, alg:: HalfInfiniteProjector )
152152 # SVD half-infinite environment
153153 halfinf = half_infinite_environment(enlarged_corners... )
154154 svd_alg = svd_algorithm(alg, coordinate)
@@ -166,7 +166,7 @@ function compute_projector(enlarged_corners, coordinate, alg::HalfInfiniteProjec
166166 P_left, P_right = contract_projectors(U, S, V, enlarged_corners... )
167167 return (P_left, P_right), (; U, S, V, info... )
168168end
169- function compute_projector(enlarged_corners, coordinate, alg:: FullInfiniteProjector )
169+ function compute_projector(enlarged_corners, coordinate, last_space, alg:: FullInfiniteProjector )
170170 halfinf_left = half_infinite_environment(enlarged_corners[1 ], enlarged_corners[2 ])
171171 halfinf_right = half_infinite_environment(enlarged_corners[3 ], enlarged_corners[4 ])
172172
@@ -187,3 +187,121 @@ function compute_projector(enlarged_corners, coordinate, alg::FullInfiniteProjec
187187 P_left, P_right = contract_projectors(U, S, V, halfinf_left, halfinf_right)
188188 return (P_left, P_right), (; U, S, V, info... )
189189end
190+
191+ # ==========================================================================================
192+ # TBD: compute ncv vectors proj.ncv_ratio * old_nvectors?
193+ struct RandomizedProjector{S, T, R} <: ProjectorAlgorithm
194+ svd_alg:: S
195+ trscheme:: T
196+ rng:: R
197+ oversampling:: Int64
198+ max_full:: Int64
199+ verbosity:: Int
200+ end
201+
202+ PROJECTOR_SYMBOLS[:randomized] = RandomizedProjector
203+
204+ svd_algorithm(alg:: RandomizedProjector ) = alg. svd_alg
205+
206+ #=
207+ # TBD is this needed?
208+ function RandomizedProjector(;
209+ rng = Random.default_rng(),
210+ svd_alg = (;),
211+ trscheme = (;),
212+ oversampling = 10,
213+ max_full = 100,
214+ verbosity = Defaults.projector_verbosity,
215+ )
216+
217+ # parse SVD forward & rrule algorithm
218+ svd_algorithm = _alg_or_nt(SVDAdjoint, svd_alg)
219+
220+ # parse truncation scheme
221+ truncation_scheme = if trscheme isa TruncationScheme
222+ trscheme
223+ elseif trscheme isa NamedTuple
224+ _TruncationScheme(; trscheme...)
225+ else
226+ throw(ArgumentError("unknown trscheme $trscheme"))
227+ end
228+
229+ return RandomizedProjector(
230+ svd_algorithm, truncation_scheme, rng, oversampling, max_full, verbosity
231+ )
232+ end
233+ =#
234+
235+
236+ # needed as default interface in PEPSKit.ProjectorAlgorithm
237+ function RandomizedProjector(svd_algorithm, trscheme, verbosity)
238+ @show " Hi RandomizedProjector"
239+ @show which(
240+ RandomizedProjector, typeof.(
241+ (
242+ svd_algorithm, trscheme, Random. default_rng(), 10 , 100 , verbosity,
243+ )
244+ )
245+ )
246+ return RandomizedProjector(
247+ svd_algorithm, trscheme, Random. default_rng(), 10 , 100 , verbosity
248+ )
249+ end
250+
251+ function random_domain(alg:: RandomizedProjector , full_space, last_space)
252+ sector_dims = map(sectors(full_space)) do s
253+ if dim(full_space, s) <= alg. max_full
254+ n = dim(full_space, s)
255+ else
256+ n = dim(last_space, s) + alg. oversampling
257+ end
258+ return s => n
259+ end
260+ return Vect[sectortype(last_space)](sector_dims)
261+ end
262+
263+
264+ function randomized_range_finder(A:: AbstractTensorMap , alg:: RandomizedProjector , randomized_space)
265+ Q = TensorMap{eltype(A)}(undef, domain(A) ← randomized_space)
266+ foreach(blocks(Q)) do (s, b)
267+ m, n = size(b)
268+ if m <= alg. max_full
269+ b .= LinearAlgebra. I(m)
270+ else
271+ Ω = randn(alg. rng, eltype(A), domain(A) ← Vect[sectortype(A)](s => n))
272+ Y = A * Ω
273+ Qs, _ = leftorth!(Y)
274+ b .= block(Qs, s)
275+ end
276+ end
277+ return Q
278+ end
279+
280+ # impose full env, could also be defined for half_infinite_environment, little gain
281+ function compute_projector(fq, coordinate, last_space, alg:: RandomizedProjector )
282+ full_space = fuse(domain(fq))
283+ randomized_space = random_domain(alg, full_space, last_space)
284+ Q = randomized_range_finder(fq, alg, randomized_space)
285+ B = Q' * fq
286+
287+ svd_alg = svd_algorithm(alg, coordinate)
288+ U′, S, V, info = tsvd!(B, svd_alg; trunc = alg.trscheme)
289+ U = Q * U′
290+ foreach(blocks(S)) do (s, b)
291+ if size(b, 1) == dim(randomized_space, s) && size(b, 1) < dim(full_space, s)
292+ @warn("Sector is too small, kept all computed values: ", s)
293+ end
294+ end
295+
296+ # Check for degenerate singular values; still needed for exact blocks
297+ Zygote.isderiving() && ignore_derivatives() do
298+ if alg.verbosity > 0 && is_degenerate_spectrum(S)
299+ svals = TensorKit.SectorDict(c => diag(b) for (c, b) in blocks(S))
300+ @warn("degenerate singular values detected: ", svals)
301+ end
302+ end
303+
304+ @reset info.truncation_error = info.truncation_error / norm(S) # normalize truncation error
305+ P_left, P_right = contract_projectors(U, S, V, fq)
306+ return (P_left, P_right), (; U, S, V, info...)
307+ end
0 commit comments