def get_tensors(self) -> List[ndarray]: """Return the computed tensors. """ assert self._step >= self._num_steps tensors = [] order = [self._mps.bond_edges[0], self._mps.array_edges[0][0]] first_t = self._mps.nodes[0].reorder_edges(order).get_tensor() first_t = add_singleton(first_t, 0) tensors.append(first_t * self._dimension) for i in range(1, len(self._mps.nodes) - 1): order = [ self._mps.bond_edges[i - 1], self._mps.bond_edges[i], self._mps.array_edges[i][0] ] temp_t = self._mps.nodes[i].reorder_edges(order).get_tensor() tensors.append(temp_t * self._dimension) order = [self._mps.bond_edges[-1], self._mps.array_edges[-1][0]] last_t = self._mps.nodes[-1].reorder_edges(order).get_tensor() last_t = add_singleton(last_t, 1) tensors.append(last_t * self._dimension) # apply basis change / transformation if not np.allclose(self._unitary_transform, np.identity(self._unitary_transform.shape[0])): for i, tensor in enumerate(tensors): tmp = create_delta(tensor, [0, 1, 2, 2]) tmp = np.dot(np.moveaxis(tmp, -2, -1), self._super_u_dagg) tmp = np.moveaxis(tmp, -1, -2) tmp = np.dot(tmp, self._super_u.T) tensors[i] = tmp return tensors
def __init__( self, tensors: List[np.ndarray], initial_tensor: np.ndarray, trace: np.ndarray, config: Dict): """Create a TensorNetworkProcessTensorBackend object. """ if "backend" in config: self._backend = config["backend"] else: self._backend = None if len(tensors) > 0 and len(tensors[0].shape) == 3: _tensors = [ create_delta(t, [0, 1, 2, 2]) for t in tensors ] elif len(tensors) > 0 and len(tensors[0].shape) == 4: _tensors = tensors else: _tensors = [] self._tensors = [ tn.Node(t, backend=self._backend) for t in _tensors ] if initial_tensor is not None: self._initial_tensor = tn.Node(initial_tensor, backend=self._backend) else: self._initial_tensor = None self._trace = tn.Node(trace, backend=self._backend) self._caps = None
def initialize(self) -> Tuple[int, ndarray]: """See BaseBackend.initialize() for docstring.""" self._initial_state = copy(self._initial_state).reshape(-1) self._super_u = util.left_right_super( self._unitary_transform, self._unitary_transform.conjugate().T) self._super_u_dagg = util.left_right_super( self._unitary_transform.conjugate().T, self._unitary_transform) self._sum_north_na = na.NodeArray([self._sum_north], left=False, right=False, name="Sum north") influences = [] if self._dkmax is None: dkmax_pre_compute = 1 else: dkmax_pre_compute = self._dkmax for i in range(dkmax_pre_compute): infl = self._influence(i) infl_four_legs = create_delta(infl, [1, 0, 0, 1]) if i == 0: tmp = dot(moveaxis(infl_four_legs, 1, -1), self._super_u_dagg) tmp = moveaxis(tmp, -1, 1) tmp = dot(tmp, self._super_u.T) infl_four_legs = tmp influences.append(infl_four_legs) self._mps = na.NodeArray([self._initial_state], left=False, right=False, name="Thee MPS") self._mpo = na.NodeArray(list(reversed(influences)), left=True, right=True, name="Thee Time Evolving MPO") self._step = 0 self._state = self._initial_state return self._step, copy(self._state)
def initialize(self) -> None: """Initializes the PT-TEMPO tensor network. """ # create mpo # create mpo last # copy and contrac mpo to mps scale = self._dimension self._super_u = util.left_right_super( self._unitary_transform, self._unitary_transform.conjugate().T) self._super_u_dagg = util.left_right_super( self._unitary_transform.conjugate().T, self._unitary_transform) self._sum_north_scaled = self._sum_north * scale influences_mpo = [] influences_mps = [] for i in range(self._num_infl): infl = self._influence(i) if i == 0: infl = infl / scale infl_mpo = create_delta(infl, [1, 1, 0]) infl_mps = infl.T / scale elif i == self._num_infl - 1: infl_mpo = add_singleton(infl, 1) infl_mpo = add_singleton(infl_mpo, 3) infl_mps = add_singleton(infl, 2) else: infl_mpo = create_delta(infl, [0, 1, 1, 0]) infl_mps = create_delta(infl / scale, [0, 1, 0]) influences_mpo.append(infl_mpo) influences_mps.append(infl_mps) self._mpo = na.NodeArray(influences_mpo, left=False, right=True, name="Thee Time Evolving MPO", backend=self._backend) self._mps = na.NodeArray(influences_mps, left=False, right=True, name="Thee MPS", backend=self._backend) self._mps.svd_sweep(from_index=-1, to_index=0, max_singular_values=None, max_truncation_err=self._epsrel, relative=True) self._mps.svd_sweep(from_index=0, to_index=-1, max_singular_values=None, max_truncation_err=self._epsrel, relative=True) one = np.array([[1.0]], dtype=NpDtype) self._one_na = na.NodeArray([one], left=True, right=False, name="The id", backend=self._backend) self._step = 1
def compute_step(self) -> Tuple[int, ndarray]: """ See BaseTempoBackend.compute_step() for docstring. For example, for at step 4, we start with: A ... self._mps B ... self._mpo w ... self._sum_west n ... self._sum_north_array p1 ... prop_1 p2 ... prop_2 n n n n | | | | | | | | | w~~ ~~B~~B~~B~~B~~ ~~p2 | | | | p1 | | | | A~~A~~A~~A return: step = 4 state = contraction of A,B,w,n,p1 effects: self._mpo will grow to the left with the next influence functional self._mps will be contraction of A,B,w,p1,p2 """ self._step += 1 prop_1, prop_2 = self._propagators(self._step - 1) prop_1_na = na.NodeArray([prop_1], left=False, right=False, name="first half-step") prop_2_na = na.NodeArray([prop_2], left=True, right=False, name="second half-step") if self._dkmax is None: mpo = self._mpo.copy() infl = self._influence(len(mpo)) infl_four_legs = create_delta(infl, [1, 0, 0, 1]) infl_na = na.NodeArray([infl_four_legs], left=True, right=True) self._mpo = na.join(infl_na, self._mpo, name="Thee Time Evolving MPO", copy=False) elif self._step < self._dkmax: _, mpo = na.split(self._mpo, int(0 - self._step), copy=True) else: mpo = self._mpo.copy() mpo.name = "temporary MPO" mpo.apply_vector(self._sum_west, left=True) self._mps.zip_up(prop_1_na, axes=[(0, 0)], left_index=-1, right_index=-1, direction="left", max_singular_values=None, max_truncation_err=self._epsrel, relative=True, copy=False) self._mps.zip_up(mpo, axes=[(0, 0)], left_index=0, right_index=-1, direction="right", max_singular_values=None, max_truncation_err=self._epsrel, relative=True, copy=False) if self._dkmax is not None and self._step >= self._dkmax: self._mps.contract(self._sum_north_na, axes=[(0, 0)], left_index=0, right_index=0, direction="right", copy=True) self._mps.svd_sweep(from_index=-1, to_index=0, max_singular_values=None, max_truncation_err=self._epsrel, relative=True) self._mps = na.join(self._mps, prop_2_na, copy=False, name=f"Thee MPS ({self._step})") tmp_mps = self._mps.copy() for _ in range(len(tmp_mps) - 1): tmp_mps.contract(self._sum_north_na, axes=[(0, 0)], left_index=0, right_index=0, direction="right", copy=True) assert len(tmp_mps) == 1 assert not tmp_mps.left assert not tmp_mps.right assert tmp_mps.rank == 1 self._state = tmp_mps.nodes[0].get_tensor() return copy(self._step), copy(self._state)