Tensor Network Theory Library  Beta release 1.0 A library of routines for performing TNT-based operations
Time evolution

## Functions

tntNodeArray tntMpsCreatePropArray (unsigned L, tntComplex h, tntNodeArray *nnl, tntNodeArray *nnr, tntComplexArray *nnparam, tntNodeArray *os, tntComplexArray *osparam)

tntNetwork tntMpsCreatePropST2sc (unsigned L, tntComplex dtc, tntNodeArray *nnL, tntNodeArray *nnR, tntComplexArray *nnparam, tntNodeArray *os, tntComplexArray *osparam)

tntNetwork tntMpsPropArrayToST2sc (tntNodeArray Proparr)

void tntMpsPropST2scConnect (tntNetwork mps, tntNetwork Prop)

double tntMpsPropSTscContract (tntNetwork mpsProp, int chi)

double tntMpsPropST2scProduct (tntNetwork mps, tntNetwork Prop, int chi)

## Detailed Description

This section describes MPS functions which are useful for performing time evolution using the TEBD algorithm, although they are not limited to this.

## Function Documentation

 tntNodeArray tntMpsCreatePropArray ( unsigned L, tntComplex h, tntNodeArray * nnl, tntNodeArray * nnr, tntComplexArray * nnparam, tntNodeArray * os, tntComplexArray * osparam )

Creates an array of propagators (length $$L-1$$) required for evolution under a site-wide operator $$\hat{O}$$ formed from a sum of nearest-neighbour and onsite terms.

$\hat{O} = \sum_{j=0}^{L-2}\sum_i^{n_n}\alpha_{i,j}\hat{o}^l_{i}\otimes\hat{o}^r_i + \sum_{j=0}^{L-1}\sum_i^{n_o}\beta_{i,j}\hat{o}^s_{i}$

Nearest-neighbour operators $$\hat{o}^l_{i}$$ and $$\hat{o}^r_i$$ should be provided in arrays nnl and nnr respectively both having length $$n_n$$. Onsite operators $$\hat{o}^s_{i}$$ should be provided in array os having length $$n_o$$. The operators should be single-site operators or product MPOs, i.e. no internal legs, and two physical legs with the legs labelled as follows:

All the operators should have the same dimension for the physical legs.

The parameters $$\alpha_{i,j}$$ and $$\beta_{i,j}$$ for the nearest neighbour are onsite terms are supplied in matrices nnparam and osparam respectively. The matrix must have a number of rows equal to the length $$n_n, n_o$$ of its respective operators array, but there are two options for the number of columns:

1. All the parameters are uniform accross the lattice. In this case the parameters array should have one column (which is the default behaviour if it is created with only one dimension specified). The parameter $$\alpha_{i,j}$$ or $$\beta_{i,j}$$ should be in position i,1 in the matrix for all sites.
2. One or more of the parameters can vary accross the lattice. In this case the parameters matrix should have L-1 rows for nearest neighbour operators and L rows for onsite operators. The parameter $$\alpha_{i,j}$$ or $$\beta_{i,j}$$ for operator i and site j should be at position i,j in the matrix. Any uniform operators should have identical entries for all the sites.

The two-site operator for the nearest-neighbour terms is simply formed from the supplied arguments as

$\hat{T}^n_{j,j+1} = \sum_i^{n_n}\alpha_{i,j}\hat{o}^l_i\otimes\hat{o}^r_i$

for each pair of sites $$j,j+1$$.

The two-site operator for the on-site terms is formed from the supplied arguments as

$\hat{T}^s_{j,j+1} = \frac{1}{2}\sum_i^{n_o}\left[(\beta_{i,j}+\delta_{0,j}\beta_{i,0})\hat{o}^s_i\otimes\mathbb{1}+(\beta_{i,j+1}+\delta_{L-1,j+1}\beta_{i,L-1})\mathbb{1}\otimes\hat{o}^s_i\right]$

for each pair of sites $$j,j+1$$ i.e. the onsite terms are distributed symmetrically amongst the two-site terms.

The propagator $$\hat{P}_{j,j+1}$$ in array entry j is then related to the operators $$\hat{T}_{j,j+1}=\hat{T}^n_{j,j+1}+\hat{T}^s_{j,j+1}$$ by:

$\hat{P}_{j,j+1} = \mathrm{exp}\left[-\mathrm{i}\Re(h)\hat{T}_{j,j+1} \right]\times\mathrm{exp}\left[-\Im(h)\hat{T}_{j,j+1} \right].$

The parameter $$h$$ is a uniform scale factor, which is usually related to the time step in simulations (e.g. half the time-step for second order decompositions). The propagators will then have four physical legs, each physical leg having the same dimension as the original physical legs, which are labelled as follows:

All nodes will be static nodes.

Returns
Returns the propagator for each pair of sites in an array.
Parameters
 L Length of system. h Uniform scale factor to apply to all terms. See the main description for information on how real and imaginary parts are applied nnl Array of nearest-neighbour operators for left site. Send NULL if there are no nearest neighbour terms. nnr Array of nearest-neighbour operators for right site. Send NULL if there are no nearest neighbour terms. nnparam Array of parameters for nearest-neighbour operators. Send NULL if there are no nearest neighbour terms. os Array of onsite operators. Send NULL if there are no on-site operators. osparam Parameters for the on-site operators. Send NULL if there are no on-site operators.
84 {
85
86  tntNodeArray Parr; /* Array of propagators to be returned by function */
87  tntComplex hs; /* Uniform scale factor multiplied by -i for real part, i for imaginary part */
88  unsigned i, j; /* Used for looping over terms and sites respectively */
89  unsigned numnodes; /* The number of different nodes that need to be created */
90  unsigned numrowlegs = 2, numcollegs = 2; /* Number of legs making up each dimension for the matrix exponential */
91  int rowlegs[2] = {TNT_MPS_TDL, TNT_MPS_TDR}, collegs[2] = {TNT_MPS_TUL, TNT_MPS_TUR}; /* Used when reshaping to matrix to form the exponential */
92  tntComplexArray two_site_params; /* Array for parameters on each site */
93  char err_msg[TNT_STRLEN]; /* buffer for error messages */
94
95  /* Check that there are the same number of left and right nearest neighbour operators */
96  if ((NULL == nnl && NULL != nnr) || (NULL != nnl && NULL == nnr) || ((NULL != nnl && NULL != nnr) && nnl->sz != nnr->sz)) {
97  tntErrorPrint("Cannot create a propagator!|The number of left nearest-neighbour terms is not equal to the number of right nearest-neighbour terms!",TNT_MPS_ERRCODE); /* NO_COVERAGE */
98  } /* NO_COVERAGE */
99
100  /* Check that there is a parameter for each of the left and right operators, or for each of the operators and each of the sites */
101  if ((nnl != NULL)&&(nnl->sz != 0)) {
102  if (NULL == nnparam || nnl->sz != nnparam->numrows) {
103  tntErrorPrint("Cannot create a propagator!|The number of nearest neighbour parameters is not equal to the number of nearest neighbour terms!",TNT_MPS_ERRCODE); /* NO_COVERAGE */
104  } /* NO_COVERAGE */
105  }
106
107  /* Check that there is a parameter for each of the onsite operators */
108  if ((os != NULL)&&(os->sz != 0)) {
109  if (NULL == osparam || os->sz != osparam->numrows) {
110  sprintf(err_msg,"Cannot create a propagator!|The number of on-site parameters per site (%d) is not equal to the number of on-site terms (%d)!",osparam->numrows,os->sz);
111  tntErrorPrint(err_msg,TNT_MPS_ERRCODE); /* NO_COVERAGE */
112  } /* NO_COVERAGE */
113  }
114
115  /* Check that the time step is not non-negligible */
116  if (TNT_DEFAULT_TOL > fabs(h.re) && TNT_DEFAULT_TOL > fabs(h.im)) { /* Checking that the time step size is not less that the tolerance */
117  tntErrorPrint("Error! Cannot create spin half two-site gates as the time step size is less than the tolerance.",TNT_MPS_ERRCODE); /* NO_COVERAGE */
118  } /* NO_COVERAGE */
119
120  /* Check that there is a non-zero number of operators */
121  if ((NULL == nnl || 0 == nnl->sz) && (NULL == os || 0 == os->sz)) {
122  tntErrorPrint("Cannot create a propogator, as there are no terms!",TNT_MPS_ERRCODE); /* NO_COVERAGE */
123  } /* NO_COVERAGE */
124
125  /* Allocate the array to be returned */
126  Parr = tntNodeArrayAlloc(L-1);
127
128  /* Calculate how many nodes to create: one node if the operators are uniform, L-1 nodes if any of the operators vary */
129  if ((NULL == os || 0 == os->sz || 1 == osparam->numcols) && (NULL == nnl || 0 == nnl->sz || 1 == nnparam->numcols)) {
130  numnodes = 1;
131  } else {
132  numnodes = L-1;
133  }
134
135  /* First take real part of time step and multiply by -i and take the imaginary part of the timestep and multiply by i */
136  hs.re = -h.im;
137  hs.im = -h.re;
138
139
140  /* If there are no on-site terms, and the parameters are uniform, then all the nodes will be identical */
141  if ((NULL == os || 0 == os->sz) && 1==numnodes) {
142
143  two_site_params = tntComplexArrayAlloc(nnl->sz); /* Array for parameters on each site */
144  /* Set the parameters for that site */
145  for (i = 0; i < nnl->sz; i++) {
146  two_site_params.vals[i].re = nnparam->vals[i].re;
147  two_site_params.vals[i].im = nnparam->vals[i].im;
148  }
149
150  Parr.vals[0] = tntMpsCreateTwoSiteOp(nnl,nnr,&two_site_params);
151  /* Take the matrix exponential to form the two-site propagator */
152  tntNodeExp(Parr.vals[0], hs, numrowlegs, rowlegs, numcollegs, collegs);
153  for (j = 1; j < L-1; j++) {
154  Parr.vals[j] = tntNodeCopy(Parr.vals[0],0);
155  }
156  /* Return the array of nodes */
157  return Parr;
158  }
159
160  /* If there are no on-site terms, and the parameters vary, then set a different node for each two site gate */
161  if ((NULL == os || 0 == os->sz) && L-1==numnodes) {
162  two_site_params = tntComplexArrayAlloc(nnl->sz); /* Array for parameters on each site */
163  for (j = 0; j < L-1; j++) {
164  /* Set the parameters for that site */
165  for (i = 0; i < nnl->sz; i++) {
166  two_site_params.vals[i].re = nnparam->vals[i + j*(nnl->sz)].re;
167  two_site_params.vals[i].im = nnparam->vals[i + j*(nnl->sz)].im;
168  }
169  /* Create the node for that site */
170  Parr.vals[j] = tntMpsCreateTwoSiteOp(nnl,nnr,&two_site_params);
171  /* Take the matrix exponential to form the two-site propagator */
172  tntNodeExp(Parr.vals[j], hs, numrowlegs, rowlegs, numcollegs, collegs);
173  }
174  /* Free the array for parameters on each site */
175  tntComplexArrayFree(&two_site_params);
176
177  /* Return the array of nodes */
178  return Parr;
179  }
180
181  /* ---------------------------------------------------------------- */
182  /* This part of the function is only reached if on-site terms exist */
183  /* ---------------------------------------------------------------- */
184
185  /* If the are on-site terms, then the identity node will need to be created */
186  tntNode eye = tntNodeCreateEyeOp(os->vals[0]); /* Identity node created using basis operator*/
187  tntNodeArray Lterms, Rterms; /* Arrays that contain both onsite and nearest neighbour left and right terms */
188
189  /* Create a node array that contains the nearest neighbour terms and the onsite terms */
190  Lterms = tntNodeArrayAlloc(nnl->sz + os->sz*2); /* twice the number of onsite terms, as require one term for .. */
191  Rterms = tntNodeArrayAlloc(nnl->sz + os->sz*2); /* ... operator on left site, and one term for oerator on right site */
192
193  /* First put the nearest neighbour terms in the array */
194  for (i = 0; i < nnl->sz; i++) {
195  Lterms.vals[i] = tntNodeCopy(nnl->vals[i],0);
196  Rterms.vals[i] = tntNodeCopy(nnr->vals[i],0);
197  }
198
199  /* Then put the on-site terms in the array */
200  for (i = 0; i < os->sz; i++) {
201  /* For the first term put the on-site operator on the left */
202  Lterms.vals[i*2 + nnl->sz] = tntNodeCopy(os->vals[i],0);
203  Rterms.vals[i*2 + nnl->sz] = tntNodeCopy(eye,0);
204
205  /* For the first term put the on-site operator on the right */
206  Rterms.vals[i*2 + 1 + nnl->sz] = tntNodeCopy(os->vals[i],0);
207  Lterms.vals[i*2 + 1 + nnl->sz] = tntNodeCopy(eye,0);
208  }
209
210  /* Now determine parameters for each two site gate, depending on whether they vary in space or not */
211  two_site_params = tntComplexArrayAlloc(Lterms.sz); /* Array for parameters on each site */
212
213  if (1 == numnodes) {
214  /* For the case where the operators are uniform, only the first and last nodes will be different, with
215  all the central nodes being the same */
216
217  /* Two site parameters are the same on every site */
218  for (i = 0; i < nnl->sz; i++) {
219  two_site_params.vals[i].re = nnparam->vals[i].re;
220  two_site_params.vals[i].im = nnparam->vals[i].im;
221  }
222
223  /* For the first site, the left on-site term is 1*parameter, right on-site term is 0.5*parameter */
224  for (i = 0; i < os->sz; i++) {
225  two_site_params.vals[i*2 + nnl->sz].re = osparam->vals[i].re;
226  two_site_params.vals[i*2 + nnl->sz].im = osparam->vals[i].im;
227  two_site_params.vals[i*2 + 1 + nnl->sz].re = osparam->vals[i].re/2.0;
228  two_site_params.vals[i*2 + 1 + nnl->sz].im = osparam->vals[i].im/2.0;
229  }
230  /* Create the node and put into the first term in the array */
231  Parr.vals[0] = tntMpsCreateTwoSiteOp(&Lterms,&Rterms,&two_site_params);
232  /* Take the matrix exponential to form the two-site propagator */
233  tntNodeExp(Parr.vals[0], hs, numrowlegs, rowlegs, numcollegs, collegs);
234
235  /* For the central sites, both the left and right on-site terms are 0.5*parameter */
236  for (i = 0; i < os->sz; i++) {
237  two_site_params.vals[i*2 + nnl->sz].re = osparam->vals[i].re/2.0;
238  two_site_params.vals[i*2 + nnl->sz].im = osparam->vals[i].im/2.0;
239  two_site_params.vals[i*2 + 1 + nnl->sz].re = osparam->vals[i].re/2.0;
240  two_site_params.vals[i*2 + 1 + nnl->sz].im = osparam->vals[i].im/2.0;
241  }
242  /* Create the node and put into the second term in the array */
243  Parr.vals[1] = tntMpsCreateTwoSiteOp(&Lterms,&Rterms,&two_site_params);
244  /* Take the matrix exponential to form the two-site propagator */
245  tntNodeExp(Parr.vals[1], hs, 2, rowlegs, 2, collegs);
246
247  /* Copy this node for all central terms */
248  for (j = 2; j<L-2; j++) {
249  Parr.vals[j] = tntNodeCopy(Parr.vals[1],0);
250  }
251
252  /* For the last site, the left on-site term is 0.5*parameter, right on-site term is 1*parameter */
253  for (i = 0; i < os->sz; i++) {
254  two_site_params.vals[i*2 + nnl->sz].re = osparam->vals[i].re/2.0;
255  two_site_params.vals[i*2 + nnl->sz].im = osparam->vals[i].im/2.0;
256  two_site_params.vals[i*2 + 1 + nnl->sz].re = osparam->vals[i].re;
257  two_site_params.vals[i*2 + 1 + nnl->sz].im = osparam->vals[i].im;
258  }
259  /* Create the node and put into the first term in the array */
260  Parr.vals[L-2] = tntMpsCreateTwoSiteOp(&Lterms,&Rterms,&two_site_params);
261  /* Take the matrix exponential to form the two-site propagator */
262  tntNodeExp(Parr.vals[L-2], hs, 2, rowlegs, 2, collegs);
263
264  } else {
265
266  /* Otherwise every node in the array will be different */
267  double scL, scR; /* Amount to scale onsite parameter by - depends on site */
268  unsigned ind, indL, indR; /* index in array */
269
270  /* Set the terms for all sites */
271  for (j = 0; j<L-1; j++) {
272  /* Set the nearest neighbour terms for the central sites */
273  for (i = 0; i < nnl->sz; i++) {
274  ind = (1 == nnparam->numcols) ? i : i + j*nnl->sz;
275  two_site_params.vals[i].re = nnparam->vals[ind].re;
276  two_site_params.vals[i].im = nnparam->vals[ind].im;
277  }
278
279  /* Set the onsite terms for the central sites */
280  scL = (0==j) ? 1.0 : 2.0;
281  scR = (L-2 == j) ? 1.0 : 2.0;
282  for (i = 0; i < os->sz; i++) {
283  indL = (1 == osparam->numcols) ? i : i + j*os->sz;
284  indR = (1 == osparam->numcols) ? i : i + (j+1)*os->sz;
285  two_site_params.vals[i*2 + nnl->sz].re = osparam->vals[indL].re/scL;
286  two_site_params.vals[i*2 + nnl->sz].im = osparam->vals[indL].im/scL;
287  two_site_params.vals[i*2 + 1 + nnl->sz].re = osparam->vals[indR].re/scR;
288  two_site_params.vals[i*2 + 1 + nnl->sz].im = osparam->vals[indR].im/scR;
289  }
290
291  /* Create the node and put into the first term in the array */
292  Parr.vals[j] = tntMpsCreateTwoSiteOp(&Lterms,&Rterms,&two_site_params);
293  /* Take the matrix exponential to form the two-site propagator */
294  tntNodeExp(Parr.vals[j], hs, numrowlegs, rowlegs, numcollegs, collegs);
295  }
296  }
297
298  /* Free the arrays and nodes */
299  tntComplexArrayFree(&two_site_params);
300  tntNodeArrayFree(&Lterms);
301  tntNodeArrayFree(&Rterms);
302  tntNodeFree(&eye);
303
304  /* Return the array of nodes */
305  return Parr;
306 }
#define TNT_MPS_TUL
Definition: tntMps.h:76
#define TNT_MPS_TUR
Definition: tntMps.h:81
tntComplex * vals
Pointer to the first element in the tntComplex array.
Definition: tnt.h:169
struct tnode * tntNode
Definition: tnt.h:118
#define TNT_MPS_TDR
Definition: tntMps.h:91
tntNode tntNodeCreateEyeOp(tntNode tn)
Definition: tntNode_funcs.c:270
tntNodeArray tntNodeArrayAlloc(unsigned num_elems)
Definition: tntArray_funcs.c:110
void tntComplexArrayFree(tntComplexArray *arr)
Definition: tntArray_funcs.c:192
Simple 1D array for tntNodes.
Definition: tnt.h:178
void tntNodeArrayFree(tntNodeArray *arr)
Definition: tntArray_funcs.c:210
unsigned numrows
The number of rows in the matrix.
Definition: tnt.h:171
void tntNodeExp(tntNode tn, tntComplex sc_val, unsigned dimNum, int *legs, unsigned dimNumB, int *legsB)
Definition: tntNode_funcs.c:855
#define TNT_DEFAULT_TOL
Definition: tnt.h:82
Simple 1D array for complex values.
Definition: tnt.h:168
tntNode * vals
Pointer to the first element in the tntNode array.
Definition: tnt.h:179
void tntNodeFree(tntNode *tn)
Definition: tntNode_funcs.c:420
#define TNT_STRLEN
Definition: tnt.h:59
double re
Definition: tnt.h:137
tntNode tntNodeCopy(tntNode tn, int conj)
Definition: tntNode_funcs.c:486
tntNode tntMpsCreateTwoSiteOp(tntNodeArray *Lnodes, tntNodeArray *Rnodes, tntComplexArray *params)
Definition: tntMpsCreateTwoSiteOp.c:39
tntComplexArray tntComplexArrayAlloc(unsigned numrows, unsigned numcols)
Definition: tntDummy_funcs.c:96
#define TNT_MPS_TDL
Definition: tntMps.h:86
double im
Definition: tnt.h:138
unsigned numcols
The number of columns in the matrix.
Definition: tnt.h:172
Use this type to define complex numbers. Any complex arithmetic needs to be done manually. For example to add two complex numbers A and B to give C write:
Definition: tnt.h:136
unsigned sz
The number of elements in the array.
Definition: tnt.h:180
 tntNetwork tntMpsCreatePropST2sc ( unsigned L, tntComplex dtc, tntNodeArray * nnL, tntNodeArray * nnR, tntComplexArray * nnparam, tntNodeArray * os, tntComplexArray * osparam )

Creates a network of two-site terms representing a site-wide propagator decomposed using a Suzuki-Trotter second-order staircase expansion. The propagator evolves under a site-wide operator $$\hat{O}$$ formed from a sum of nearest-neighbour and onsite terms for a timestep of size dtc.

$\hat{O} = \sum_{j=0}^{L-2}\sum_i^{n_n}\alpha_{i,j}\hat{o}^l_{i}\otimes\hat{o}^r_i + \sum_{j=0}^{L-1}\sum_i^{n_o}\beta_{i,j}\hat{o}^s_{i}$

The two-site propagators are formed using tntMpsCreatePropArray() using half the time-step as the uniform scale factor (see the documentation for this function for more information). They are then connected in a staircase network from left-to-right, then right-to-left, so the network represents a complete time step.

The orange diamonds represent the start and end of the network i.e. the network starts at the top-most propagator and ends at the bottom-most propagator.

Functions tntMpsPropST2scProduct() for then taking the product of the network with an MPS.
Returns
A network representing the site-wide propagator
Parameters
 L Length of system. dtc Size of the time step. See the main description for information on how real and imaginary parts are applied nnL Array of nearest-neighbour operators for left site. Send NULL if there are no nearest neighbour terms. nnR Array of nearest-neighbour operators for right site. Send NULL if there are no nearest neighbour terms. nnparam Array of parameters for nearest-neighbour operators. Send NULL if there are no nearest neighbour terms. os Array of onsite operators. Send NULL if there are no on-site operators. osparam Parameters for the on-site operators. Send NULL if there are no on-site operators.
49 {
50  tntComplex h; /* Uniform scale factor for exponentials */
51  tntNodeArray Proparr; /* Array of propagators */
52  tntNetwork Prop; /* The propagator network to return */
53
54  /* Create the scale factor from the time step */
55  h.re = dtc.re/2.0;
56  h.im = dtc.im/2.0;
57
58  /* Generate an array of propagators required to build the network */
59  Proparr = tntMpsCreatePropArray(L,h,nnL,nnR,nnparam,os,osparam);
60
61  Prop = tntMpsPropArrayToST2sc(Proparr);
62
63  /* Free the array of propagators (copies of all nodes taken for the network so we can free it) */
64  tntNodeArrayFree(&Proparr);
65
66  /* Return the network */
67  return Prop;
68
69 }
tntNodeArray tntMpsCreatePropArray(unsigned L, tntComplex h, tntNodeArray *nnl, tntNodeArray *nnr, tntComplexArray *nnparam, tntNodeArray *os, tntComplexArray *osparam)
Definition: tntMpsCreatePropagator.c:77
Simple 1D array for tntNodes.
Definition: tnt.h:178
struct tnetwork * tntNetwork
Definition: tnt.h:123
void tntNodeArrayFree(tntNodeArray *arr)
Definition: tntArray_funcs.c:210
tntNetwork tntMpsPropArrayToST2sc(tntNodeArray Proparr)
Definition: tntMpsCreateSTstaircase.c:85
double re
Definition: tnt.h:137
double im
Definition: tnt.h:138
Use this type to define complex numbers. Any complex arithmetic needs to be done manually. For example to add two complex numbers A and B to give C write:
Definition: tnt.h:136
 tntNetwork tntMpsPropArrayToST2sc ( tntNodeArray Proparr )

Creates a network of two-site terms representing a site-wide propagator from an array of propagators decomposed using a Suzuki-Trotter second-order staircase expansion. Array entry j is assumed to contain the two-site propagator for sites $$j,j+1$$, and two copies of the propagator are placed in the network i.e. one for a right to left sweep, and one for a left-to-right sweep. Such an array can be created using tntMpsCreatePropArray(), although it does not have to be (e.g. the nodes could be loaded from an initialisation file instead). The final network has the following form:

The orange diamonds represent the start and end of the network i.e. the network starts at the top-most propagator and ends at the bottom-most propagator.

Returns
A network representing the site-wide propagator
Parameters
 Proparr Array of propagators. Uncahnged by the function - copies of all nodes are used.
86 {
87
88  tntNetwork Prop; /* The propagator network to return */
89  tntNode Ptop; /* Last inserted node in the top or left-to-right staircase */
90  tntNode Pbot; /* Last inserted node in the bottom or right-to-left staircase */
91  unsigned termleg=5; /* Label for the terminating leg */
92  unsigned j; /* site counter */
93
94  /* Create an empty network */
95  Prop = tntNetworkCreate();
96
97  /* Copy over first node */
98  Ptop = tntNodeCopy(Proparr.vals[0],0);
99
100  /* Add a leg to the first node in the network for joining to start of network */
102
103  /* Place a copy of the first node at the start of the network
104  * This represents the top of the staircase
105  * Left bottom leg points to the end of the network */
106  tntNodeInsertAtStart(Ptop,termleg,TNT_MPS_TDL,Prop);
107
108  /* Copy over first node again */
109  Pbot = tntNodeCopy(Proparr.vals[0],0);
110
111  /* Add a leg to the first node in the network for joining to end of network */
113
114  /* Place a copy of the first node at the end of the network
115  * This represents the end of the staircase or zip back and forth
116  * The top left leg of this node connects to the bottom left leg of the topmost propagator that previously pointed to the end of the network */
117  tntNodeInsertAtEnd(Pbot, TNT_MPS_TUL, termleg, Prop);
118
119  /* Join the nodes on their right legs too */
120  tntNodeJoin(Ptop, TNT_MPS_TDR, Pbot, TNT_MPS_TUR);
121
122  /* Now move from left to right, inserting nodes below and right to the nodes forming the left to right staircase and above and right the nodes forming the right to left staircase */
123  for (j = 1; j < Proparr.sz; j++) {
124
125  /* Insert new top node to the right of and between the current top node and bottom node */
127
128  /* Reassign the current top node */
129  Ptop = tntNodeFindConn(Ptop, TNT_MPS_TDR);
130
131  /* Insert new bottom node directly under the new current top node and above and to the right of the current bottom node */
133
134  /* Reassign the current bottom node */
135  Pbot = tntNodeFindConn(Pbot, TNT_MPS_TUR);
136
137  /* Join the nodes on their right legs too */
138  tntNodeJoin(Ptop, TNT_MPS_TDR, Pbot, TNT_MPS_TUR);
139
140  }
141
142  /* Return the network */
143  return Prop;
144 }
#define TNT_MPS_TUL
Definition: tntMps.h:76
#define TNT_MPS_TUR
Definition: tntMps.h:81
tntNode tntNodeFindConn(tntNode tn, unsigned legA)
Definition: tntNode_funcs.c:438
struct tnode * tntNode
Definition: tnt.h:118
Definition: tntNode_funcs.c:401
#define TNT_MPS_TDR
Definition: tntMps.h:91
void tntNodeInsertAtEnd(tntNode tnI, int legIlast, int legInwend, tntNetwork tnw)
Definition: tntNode_funcs.c:945
void tntNodeInsert(tntNode tnI, int legIA, int legIB, tntNode tnA, int legA, tntNode tnB, int legB)
Definition: tntNode_funcs.c:879
void tntNodeInsertAtStart(tntNode tnI, int legInwstart, int legIfirst, tntNetwork tnw)
Definition: tntNode_funcs.c:905
struct tnetwork * tntNetwork
Definition: tnt.h:123
tntNetwork tntNetworkCreate(void)
Definition: tntNetwork_funcs.c:62
tntNode * vals
Pointer to the first element in the tntNode array.
Definition: tnt.h:179
tntNode tntNodeCopy(tntNode tn, int conj)
Definition: tntNode_funcs.c:486
void tntNodeJoin(tntNode tnA, int legA, tntNode tnB, int legB)
Definition: tntNode_funcs.c:462
#define TNT_MPS_TDL
Definition: tntMps.h:86
unsigned sz
The number of elements in the array.
Definition: tnt.h:180
 void tntMpsPropST2scConnect ( tntNetwork mps, tntNetwork Prop )

Connects a network created using tntMpsCreatePropST2sc() to an MPS network. It removes the singleton legs from the propagator network, and the start and end legs of the complete network are those that originally belonged to the MPS, as shown below.

Note the orange diamonds represent the start and end of the network.

The MPS passed as an argument is used, so the connections on the physical legs are modified by the function, and they must initially be unconnected. A copy of the propagator network is connected, so the propagator network passed in the arguments is unchanged by the function.

Functions tntMpsPropST2scProduct() for then taking the product of the network with an MPS.
Returns
No return value
Parameters
 mps The network representing the MPS Prop The network representing the propagator
33 {
34
35  tntNetwork Propc; /* A copy of the propagator network */
36  tntNode P; /* The current propagator */
37  tntNode A; /* The current MPS node */
38  unsigned j; /* site counter */
39
40  /* make a copy of the network */
41  Propc = tntNetworkCopy(Prop);
42
43  /* Find the first node in the copy of the propagator */
44  P = tntNodeFindFirst(Propc);
45
46  /* Find the first MPS node */
47  A = tntNodeFindFirst(mps);
48
49  /* Attach the top left leg of the first propagator to the first MPS node */
51
52  /* Loop through the networks, joining top right leg of propagator to the next MPS node */
53  for (j = 1; j < tntMpsLength(mps); j++) {
54
55  /* Find the next MPS node */
56  A = tntNodeFindConn(A, TNT_MPS_R);
57
58  /* Connect it to the top right leg of the current propagator */
60
61  /* Go to the next propagator in the staircase */
63
64  }
65
66  /* Get rid of connections to the start and end of the network */
67  tntNetworkToNodeGroup(&Propc);
68
69  return;
70
71 }
#define TNT_MPS_TUL
Definition: tntMps.h:76
void tntNetworkToNodeGroup(tntNetwork *tnwp)
Definition: tntNetwork_funcs.c:209
#define TNT_MPS_TUR
Definition: tntMps.h:81
tntNode tntNodeFindConn(tntNode tn, unsigned legA)
Definition: tntNode_funcs.c:438
unsigned tntMpsLength(tntNetwork mps)
Definition: tntMpsUtil.c:208
struct tnode * tntNode
Definition: tnt.h:118
#define TNT_MPS_TDR
Definition: tntMps.h:91
struct tnetwork * tntNetwork
Definition: tnt.h:123
tntNode tntNodeFindFirst(tntNetwork tnw)
Definition: tntNode_funcs.c:664
tntNetwork tntNetworkCopy(tntNetwork tnw)
Definition: tntNetwork_funcs.c:36
void tntNodeJoin(tntNode tnA, int legA, tntNode tnB, int legB)
Definition: tntNode_funcs.c:462
#define TNT_MPS_D
Definition: tntMps.h:66
#define TNT_MPS_R
Definition: tntMps.h:61
 double tntMpsPropST2scProduct ( tntNetwork mps, tntNetwork Prop, int chi )

Performs a single step of a second order Suzuki-Trotter staircase expansion of a site-wide propagator.

A network as that pictured above must be provided for the propagator i.e. with the gates applied in a zip across first left to right, then right to left. A suitable propagator can be built using tntMpsCreatePropST2sc(). The entire propagator is then multiplied with the MPS i.e. a sweep in both directions is performed.

The orthogonality centre of the MPS should be on the first site before applying the step, and will return to the first site after the step.

Returns
The truncation error for that step, which is the sum of the truncation error for all SVDS. The truncation error for each SVD can be defined in a few different ways - see the documentation for tntTruncType() for more details.
Parameters
 mps Network representing the MPS wave function. Will be changed by the function, by applying one step of the evolution operator. Prop A network of two-site operators arranged in a left to right then right to left staircase. Unchanged by function. chi The maximum internal dimension. All SVD's will be truncated to this value.
Examples:
tebd.c.
221 {
222
223  /* Total truncation error */
224  double err;
225
226  /* Connect a copy of Prop to the mps */
227  tntMpsPropST2scConnect(mps,Prop);
228
229  /* Apply two contractions of a single staircase */
230  err = tntMpsPropSTscContract(mps,chi);
231  err += tntMpsPropSTscContract(mps,chi);
232
233  /* Return the error */
234  return err;
235
236 }
double tntMpsPropSTscContract(tntNetwork mpsProp, int chi)
Definition: tntMpsST2sc.c:97
void tntMpsPropST2scConnect(tntNetwork mps, tntNetwork Prop)
Definition: tntMpsST2sc.c:31
 double tntMpsPropSTscContract ( tntNetwork mpsProp, int chi )

Performs a single sweep in one direction of a Suzuki-Trotter staircase sweep, contracting the propagators with the MPS nodes. The direction is determined by the connections of the network.

The connections of the network must be as follows for a left to right sweep:

and as follows for a right to left sweep:

Any node connected to the downwards facing legs of the propagator network are unaffected by the function.

The `twist' or orthogonality centre is moved as the two-site gates are swept across. After completion of a left to right sweep the orthogonality centre will be on the last site, and after the completion of a right to left sweep the orthogonality centre will be on the first site.

Returns
The truncation error for that sweep, which is the sum of the truncation error for all SVDS. The truncation error for each SVD can be defined in a few different ways - see the documentation for tntTruncType() for more details.
Parameters
 mpsProp Network representing the MPS connected to the staircase. Will be changed by the function, by applying the propagator. chi The maximum internal dimension. All SVD's will be truncated to this value.
99 {
100
101  /* Nodes used in function */
102  tntNode A; /* the current node */
103  tntNode A_nxt; /* the next node along in the specified direction (set to NULL for the purposes of the first loop) */
104  tntNode beta; /* the node made by contracting two neighbouring nodes */
105  tntNode theta; /* the node made by contracting the beta tensor with the two site gate */
106  tntNode P; /* The propagator to contract */
107
108  /* Maps and declerations for leg types */
109  int start_legtypes[2]; /* Array for holding the types of the 'start legs' of the SVD */
110  int type_sconn; /* The type of connection that will link U to S and S to V */
111  int type_econn; /* The type of connection that will link S to U and V to S */
112  int idmapsvd[5] = {0,1,2,3,3}; /* The maps for the SVD. Note there is no type zero actually used. The internal legs remain the same. The physical legs 3 and 4 both become type 3 on the new nodes */
113  int idmap1[4] = {0,1,2,3}, idmap2[4] = {0,1,2,3}; /* The maps for the contraction. Map will depend on direction, so one of these maps will be changed when direction is tested. */
114  int op_direction; /* The opposite direction to the direction of movement */
115
116  /* Variables for keeping track of sites */
117  int j, jstart, jend; /* Site count, first site and last site to visit. */
118  int dj; /* Difference in j between successive sites visited */
119  unsigned numsites; /* Number of nodes in the MPS */
120  int direction; /* direction of the sweep */
121
122  /* Total truncation error, truncation error for each SVD. */
123  double err = 0, errc;
124
125  /* Get the number of nodes in the MPS */
126  numsites = tntMpsLength(mpsProp);
127
128  /* Determine the direction of the staircase. If the first two nodes are connected to the same propagator it is a left-to-right sweep, otherwise assume left to right sweep */
129  A = tntNodeFindFirst(mpsProp);
130  A_nxt = tntNodeFindConn(A,TNT_MPS_R);
131  if (tntNodeFindConn(A, TNT_MPS_D) == tntNodeFindConn(A_nxt, TNT_MPS_D)) {
132  direction = TNT_MPS_R;
133  } else {
134  direction = TNT_MPS_L;
135  }
136
137  /* Check the direction of moving through the network, and set variables appropriately. */
138  if (TNT_MPS_R == direction) {
139  /* Set the current tensor equal to the first tensor in the network if moving right */
140  A = tntNodeFindFirst(mpsProp);
141  op_direction = TNT_MPS_L;
142  start_legtypes[0] = 1;
143  start_legtypes[1] = 3;
144  idmap2[3] = 4;
145  jstart = 0;
146  jend = numsites - 1;
147  dj = 1;
148  } else {
149  /* Set the current tensor equal to the last tensor in the network if moving left */
150  A = tntNodeFindLast(mpsProp);
151  op_direction = TNT_MPS_R;
152  start_legtypes[0] = 2;
153  start_legtypes[1] = 4;
154  idmap1[3] = 4;
155  jstart = numsites - 2;
156  jend = -1;
157  dj = -1;
158  }
159
160  type_sconn = direction; /* type of connection for SVD: U to S and S to VT */
161  type_econn = op_direction; /* type of connection for SVD: S to U and VT to S */
162
163
164  /* Move through all the tensors in the chain perform the SVD and contraction steps, */
165  /* Stopping when the last node is reached */
166  for (j = jstart; j != jend; j += dj) {
167  /* Find the next node along */
168  A_nxt = tntNodeFindConn(A,direction);
169
170  /* Find the propagator */
171  P = tntNodeFindConn(A, TNT_MPS_D);
172
173  /* Contract first and second node */
174  beta = tntNodeContract(A,A_nxt,idmap1,idmap2);
175
176  /* Contract beta with the time step */
177  theta = tntNodeContract(beta,P,NULL,NULL);
178
179  /* SVD theta tensor */
180  A = tntNodeSVD(theta,start_legtypes,2,type_sconn,type_econn,idmapsvd,chi,&errc);
181
182  /* Add the truncation error */
183  err += errc;
184
185  /* Determine the tensors that need to be contracted (S and VT from the SVD) */
186  /* Find S by finding node connected to the leg of the correct leg type, and assign to tn */
187  A = tntNodeFindConn(A,direction);
188
189  /* Find VT by finding node connected to the leg of the correct leg type, and assign to tn_nxt */
190  A_nxt = tntNodeFindConn(A,direction); /* VT becomes tn_nxt */
191
192  /* Contract S and VT and assign the result to tn. */
193  A = tntNodeContract(A, A_nxt,NULL,NULL);
194
195  }
196  /* Return the error */
197  return err;
198
199 }
tntNode tntNodeFindConn(tntNode tn, unsigned legA)
Definition: tntNode_funcs.c:438
unsigned tntMpsLength(tntNetwork mps)
Definition: tntMpsUtil.c:208
struct tnode * tntNode
Definition: tnt.h:118
tntNode tntNodeFindLast(tntNetwork tnw)
Definition: tntNode_funcs.c:685
tntNode tntNodeContract(tntNode tnA, tntNode tnB, int *legMapAC, int *legMapBC)
Definition: tntDummy_funcs.c:34
#define TNT_MPS_L
Definition: tntMps.h:56
tntNode tntNodeSVD(tntNode tn, int *startLegs, unsigned startNum, int legUS, int legSU, int *legMap, int connDim, double *err)
Definition: tntNode_funcs.c:64
tntNode tntNodeFindFirst(tntNetwork tnw)
Definition: tntNode_funcs.c:664
#define TNT_MPS_D
Definition: tntMps.h:66
#define TNT_MPS_R
Definition: tntMps.h:61