Tensor Network Theory Library  Beta release 1.2.1 A library of routines for performing TNT-based operations
tntNodeAlgebra.c
1 /*
2 Authors: Sarah Al-Assam, Stephen Clark and Dieter Jaksch
3 $LastChangedDate: 2015-06-29 20:44:17 +0100 (Mon, 29 Jun 2015)$
4 (c) University of Oxford 2014
5 */
6
15 /*-------------------------------------------*/
16
21
38  tntNode B)
39 {
40
41  TNT_ERR_RET_DEFS /* return value from internal function */
42
43  ret = _tnt_tnode_checkqn(A);
44  TNT_PUB_ERR_CHK /* NO_COVERAGE */
45
46  ret = _tnt_tnode_checkqn(B);
47  TNT_PUB_ERR_CHK /* NO_COVERAGE */
48
50  TNT_PUB_ERR_CHK /* NO_COVERAGE */
51 }
52
62 tntNode tntNodeDirectSum(tntNode A,
63  tntNode B,
64  tntLegLabel expandedLegs)
65 {
66
67  tntNode C; /* the result of the sum */
68  unsigned *expandedids, numexpanded; /* Number of expanded legs and their ids */
69  TNT_ERR_RET_DEFS /* return value from internal function */
70
71  ret = _tnt_tnode_checkqn(A);
72  TNT_PUB_ERR_CHK /* NO_COVERAGE */
73
74  ret = _tnt_tnode_checkqn(B);
75  TNT_PUB_ERR_CHK /* NO_COVERAGE */
76
77  /* Convert leg labals to leg ids */
78  ret = _tnt_node_id_strtonum(&numexpanded,&expandedids,expandedLegs);
79  TNT_PUB_ERR_CHK /* NO_COVERAGE */
80
81  if (NULL == A) {
82  sprintf(tnt_err.errinfostr,"Tring to perform direct sum with invalid node - check first argument"); /* NO_COVERAGE */
83  sprintf(tnt_err.pubfuncname,"tntNodeDirectSum"); /* NO_COVERAGE */
84  _tnt_print_error(); /* NO_COVERAGE */
85  } /* NO_COVERAGE */
86
87  if (NULL == B) {
88  sprintf(tnt_err.errinfostr,"Tring to perform direct sum with invalid node - check second argument"); /* NO_COVERAGE */
89  sprintf(tnt_err.pubfuncname,"tntNodeDirectSum"); /* NO_COVERAGE */
90  _tnt_print_error(); /* NO_COVERAGE */
91  } /* NO_COVERAGE */
92
93  ret = _tnt_tnode_directsum(&C, A, B, numexpanded, expandedids);
94  TNT_PUB_ERR_CHK /* NO_COVERAGE */
95
96  free(expandedids);
97
98  return C;
99 }
100
117 #ifdef MAKINGPUBLICDOCS
118 tntNode tntNodeContract(tntNode A,
119  tntNode B,
120  tntLegLabel legMapAC,
121  tntLegLabel legMapBC)
122 #else
123 tntNode tntNodeNamedContract(const char *vnA,
124  tntNode A,
125  const char *vnB,
126  tntNode B,
127  tntLegLabel legMapAC,
128  tntLegLabel legMapBC)
129 #endif
130 {
131  tntNode C; /* the result of the contraction */
132  unsigned legidMapAC[TNT_MAXLEGNUM+1], legidMapBC[TNT_MAXLEGNUM+1]; /* integer leg map */
133  char tmpstr[TNT_STRLEN];
134  TNT_ERR_RET_DEFS /* return value from internal function */
135
136  ret = _tnt_tnode_checkqn(A);
137  TNT_PUB_ERR_CHK /* NO_COVERAGE */
138
139  ret = _tnt_tnode_checkqn(B);
140  TNT_PUB_ERR_CHK /* NO_COVERAGE */
141
142  /* Convert leg map to numeric leg map */
143  ret = _tnt_node_id_legmapconv(legidMapAC,legMapAC);
144  if (TNT_SUCCESS != ret) {
145  strcpy(tmpstr, tnt_err.errinfostr);
146  sprintf(tnt_err.errinfostr,"Cannot contract node %s with node %s|%s", vnA, vnB, tmpstr); /* NO_COVERAGE */
147  sprintf(tnt_err.pubfuncname,"tntNodeSVD()"); /* NO_COVERAGE */
148  _tnt_print_error(); /* NO_COVERAGE */
149  } /* NO_COVERAGE */
150
151  /* Convert leg map to numeric leg map */
152  ret = _tnt_node_id_legmapconv(legidMapBC,legMapBC);
153  if (TNT_SUCCESS != ret) {
154  strcpy(tmpstr, tnt_err.errinfostr);
155  sprintf(tnt_err.errinfostr,"Cannot contract node %s with node %s|%s", vnA, vnB, tmpstr); /* NO_COVERAGE */
156  sprintf(tnt_err.pubfuncname,"tntNodeSVD()"); /* NO_COVERAGE */
157  _tnt_print_error(); /* NO_COVERAGE */
158  } /* NO_COVERAGE */
159
160
161  /* ------- Checks on arguments ------- */
162  if (A == B) {
163  ret = _tnt_tnode_copy(&B, A, 0);
164  TNT_PUB_N_ERR_CHK("tntNodeContract()"); /* NO_COVERAGE */
165  } /* NO_COVERAGE */
166
167  if (NULL == A) {
168  sprintf(tnt_err.errinfostr,"Tring to contract invalid node %s", vnA); /* NO_COVERAGE */
169  sprintf(tnt_err.pubfuncname,"tntNodeContract"); /* NO_COVERAGE */
170  _tnt_print_error(); /* NO_COVERAGE */
171  } /* NO_COVERAGE */
172
173  if (NULL == B) {
174  sprintf(tnt_err.errinfostr,"Tring to contract invalid node %s", vnB); /* NO_COVERAGE */
175  sprintf(tnt_err.pubfuncname,"tntNodeContract"); /* NO_COVERAGE */
176  _tnt_print_error(); /* NO_COVERAGE */
177  } /* NO_COVERAGE */
178
179  ret = _tnt_tnode_contract(&C, A, B, (int *) legidMapAC, (int *) legidMapBC);
180  if (TNT_SUCCESS != ret) {
181  strcpy(tmpstr, tnt_err.errinfostr);
182  sprintf(tnt_err.errinfostr,"Cannot contract %s and %s|%s", vnA, vnB, tmpstr); /* NO_COVERAGE */
183  sprintf(tnt_err.pubfuncname,"tntNodeContract"); /* NO_COVERAGE */
184  _tnt_print_error(); /* NO_COVERAGE */
185  } /* NO_COVERAGE */
186
187  /* If no legs remain, add a leg with id 1 */
188  if (0 == C->num_legs) {
189  unsigned newlegid;
190
191  ret = _tnt_node_id_chartonum(&newlegid, '1');
192  TNT_PUB_N_ERR_CHK("tntNodeContract()"); /* NO_COVERAGE */
193
195  TNT_PUB_N_ERR_CHK("tntNodeContract()") /* NO_COVERAGE */
196  }
197
198  return C;
199 }
200
210 void tntNodePrepContract(tntNode A,
211  tntNode B)
212 {
213
214  TNT_ERR_RET_DEFS /* return value from internal function */
215
216  if (A == B) {
217  sprintf(tnt_err.errinfostr,"Attempting to contract a node with itself"); /* NO_COVERAGE */
218  sprintf(tnt_err.pubfuncname,__FUNCTION__); /* NO_COVERAGE */
219  _tnt_print_error(); /* NO_COVERAGE */
220  } /* NO_COVERAGE */
221
222  ret = _tnt_tnode_checkqn(A);
223  TNT_PUB_ERR_CHK /* NO_COVERAGE */
224
225  ret = _tnt_tnode_checkqn(B);
226  TNT_PUB_ERR_CHK /* NO_COVERAGE */
227
228  ret = _tnt_tnode_prepcontract(A,B);
229  TNT_PUB_ERR_CHK /* NO_COVERAGE */
230
231 }
232
233 #ifdef MAKINGPUBLICDOCS
234
255 /* Function call leads to function below through C pre-processor macro */
256 tntNode tntNodeContractList(tntLegLabel remlegs,
257  tntNode A,
258  tntNode B,
259  tntNode C...)
260 #else
261 tntNode tntNodeStaticListContract(tntLegLabel remleglabels,
262  const char *vnA, tntNode tnA, const char *vnB, tntNode B, const char *vnC, tntNode C, const char *vnD, tntNode tnD,
263  const char *vnE, tntNode tnE, const char *vnF, tntNode tnF, const char *vnG, tntNode tnG, const char *vnH, tntNode tnH,
264  const char *vnI, tntNode tnI, const char *vnJ, tntNode tnJ, const char *vnK, tntNode tnK, const char *vnL, tntNode tnL)
265 #endif
266 {
267  tntNode tns[12] = {tnA,B,C,tnD,tnE,tnF,tnG,tnH,tnI,tnJ,tnK,tnL}; /* Array of the nodes to contract */
268  const char *vnso[12] = {vnA,vnB,vnC,vnD,vnE,vnF,vnG,vnH,vnI,vnJ,vnK,vnL}; /* Array of variable names for nodes */
269
270  tntNode tnR; /* The node to return */
271  unsigned numnodes=12; /* Number of nodes being contracted, loop counter */
272  char *vns[12]; /* modifiable array of character names */
273  unsigned numids, *remlegids;/* numeric leg ids */
274  char varRname[TNT_STRLEN]; /* variable names for printing information */
275  unsigned *idmax; /* number of legs and maximum leg id for each node */
276  int id1, id2; /* id's for a pair of connected legs */
277  tntIntArray leg_ids; /* leg ids for the current node */
278  unsigned *legmap; /* Array used for the legmap for all contractions */
279  unsigned n,l,m; /* Used for looping through nodes, leg labels and map entries */
280  unsigned dimconn; /* dimension connecting next lot of nodes to be contracted */
281  unsigned newgroup[12]={0}; /* Used to signify that a new intermediate group of nodes should be started in the contraction */
282  unsigned numRnodes=1; /* Number of intermediate nodes - a new one is generated whenever a singleton dimension is found */
283  TNT_ERR_RET_DEFS
284
285
286  /* Look for NULL arguments */
287  for (n = 12; n > 0 ; n--) {
288  if (NULL == tns[n-1]) numnodes--;
289  else {
290  ret = _tnt_tnode_checkqn(tns[n-1]);
291  TNT_PUB_ERR_CHK /* NO_COVERAGE */
292  }
293  }
294
295  /* copy over variable names */
296  for (n = 0; n < numnodes; n++) {
297  vns[n] = malloc(TNT_STRLEN*sizeof(char));
298  strcpy(vns[n],vnso[n]);
299  }
300
301  /* Turn the leg labels into numeric ids */
302  ret = _tnt_node_id_strtonum(&numids,&remlegids,remleglabels);
303  TNT_PUB_N_ERR_CHK("tntNodeContractList()") /* NO_COVERAGE */
304
305  /* Allocate array for maximum leg ids, setting all values to 1 */
306  chk = idmax = calloc(numnodes, sizeof(unsigned));
307  TNT_PUB_MEM_CHK /* NO_COVERAGE */
308
309  /* First perform checks on arguments */
310  for (n = 0; n < numnodes; n++) {
311  for (m = n+1; m < numnodes; m++) {
312  if (tns[n] == tns[m]) {
313  sprintf(tnt_err.errinfostr,"Cannot contract node %s with node %s as they are the same node", vns[n], vns[m]); /* NO_COVERAGE */
314  sprintf(tnt_err.pubfuncname,"tntNodeContractList()"); /* NO_COVERAGE */
315  _tnt_print_error(); /* NO_COVERAGE */
316  } /* NO_COVERAGE */
317  }
318  }
319
320  /* Look for any nodes with self connections and contract these first */
321  for (n = 0; n < numnodes; n++) {
322  ret = _tnt_tnode_findconnid(&id1,&id2,tns[n],tns[n]);
323  TNT_PUB_N_ERR_CHK("tntNodeContractList()") /* NO_COVERAGE */
324
325  if (-1 != id1) tntNodeNamedSelfContract(vns[n],tns+n);
326  }
327
328  /* Now, the leg-ids will be mapped, so that every leg id is unique */
329  /* This will be done by adding the maximum leg id of the previous node to the current node */
330
331  /* First find the number of legs and maximum leg id for each node */
332  for (n = 0; n < numnodes; n++) {
333
334  /* Get leg ids */
335  ret = _tnt_tnode_idget(&leg_ids, tns[n]);
336  TNT_PUB_N_ERR_CHK("tntNodeContractList()") /* NO_COVERAGE */
337
338  /* Find the id of the largest leg */
339  for (l = 0; l < leg_ids.sz; l++) {
340  if (leg_ids.vals[l] > (int) idmax[n]) idmax[n] = leg_ids.vals[l];
341  }
342
343  /* Add an extra leg to the final node in case the operation removes all legs */
344  if (n == numnodes-1) {
345  idmax[n] += 1;
347  TNT_PUB_N_ERR_CHK("tntNodeContractList()") /* NO_COVERAGE */
348  }
349
350  /* add the maximum leg id to the maximum leg id of the previous node
351  * since this will be the new maximum id after the map has been applied */
352  idmax[n] = (0 == n) ? idmax[n] : idmax[n] + idmax[n-1];
353
354  /* Free the leg_ids */
355  tntIntArrayFree(&leg_ids);
356
357  }
358
359
360
361  /* Make a 'no-change' leg map, up to the size of the total leg id */
362  chk = legmap = malloc((idmax[numnodes-1] + 1)*sizeof(int));
363  TNT_PUB_MEM_CHK /* NO_COVERAGE */
364  for (m = 0; m <= idmax[numnodes-1]; m++) legmap[m] = m;
365
366  /* Now map legs of all nodes apart from the first node, to offset by cumulative sum of maximum leg ids on prev node */
367  for (n = 1; n < numnodes; n++) {
368  ret = _tnt_tnode_maplegids(tns[n],legmap+idmax[n-1]);
369  TNT_PUB_N_ERR_CHK("tntNodeContractList()") /* NO_COVERAGE */
370  }
371
372  /* Determine the correct contraction order for 3 nodes */
373  if (3 == numnodes) {
374  ret = _tnt_tnode_contract_order_three(tns, vns);
375  TNT_PUB_N_ERR_CHK("tntNodeContractList()") /* NO_COVERAGE */
376  }
377
378  /* Determine the correct contraction order for 4 nodes */
379  /* if pairwise, start a new group on the 3rd node, so send array element 3 as pairwise flag */
380  if (4 == numnodes) {
381  ret = _tnt_tnode_contract_order_four(tns, vns, newgroup+2);
382  TNT_PUB_N_ERR_CHK("tntNodeContractList()") /* NO_COVERAGE */
383  }
384
385  /* Contract list of nodes 1 by 1, skipping any singleton connections or any that are flagged */
386  tnR = tns[0];
387  strcpy(varRname,vns[0]);
388  for (n = 1; n < numnodes; n++) {
389  /* determine whether there is a connecting dimension of 1, if we are not already starting a new group */
390  if (0 == newgroup[n]) {
391  ret = _tnt_tnode_getdimconn(&dimconn, tnR, tns[n]);
392  TNT_PUB_N_ERR_CHK("tntNodeContractList()") /* NO_COVERAGE */
393  if (1 == dimconn) newgroup[n] = 1;
394  }
395
396  /* Now check flag */
397  if (1 == newgroup[n]) {
398  /* put current resulting node in the array */
399  tns[numRnodes-1] = tnR;
400  strcpy(vns[numRnodes-1],"(");
401  strcat(vns[numRnodes-1],varRname);
402  strcat(vns[numRnodes-1],")");
403
404  /* increase the counter for the number of intermediate nodes */
405  numRnodes++;
406
407  /* set the next node to start contracting with as the next node in the array */
408  tnR = tns[n];
409  strcpy(varRname,vns[n]);
410  } else {
411  /* Otherwise perform a contraction */
412  ret = _tnt_tnode_contract(&tnR,tnR,tns[n],(int *) legmap,(int *) legmap);
413  if (TNT_SUCCESS != ret) {
414  char tmpstr[TNT_STRLEN];
415  strcpy(tmpstr, tnt_err.errinfostr);
416  sprintf(tnt_err.errinfostr,"Cannot contract %s with %s|%s", varRname, vns[n],tmpstr); /* NO_COVERAGE */
417  sprintf(tnt_err.pubfuncname,"tntNodeContractList()"); /* NO_COVERAGE */
418  tntNodePrintNamedInfo(varRname,tnR,0);
419  tntNodePrintNamedInfo(vns[n],tns[n],0);
420  _tnt_print_error(); /* NO_COVERAGE */
421  } /* NO_COVERAGE */
422
423  strcat(varRname,"*");
424  strcat(varRname,vns[n]);
425  }
426  }
427
428  /* Put the final contracted group of nodes in the array, and reset tnR with first intermediate node, if we are doing another round of contractions */
429  if (numRnodes > 1) {
430  tns[numRnodes-1] = tnR;
431  strcpy(vns[numRnodes-1],"(");
432  strcat(vns[numRnodes-1],varRname);
433  strcat(vns[numRnodes-1],")");
434
435  tnR = tns[0];
436  strcpy(varRname,vns[0]);
437  }
438
439  /* Now go through and contract intermediate nodes */
440  for (n = 1; n < numRnodes; n++) {
441  ret = _tnt_tnode_contract(&tnR,tnR,tns[n],(int *) legmap,(int *) legmap);
442  if (TNT_SUCCESS != ret) {
443  char tmpstr[TNT_STRLEN];
444  strcpy(tmpstr, tnt_err.errinfostr);
445  sprintf(tnt_err.errinfostr,"Cannot contract %s with %s|%s", varRname, vns[n],tmpstr); /* NO_COVERAGE */
446  sprintf(tnt_err.pubfuncname,"tntNodeContractList()"); /* NO_COVERAGE */
447  _tnt_print_error(); /* NO_COVERAGE */
448  } /* NO_COVERAGE */
449
450  strcat(varRname,"*");
451  strcat(varRname,vns[n]);
452  }
453
454  /* Map the leg ids on the contracted node to the intended values if more than one leg remains, otherwise give the remaining leg an id of 1 */
455  if (1 == tnR->num_legs) {
456  /* Set the leg map to change it to id 1 on contraction */
457  ret = _tnt_node_id_chartonum((unsigned *) legmap + idmax[numnodes-1], '1');
458  TNT_PUB_N_ERR_CHK("tntNodeContractList()"); /* NO_COVERAGE */
459  } else if (NULL == remlegids) {
460
461  /* Get rid of the additional leg */
462  ret = _tnt_tnode_squeeze(tnR,1,idmax + numnodes-1);
463  TNT_PUB_N_ERR_CHK("tntNodeContractList()"); /* NO_COVERAGE */
464
465  /* If no map is given, simply remove the offsets added before contraction */
466  for (n = 0; n < numnodes-1; n++) {
467  for (m = idmax[n]+1; m <= idmax[n+1]; m++) legmap[m] -= idmax[n];
468  }
469
470  } else {
471  /* If a leg map has been given, then the leg labels on the contracted node (in ascending order) will match those of the map sent */
472
473  /* Get rid of the additional leg */
474  ret = _tnt_tnode_squeeze(tnR,1,idmax + numnodes-1);
475  TNT_PUB_N_ERR_CHK("tntNodeContractList()"); /* NO_COVERAGE */
476
477  /* Get the leg-ids on the contracted node */
478  ret = _tnt_tnode_idget(&leg_ids, tnR);
479  TNT_PUB_N_ERR_CHK("tntNodeContractList()") /* NO_COVERAGE */
480
481  /* Mark the leg ids on the contracted node with a -2 in the leg map */
482  for (l = 0; l < leg_ids.sz; l++) legmap[leg_ids.vals[l]] = -2;
483
484  tntIntArrayFree(&leg_ids);
485
486  /* initialising current leg number on contracted node to 0 */
487  l = 0;
488
489  /* Now loop through all entries - set legs that exist on the contracted node to the value given in the remlegids argument (first checking numbers are sensible */
490  for (m = 0; m <= idmax[numnodes-1]; m++) {
491  if (-2 == legmap[m]) {
492  if (remlegids[l] < TNT_MAXLEGNUM) {
493  legmap[m] = remlegids[l];
494  l++;
495  } else {
496  sprintf(tnt_err.errinfostr, "Invalid leg label %c given for leg labels on contracted node|"
497  " Leg label must be alphanumeric character", _tnt_node_iderr_numtochar(remlegids[l])); /* NO_COVERAGE */
498  sprintf(tnt_err.pubfuncname,"tntNodeContractList()"); /* NO_COVERAGE */
499  _tnt_print_error(); /* NO_COVERAGE */
500  }
501  }
502  }
503  }
504
505  /* Apply the leg map to the contracted node */
506  ret = _tnt_tnode_maplegids(tnR,legmap);
507  TNT_PUB_N_ERR_CHK("tntNodeContractList()") /* NO_COVERAGE */
508
509  /* Free dynamically allocated memory */
510  free(legmap);
511  free(idmax);
512
513  for (n = 0; n < numnodes; n++) free(vns[n]);
514  free(remlegids);
515
516  return tnR;
517 }
518
519 #ifdef MAKINGPUBLICDOCS
520
530 void tntNodeContractSelf(tntNode *Ap)
531 #else
532 void tntNodeNamedSelfContract(const char *vnA, tntNode *Ap)
533 #endif
534 {
535  tntNode A,B,C; /* the nodes to be contracted, and the result of the contraction */
536  tntIntArray leg_ids; /* leg ids for node A */
537  int id1, id2; /* id's for a pair of connected legs */
538  char label1[]="a", label2[]="b";
539  unsigned idmax = 0, numlegs; /* Maximum leg id for node, and the number of uncontracted legs */
540  int *ncmapA = NULL; /* no change leg maps - variables only used if one or both of the leg maps are NULL */
542  unsigned l; /* Used for looping through leg labels */
543  unsigned m; /* Used for looping through map entries */
544  TNT_ERR_RET_DEFS /* return value from internal function */
545
546  /* Check node is valid */
547  if ((NULL == Ap) || (NULL == *Ap)) {
548  sprintf(tnt_err.errinfostr,"Tring to contract invalid node %s", vnA); /* NO_COVERAGE */
549  sprintf(tnt_err.pubfuncname,"tntNodeContractSelf()"); /* NO_COVERAGE */
550  _tnt_print_error(); /* NO_COVERAGE */
551  } /* NO_COVERAGE */
552
553  /* Set the first node to be contracted as the node pointed to by the input argument */
554  A = *Ap;
555
556  ret = _tnt_tnode_checkqn(A);
557  TNT_PUB_ERR_CHK /* NO_COVERAGE */
558
559  /* Get leg ids */
560  ret = _tnt_tnode_idget(&leg_ids, A);
561  TNT_PUB_N_ERR_CHK("tntNodeContractSelf()") /* NO_COVERAGE */
562
563  /* Set the number of legs that the node currently has */
564  numlegs = leg_ids.sz;
565
566  /* Find the id of the largest leg */
567  for (l = 0; l < leg_ids.sz; l++) {
568  if (leg_ids.vals[l] > (int) idmax) {
569  idmax = leg_ids.vals[l];
570  }
571  }
572
573  /* Create a leg map for A - no changes. Make it one size larger than it needs to be in case a leg is added later */
574  chk = ncmapA = malloc((idmax + 2)*sizeof(int));
575  TNT_PUB_N_MEM_CHK("tntNodeContractSelf()") /* NO_COVERAGE */
576
577  /* Populate the elements */
578  for (m = 0; m <= idmax+1; m++) ncmapA[m] = m;
579
580  /* Find ids for a pair of self-connected legs */
581  ret = _tnt_tnode_findconnid(&id1,&id2,A,A);
582  TNT_PUB_N_ERR_CHK("tntNodeContractSelf()") /* NO_COVERAGE */
583
584  /* Keep repeating whilst there are self-connections */
585  while (id1 != -1) {
586
587  /* If the number of legs is now 2, then contracting will remove all legs, so add a new sinlgeton leg */
588  if (2 == numlegs) {
589  /* If this is all the legs, add a new leg - give it the number of the largest leg-id + 1 */
590  added_leg = idmax + 1;
591  idmax++;
593  TNT_PUB_N_ERR_CHK("tntNodeContractSelf()") /* NO_COVERAGE */
594
595  /* Set the leg map to change it to id 1 on contraction */
596  ret = _tnt_node_id_chartonum((unsigned *) ncmapA + added_leg, '1');
597  TNT_PUB_N_ERR_CHK("tntNodeContractSelf()") /* NO_COVERAGE */
598  }
599
600  /* Convert ids to labels */
601  ret = _tnt_node_id_numtochar(label1, id1);
602  TNT_PUB_N_ERR_CHK("tntNodeContractSelf()") /* NO_COVERAGE */
603
604  /* Convert ids to labels */
605  ret = _tnt_node_id_numtochar(label2, id2);
606  TNT_PUB_N_ERR_CHK("tntNodeContractSelf()") /* NO_COVERAGE */
607
608  /* Make an identity node with the same leg properties as the legs to contract */
609  B = tntNodeCreateEyeLeg(A,label1,A,label2);
610
611  /* Insert this node within the self-contracted legs */
612  ret = _tnt_tnode_insert(B, id2, A, id1, id1, A, id2, 0);
613  TNT_PUB_ERR_CHK /* NO_COVERAGE */
614
615  /* Contract the nodes and assign to C */
616  ret = _tnt_tnode_contract(&C, A, B, ncmapA, ncmapA);
617  if (TNT_SUCCESS != ret) {
618  char tmpstr[TNT_STRLEN];
619  strcpy(tmpstr, tnt_err.errinfostr);
620  sprintf(tnt_err.errinfostr,"Cannot contract %s with itself|%s", vnA,tmpstr); /* NO_COVERAGE */
621  sprintf(tnt_err.pubfuncname,"tntNodeContractSelf()"); /* NO_COVERAGE */
622  _tnt_print_error(); /* NO_COVERAGE */
623  } /* NO_COVERAGE */
624
625  /* Set A to C */
626  A = C;
627
628  /* reduce the number of legs by 2 */
629  numlegs -= 2;
630
631  /* Look for another pair of connections */
632  ret = _tnt_tnode_findconnid(&id1,&id2,A,A);
633  TNT_PUB_N_ERR_CHK("tntNodeContractSelf()") /* NO_COVERAGE */
634  }
635
636  /* Free the arrays that are no longer needed */
637  free(ncmapA);
638  tntIntArrayFree(&leg_ids);
639
640  /* Assigned the pointed to the contracted node */
641  *Ap = A;
642
643  return;
644 }
645
652 void tntNodeExp(tntNode A,
653  tntComplex c,
654  tntLegLabel rowlegs,
655  tntLegLabel collegs)
656 {
657
658  TNT_ERR_RET_DEFS /* return value from internal function */
659  unsigned rownum, *rowlegids, colnum, *collegids;
660
661  ret = _tnt_tnode_checkqn(A);
662  TNT_PUB_ERR_CHK /* NO_COVERAGE */
663
664  ret = _tnt_node_id_strtonum(&rownum, &rowlegids, rowlegs);
665  TNT_PUB_ERR_CHK /* NO_COVERAGE */
666
667  ret = _tnt_node_id_strtonum(&colnum, &collegids, collegs);
668  TNT_PUB_ERR_CHK /* NO_COVERAGE */
669
670  ret = _tnt_tnode_exp(A, c, rownum, (int *) rowlegids, colnum, (int *) collegids);
671  TNT_PUB_ERR_CHK /* NO_COVERAGE */
672
673  free(rowlegids);
674  free(collegids);
675 }
676
682 void tntNodeInverseFact(tntNode A,
683  tntLegLabel legA)
684 {
685  unsigned legid;
686  TNT_ERR_RET_DEFS /* return value from internal function */
687
688  ret = _tnt_tnode_checkqn(A);
689  TNT_PUB_ERR_CHK /* NO_COVERAGE */
690
691  /* Get the integer leg id */
692  ret = _tnt_node_id_chartonum(&legid, *legA);
693  TNT_PUB_ERR_CHK /* NO_COVERAGE */
694
695  ret = _tnt_tnode_inversefact(A, legid);
696  TNT_PUB_ERR_CHK /* NO_COVERAGE */
697
698 }
699
704 void tntNodeScaleComplex(tntNode A,
705  tntComplex val)
706 {
707  TNT_ERR_RET_DEFS /* return value from internal function */
708
709  ret = _tnt_tnode_checkqn(A);
710  TNT_PUB_ERR_CHK /* NO_COVERAGE */
711
712  ret = _tnt_tnode_scale(A,val);
713  TNT_PUB_ERR_CHK /* NO_COVERAGE */
714 }
715
720 void tntNodeScaleReal(tntNode A,
721  double val)
722 {
723  tntComplex cval; /* Complex scaling value */
724  TNT_ERR_RET_DEFS /* return value from internal function */
725
726  ret = _tnt_tnode_checkqn(A);
727  TNT_PUB_ERR_CHK /* NO_COVERAGE */
728
729  cval.re = val;
730  cval.im = 0.0;
731
732  ret = _tnt_tnode_scale(A,cval);
733  TNT_PUB_ERR_CHK /* NO_COVERAGE */
734 }
735
736
776 #ifdef MAKINGPUBLICDOCS
777 tntNode tntNodeSVD(tntNode A,
778  tntLegLabel Ulegs,
779  tntLegLabel legUS,
780  tntLegLabel legSU,
781  tntLegLabel legSV,
782  tntLegLabel legVS,
783  int chi,
784  double *err,
785  tntLegLabel legmap)
786 #else
787 tntNode tntNodeSVD_(tntNode A,
788  const char *varnameA,
789  tntLegLabel Ulegs,
790  tntLegLabel legUS,
791  tntLegLabel legSU,
792  tntLegLabel legSV,
793  tntLegLabel legVS,
794  int chi,
795  double *err,
796  tntLegLabel legmap)
797 #endif
798 {
799  tntNode U; /* the tnode to return */
800  unsigned startNum; /* the number of start legs */
801  unsigned endNum; /* the number of end legs */
802  unsigned *startLegs; /* The legs that will be assigned to U */
803  unsigned *endLegs; /* the legs that will be assigned to VH */
804  unsigned intlegmap[TNT_MAXLEGNUM+1]; /* integer leg map */
805
806  unsigned ls, le, la; /* used to denote leg number for start legs, for end legs, and for all legs respectively */
807  unsigned us_id, su_id, sv_id, vs_id; /* Numbers for internal legtypes */
808  int isStart; /* flag to denote this leg one of the start legs */
809  double lclerr=0.0; /* local error variable - discarded if user is not interested in error and passed NULL as argument, or otherwise assigned to pointer value */
810  char tmpstr[TNT_STRLEN];
811  TNT_ERR_RET_DEFS /* return value from internal function */
812
813  /* Convert character arrays to numeric arrays */
814  ret = _tnt_node_id_strtonum(&startNum,&startLegs,Ulegs);
815  if (TNT_SUCCESS != ret) {
816  strcpy(tmpstr, tnt_err.errinfostr);
817  sprintf(tnt_err.errinfostr,"Cannot take SVD of %s|%s", varnameA, tmpstr); /* NO_COVERAGE */
818  sprintf(tnt_err.pubfuncname,"tntNodeSVD()"); /* NO_COVERAGE */
819  _tnt_print_error(); /* NO_COVERAGE */
820  } /* NO_COVERAGE */
821
822  /* Convert leg map to numeric leg map */
823  ret = _tnt_node_id_legmapconv(intlegmap,legmap);
824  if (TNT_SUCCESS != ret) {
825  strcpy(tmpstr, tnt_err.errinfostr);
826  sprintf(tnt_err.errinfostr,"Cannot take SVD of %s|%s", varnameA, tmpstr); /* NO_COVERAGE */
827  sprintf(tnt_err.pubfuncname,"tntNodeSVD()"); /* NO_COVERAGE */
828  _tnt_print_error(); /* NO_COVERAGE */
829  } /* NO_COVERAGE */
830
831  ret = _tnt_tnode_checkqn(A);
832  TNT_PUB_ERR_CHK /* NO_COVERAGE */
833
834  /* Calculate the number of remaining legs, which will all be assigned to VT */
835  endNum = A->num_legs - startNum;
836
837  /* Allocate an array for the remaining leg types */
838  chk = endLegs = malloc(endNum * sizeof(int));
839  TNT_PUB_MEM_CHK /* NO_COVERAGE */
840
841  /* current leg number of end legs is zero, as none have yet been assigned */
842  le = 0;
843  /* loop over all legs, and for each one, check if it has been assigned to the start legs */
844  for (la = 0; la < A->num_legs; la++) {
845  /* reset the flag */
846  isStart = 0;
847  /* check if this leg id is one of the start legs */
848  for (ls = 0; ls < startNum; ls++) {
849  if (A->leg_id[la] == startLegs[ls]) {
850  isStart = 1;
851  break;
852  }
853  }
854  if (!isStart) {
855  if (le < endNum) {
856  endLegs[le] = A->leg_id[la];
857  le++;
858  } else {
859  sprintf(tnt_err.errinfostr,"Cannot take SVD of %s|Some or all of the labels passed as start legs do not exist on the node", varnameA); /* NO_COVERAGE */
860  sprintf(tnt_err.pubfuncname,"tntNodeSVD()"); /* NO_COVERAGE */
861  _tnt_print_error(); /* NO_COVERAGE */
862  }
863  }
864  }
865
866  /* Convert all the character types to numbers */
867  ret = _tnt_node_id_chartonum(&us_id,legUS[0]);
868  if (TNT_SUCCESS != ret) {
869  strcpy(tmpstr, tnt_err.errinfostr);
870  sprintf(tnt_err.errinfostr,"Cannot take SVD of %s|%s", varnameA, tmpstr); /* NO_COVERAGE */
871  sprintf(tnt_err.pubfuncname,"tntNodeSVD()"); /* NO_COVERAGE */
872  _tnt_print_error(); /* NO_COVERAGE */
873  } /* NO_COVERAGE */
874
875  ret = _tnt_node_id_chartonum(&su_id,legSU[0]);
876  if (TNT_SUCCESS != ret) {
877  strcpy(tmpstr, tnt_err.errinfostr);
878  sprintf(tnt_err.errinfostr,"Cannot take SVD of %s|%s", varnameA, tmpstr); /* NO_COVERAGE */
879  sprintf(tnt_err.pubfuncname,"tntNodeSVD()"); /* NO_COVERAGE */
880  _tnt_print_error(); /* NO_COVERAGE */
881  } /* NO_COVERAGE */
882
883  ret = _tnt_node_id_chartonum(&sv_id,legSV[0]);
884  if (TNT_SUCCESS != ret) {
885  strcpy(tmpstr, tnt_err.errinfostr);
886  sprintf(tnt_err.errinfostr,"Cannot take SVD of %s|%s", varnameA, tmpstr); /* NO_COVERAGE */
887  sprintf(tnt_err.pubfuncname,"tntNodeSVD()"); /* NO_COVERAGE */
888  _tnt_print_error(); /* NO_COVERAGE */
889  } /* NO_COVERAGE */
890
891  ret = _tnt_node_id_chartonum(&vs_id,legVS[0]);
892  if (TNT_SUCCESS != ret) {
893  strcpy(tmpstr, tnt_err.errinfostr);
894  sprintf(tnt_err.errinfostr,"Cannot take SVD of %s|%s", varnameA, tmpstr); /* NO_COVERAGE */
895  sprintf(tnt_err.pubfuncname,"tntNodeSVD()"); /* NO_COVERAGE */
896  _tnt_print_error(); /* NO_COVERAGE */
897  } /* NO_COVERAGE */
898
899  /* Call tnode function with all the same arguments */
900  ret = _tnt_tnode_svd(&U, A, startLegs, startNum, us_id, su_id, endLegs, endNum, sv_id, vs_id, (int *) intlegmap, chi, &lclerr);
901  if (TNT_SUCCESS != ret) {
902  strcpy(tmpstr, tnt_err.errinfostr);
903  sprintf(tnt_err.errinfostr,"Cannot take SVD of %s|%s", varnameA, tmpstr); /* NO_COVERAGE */
904  sprintf(tnt_err.pubfuncname,"tntNodeSVD()"); /* NO_COVERAGE */
905  _tnt_print_error(); /* NO_COVERAGE */
906  } /* NO_COVERAGE */
907
908  /* return error if pointer passed it not NULL */
909  if (NULL != err) *err = lclerr;
910
911  /* Free the dynamically allocated arrays */
912  free(endLegs);
913  free(startLegs);
914
915  return U;
916 }
tntNode tntNodeDirectSum(tntNode A, tntNode B, tntLegLabel expandedLegs)
void tntNodeExp(tntNode A, tntComplex c, tntLegLabel rowlegs, tntLegLabel collegs)
tntNode tntNodeContractList(tntLegLabel remlegs, tntNode A, tntNode B, tntNode C...)
tntNode tntNodeCreateEyeLeg(tntNode A, tntLegLabel legA, tntNode B, tntLegLabel legB)
Definition: tntNodeUtil.c:76
void tntNodeScaleComplex(tntNode A, tntComplex val)
tntNode tntNodeSVD(tntNode A, tntLegLabel Ulegs, tntLegLabel legUS, tntLegLabel legSU, tntLegLabel legSV, tntLegLabel legVS, int chi, double *err, tntLegLabel legmap)