|
1 | 1 | using .BaseExtensions: maybe_real |
2 | 2 | using Graphs: has_edge |
| 3 | +using ITensors.NDTensors: scalartype |
3 | 4 | using ITensors: ITensors, ITensor, Index, Ops, apply, commonind, commoninds, contract, dag, |
4 | 5 | denseblocks, factorize, factorize_svd, hasqns, isdiag, noncommoninds, noprime, prime, |
5 | | - replaceind, replaceinds, unioninds, uniqueinds |
| 6 | + replaceind, replaceinds, tags, unioninds, uniqueinds |
6 | 7 | using KrylovKit: linsolve |
7 | 8 | using LinearAlgebra: eigen, norm, qr, svd |
8 | 9 | using NamedGraphs: NamedEdge, has_edge |
@@ -304,80 +305,6 @@ function _contract_gate(o::AbstractEdge, ψv1, Λ, ψv2) |
304 | 305 | return Qᵥ₁, Rᵥ₁, Qᵥ₂, Rᵥ₂, theta |
305 | 306 | end |
306 | 307 |
|
307 | | -# In the future we will try to unify this into apply() above but currently leave it mostly as a separate function |
308 | | -# Apply() function for an ITN in the Vidal Gauge. Hence the bond tensors are required. |
309 | | -# Gate does not necessarily need to be passed. Can supply an edge to do an identity update instead. Uses Simple Update procedure assuming gate is two-site |
310 | | -function ITensors.apply( |
311 | | - o::Union{NamedEdge, ITensor}, ψ::VidalITensorNetwork; normalize = false, apply_kwargs... |
312 | | - ) |
313 | | - updated_ψ = copy(site_tensors(ψ)) |
314 | | - updated_bond_tensors = copy(bond_tensors(ψ)) |
315 | | - v⃗ = _gate_vertices(o, ψ) |
316 | | - if length(v⃗) == 2 |
317 | | - e = NamedEdge(v⃗[1] => v⃗[2]) |
318 | | - ψv1, ψv2 = ψ[src(e)], ψ[dst(e)] |
319 | | - e_ind = commonind(ψv1, ψv2) |
320 | | - |
321 | | - for vn in neighbors(ψ, src(e)) |
322 | | - if (vn != dst(e)) |
323 | | - ψv1 = noprime(ψv1 * bond_tensor(ψ, vn => src(e))) |
324 | | - end |
325 | | - end |
326 | | - |
327 | | - for vn in neighbors(ψ, dst(e)) |
328 | | - if (vn != src(e)) |
329 | | - ψv2 = noprime(ψv2 * bond_tensor(ψ, vn => dst(e))) |
330 | | - end |
331 | | - end |
332 | | - |
333 | | - Qᵥ₁, Rᵥ₁, Qᵥ₂, Rᵥ₂, theta = _contract_gate(o, ψv1, bond_tensor(ψ, e), ψv2) |
334 | | - |
335 | | - U, S, V = ITensors.svd( |
336 | | - theta, |
337 | | - uniqueinds(Rᵥ₁, Rᵥ₂); |
338 | | - lefttags = ITensorNetworks.edge_tag(e), |
339 | | - righttags = ITensorNetworks.edge_tag(e), |
340 | | - apply_kwargs... |
341 | | - ) |
342 | | - |
343 | | - ind_to_replace = commonind(V, S) |
344 | | - ind_to_replace_with = commonind(U, S) |
345 | | - S = replaceind(S, ind_to_replace => ind_to_replace_with') |
346 | | - V = replaceind(V, ind_to_replace => ind_to_replace_with) |
347 | | - |
348 | | - ψv1, updated_bond_tensors[e], ψv2 = U * Qᵥ₁, S, V * Qᵥ₂ |
349 | | - |
350 | | - for vn in neighbors(ψ, src(e)) |
351 | | - if (vn != dst(e)) |
352 | | - ψv1 = |
353 | | - noprime(ψv1 * ITensorsExtensions.inv_diag(bond_tensor(ψ, vn => src(e)))) |
354 | | - end |
355 | | - end |
356 | | - |
357 | | - for vn in neighbors(ψ, dst(e)) |
358 | | - if (vn != src(e)) |
359 | | - ψv2 = |
360 | | - noprime(ψv2 * ITensorsExtensions.inv_diag(bond_tensor(ψ, vn => dst(e)))) |
361 | | - end |
362 | | - end |
363 | | - |
364 | | - if normalize |
365 | | - ψv1 /= norm(ψv1) |
366 | | - ψv2 /= norm(ψv2) |
367 | | - updated_bond_tensors[e] /= norm(updated_bond_tensors[e]) |
368 | | - end |
369 | | - |
370 | | - setindex_preserve_graph!(updated_ψ, ψv1, src(e)) |
371 | | - setindex_preserve_graph!(updated_ψ, ψv2, dst(e)) |
372 | | - |
373 | | - return VidalITensorNetwork(updated_ψ, updated_bond_tensors) |
374 | | - |
375 | | - else |
376 | | - updated_ψ = apply(o, updated_ψ; normalize) |
377 | | - return VidalITensorNetwork(updated_ψ, updated_bond_tensors) |
378 | | - end |
379 | | -end |
380 | | - |
381 | 308 | ### Full Update Routines ### |
382 | 309 |
|
383 | 310 | # Calculate the overlap of the gate acting on the previous p and q versus the new p and q in the presence of environments. This is the cost function that optimise_p_q will minimise |
|
0 commit comments