Skip to content

Commit dccf5d3

Browse files
circuit now properly does single sweep in circuit TDVP
1 parent 952d4b9 commit dccf5d3

File tree

1 file changed

+60
-16
lines changed

1 file changed

+60
-16
lines changed

src/yaqs/core/methods/TDVP.py

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -476,9 +476,10 @@ def single_site_TDVP(state: MPS, H: MPO, sim_params, numiter_lanczos: int=25):
476476
state.tensors[i - 1] = update_site(left_blocks[i - 1], right_blocks[i - 1], H.tensors[i - 1], state.tensors[i - 1], 0.5*sim_params.dt, numiter_lanczos)
477477

478478

479-
def two_site_TDVP(state: MPS, H: MPO, sim_params, numiter_lanczos: int=25):
480-
"""
481-
Perform symmetric two-site TDVP integration.
479+
def two_site_TDVP(
480+
state: MPS, H: MPO, sim_params: PhysicsSimParams | StrongSimParams | WeakSimParams, numiter_lanczos: int = 25
481+
) -> None:
482+
"""Perform symmetric two-site TDVP integration.
482483
483484
This function evolves the MPS by updating two neighboring sites simultaneously.
484485
The evolution includes merging the two site tensors, applying the local Hamiltonian,
@@ -499,11 +500,15 @@ def two_site_TDVP(state: MPS, H: MPO, sim_params, numiter_lanczos: int=25):
499500
"Unifying time evolution and optimization with matrix product states",
500501
Phys. Rev. B 94, 165116 (2016) (arXiv:1408.5056)
501502
"""
503+
from ..data_structures.simulation_parameters import StrongSimParams, WeakSimParams
504+
502505
num_sites = H.length
503506
if num_sites != state.length:
504-
raise ValueError("State and Hamiltonian must have the same number of sites")
507+
msg = "State and Hamiltonian must have the same number of sites"
508+
raise ValueError(msg)
505509
if num_sites < 2:
506-
raise ValueError("Hamiltonian is too short for a two-site update (2TDVP).")
510+
msg = "Hamiltonian is too short for a two-site update (2TDVP)."
511+
raise ValueError(msg)
507512

508513
# Compute the right operator blocks.
509514
right_blocks = initialize_right_environments(state, H)
@@ -518,8 +523,9 @@ def two_site_TDVP(state: MPS, H: MPO, sim_params, numiter_lanczos: int=25):
518523
left_identity[i, a, i] = 1
519524
left_blocks[0] = left_identity
520525

526+
# Adjust simulation time step if simulation parameters require a unit time step.
521527
if isinstance(sim_params, (WeakSimParams, StrongSimParams)):
522-
sim_params.dt = 1
528+
sim_params.dt = 2
523529

524530
# Left-to-right sweep for sites 0 to L-2.
525531
for i in range(num_sites - 2):
@@ -528,35 +534,73 @@ def two_site_TDVP(state: MPS, H: MPO, sim_params, numiter_lanczos: int=25):
528534
# Similarly, merge the corresponding MPO tensors.
529535
merged_mpo = merge_mpo_tensors(H.tensors[i], H.tensors[i + 1])
530536
# Evolve the merged tensor forward by half a time step.
531-
merged_tensor = update_site(left_blocks[i], right_blocks[i + 1], merged_mpo, merged_tensor, 0.5*sim_params.dt, numiter_lanczos)
537+
merged_tensor = update_site(
538+
left_blocks[i], right_blocks[i + 1], merged_mpo, merged_tensor, 0.5 * sim_params.dt, numiter_lanczos
539+
)
532540
# Split the merged tensor back into two tensors.
533-
state.tensors[i], state.tensors[i + 1] = split_mps_tensor( merged_tensor, 'right', threshold=sim_params.threshold)
541+
state.tensors[i], state.tensors[i + 1] = split_mps_tensor(
542+
merged_tensor, "right", threshold=sim_params.threshold
543+
)
534544
# Update the left operator block for site i+1.
535545
left_blocks[i + 1] = update_left_environment(state.tensors[i], state.tensors[i], H.tensors[i], left_blocks[i])
536546
# Evolve the tensor at site i+1 backward by half a time step.
537-
state.tensors[i + 1] = update_site(left_blocks[i + 1], right_blocks[i + 1], H.tensors[i + 1], state.tensors[i + 1], -0.5*sim_params.dt, numiter_lanczos)
547+
state.tensors[i + 1] = update_site(
548+
left_blocks[i + 1],
549+
right_blocks[i + 1],
550+
H.tensors[i + 1],
551+
state.tensors[i + 1],
552+
-0.5 * sim_params.dt,
553+
numiter_lanczos,
554+
)
555+
556+
# Guarantees unit time at final site for circuits
557+
if isinstance(sim_params, (WeakSimParams, StrongSimParams)):
558+
sim_params.dt = 1
538559

539560
# Process the rightmost pair (sites L-2 and L-1)
540561
i = num_sites - 2
541562
merged_tensor = merge_mps_tensors(state.tensors[i], state.tensors[i + 1])
542563
merged_mpo = merge_mpo_tensors(H.tensors[i], H.tensors[i + 1])
543564
# Evolve the merged tensor forward by a full time step.
544-
merged_tensor = update_site(left_blocks[i], right_blocks[i + 1], merged_mpo, merged_tensor, sim_params.dt, numiter_lanczos)
565+
merged_tensor = update_site(
566+
left_blocks[i], right_blocks[i + 1], merged_mpo, merged_tensor, sim_params.dt, numiter_lanczos
567+
)
568+
# Only a single sweep is needed for circuits
569+
if isinstance(sim_params, (WeakSimParams, StrongSimParams)):
570+
state.tensors[i], state.tensors[i + 1] = split_mps_tensor(merged_tensor, "right", threshold=sim_params.threshold)
571+
return
572+
545573
# Split the merged tensor using a 'left' distribution of singular values.
546-
state.tensors[i], state.tensors[i + 1] = split_mps_tensor(merged_tensor, 'left', threshold=sim_params.threshold)
574+
state.tensors[i], state.tensors[i + 1] = split_mps_tensor(merged_tensor, "left", threshold=sim_params.threshold)
575+
547576
# Update the right operator block for site i.
548-
right_blocks[i] = update_right_environment(state.tensors[i + 1], state.tensors[i + 1], H.tensors[i + 1], right_blocks[i + 1])
577+
right_blocks[i] = update_right_environment(
578+
state.tensors[i + 1], state.tensors[i + 1], H.tensors[i + 1], right_blocks[i + 1]
579+
)
580+
581+
549582

550583
# Right-to-left sweep.
551584
for i in reversed(range(num_sites - 2)):
552585
# Evolve the tensor at site i+1 backward by half a time step.
553-
state.tensors[i + 1] = update_site(left_blocks[i + 1], right_blocks[i + 1], H.tensors[i + 1], state.tensors[i + 1], -0.5*sim_params.dt, numiter_lanczos)
586+
state.tensors[i + 1] = update_site(
587+
left_blocks[i + 1],
588+
right_blocks[i + 1],
589+
H.tensors[i + 1],
590+
state.tensors[i + 1],
591+
-0.5 * sim_params.dt,
592+
numiter_lanczos,
593+
)
554594
# Merge the tensors at sites i and i+1.
555595
merged_tensor = merge_mps_tensors(state.tensors[i], state.tensors[i + 1])
556596
merged_mpo = merge_mpo_tensors(H.tensors[i], H.tensors[i + 1])
557597
# Evolve the merged tensor forward by half a time step.
558-
merged_tensor = update_site(left_blocks[i], right_blocks[i + 1], merged_mpo, merged_tensor, 0.5 * sim_params.dt, numiter_lanczos)
598+
merged_tensor = update_site(
599+
left_blocks[i], right_blocks[i + 1], merged_mpo, merged_tensor, 0.5 * sim_params.dt, numiter_lanczos
600+
)
559601
# Split the merged tensor using a 'left' distribution.
560-
state.tensors[i], state.tensors[i + 1] = split_mps_tensor(merged_tensor, 'left', threshold=sim_params.threshold)
602+
state.tensors[i], state.tensors[i + 1] = split_mps_tensor(merged_tensor, "left", threshold=sim_params.threshold)
561603
# Update the right operator block.
562-
right_blocks[i] = update_right_environment(state.tensors[i + 1], state.tensors[i + 1], H.tensors[i + 1], right_blocks[i + 1])
604+
right_blocks[i] = update_right_environment(
605+
state.tensors[i + 1], state.tensors[i + 1], H.tensors[i + 1], right_blocks[i + 1]
606+
)

0 commit comments

Comments
 (0)