FORM v5.0.0-35-g6318119
grcc.cc
1// { ( [
2//**************************************************************
3// grcc.cc
4
5/* #[ License : */
6/*
7 * Copyright (C) 2023-2026 T. Kaneko
8 * When using this file you are requested to refer to the publication
9 * Comput.Phys.Commun. 92 (1995) 127-152
10 *
11 * This file is part of FORM.
12 *
13 * FORM is free software: you can redistribute it and/or modify it under the
14 * terms of the GNU General Public License as published by the Free Software
15 * Foundation, either version 3 of the License, or (at your option) any later
16 * version.
17 *
18 * FORM is distributed in the hope that it will be useful, but WITHOUT ANY
19 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
21 * details.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with FORM. If not, see <http://www.gnu.org/licenses/>.
25 */
26/* #] License : */
27
28#ifndef NOFORM
29extern "C" {
30#include "form3.h"
31}
32#endif
33
34#include <iostream>
35#include <iomanip>
36#include <sstream>
37#include <cstdio>
38#include <stdlib.h>
39#include <string.h>
40#include <time.h>
41
42//==============================================================
43// new default values of options
44// #define OLDDEFAULT
45
46// new function for the output in python format
47// #define NEWOUTPY
48
49//==============================================================
50// For debugging
51//
52// #define MONITOR // in graph elimination
53// #define CHECK // check consistency
54
55//==============================================================
56// optimization : best combination depends on process by process
57#define SIMPSEL
58
59// optimization : lower and upper bound of deg of target node of connection.
60#define MINMAXLEG
61
62// optimization : optimization with respect to 'extonly' particles
63#define OPTEXTONLY
64
65// check unique interaction by name or by code
66#define UNIQINTR
67
68// possible extensions of the program
69// #define ORBITS
70
71// reverse direction of an edge of agraph when anti-particle flows on it.
72// In this case the direction of edges will be diffrent
73// from ones of original mgraph.
74// #define EDGEPORDER
75
76//--------------------------------------------------------------
77#include "grcc.h"
78
79#ifdef GRCC_NAMESPACE
80using namespace Grcc;
81#endif
82
83#define MAXSTR 1024
84
85//--------------------------------------------------------------
86// Macro functions
87#define CLWIGHTD(x) (5*(x))
88#define CLWIGHTO(x) (3*(x)-2)
89#define MAXSTRLEN 81
90
91#define MASK(n) ((1ul) << (n))
92
93#define BOOLSTR(x) ((x) ? "True" : "False")
94
95//--------------------------------------------------------------
96// Static variables
97
98static OptDef optDef0[] = {
99 {"Step", "Generate particle assigned graphs", GRCC_AGraph, 0},
100 {"Outgrf", "Output to file (out.grf)", False, 0},
101 {"Outgrp", "Output to file (out.grp)", False, 0},
102 {"OPI", "Only 1PI graphs", True , 0},
103 {"NoSelfLoop", "Exclude graphs with loops consist of 1 edge", True , 0},
104 {"NoTadpole", "Exclude graphs with tadpoles (2 edge connected)", True , 0},
105 {"No1PtBlock", "Exclude graphs with tadpole blocks (2 node connected)", False, 0},
106 {"No2PtL1PI", "Exclude graphs with 2-point subgraphs", False, 0},
107 {"NoExtSelf", "Exclude graphs with 2-pt subgraphs at ext. particles", False, 0},
108 {"NoAdj2PtV", "Exclude graphs with an edge connecting 2-pt vertices", False, 0},
109 {"Block", "Exclude graphs with more than one block", False, 0},
110 {"NoMultiEdge","Exclude graphs with multi-edges", False, 0},
111 {"SymmInitial","Symmetrize initial particles", False, 0},
112 {"SymmFinal", "Symmetrize final particles", False, 0},
113};
114static OptDef optDef1[] = {
115 {"Step", "Generate particle assigned graphs", GRCC_AGraph, 0},
116 {"Outgrf", "Ouput to file (out.grf)", False, 0},
117 {"Outgrp", "Ouput to file (out.grp)", False, 0},
118 {"OPI", "Only 1PI graphs", False, 0},
119 {"NoSelfLoop", "Exclude graphs with loops consist of 1 edge", False, 0},
120 {"NoTadpole", "Exclude graphs with tadpoles (2 edge connected)", False, 0},
121 {"No1PtBlock", "Exclude graphs with tadpole blocks (2 node connected)", False, 0},
122 {"No2PtL1PI", "Exclude graphs with 2-point subgraphs", False, 0},
123 {"NoExtSelf", "Exclude graphs with 2-pt subgraphs at ext. particles", False, 0},
124 {"NoAdj2PtV", "Exclude graphs with an edge connecting 2-pt vertices", False, 0},
125 {"Block", "Exclude graphs with more than one block", False, 0},
126 {"NoMultiEdge","Exclude graphs with multi-edges", False, 0},
127 {"SymmInitial","Symmetrize initial particles", False, 0},
128 {"SymmFinal", "Symmetrize final particles", False, 0},
129};
130#ifdef OLDDEFAULT
131static OptDef *optDef = &(optDef0[0]);
132static int nOptDef = sizeof(optDef0)/sizeof(OptDef);
133#else
134static OptDef *optDef = &(optDef1[0]);
135static int nOptDef = sizeof(optDef1)/sizeof(OptDef);
136#endif
137
138
139static OptQGDef optQGDef[] = {
140 {"onepi", "onepr", "one-particle illreducible"},
141 {"onshell", "offshell", "without self-energy part at external particles"},
142 {"nosigma", "sigma", "no 2-point functions"},
143 {"nosnail", "snail", "without snail"},
144 {"notadpole", "tadpole", "without tadpole"},
145 {"simple", "notsimple", "without self-loop nor multi-edge"},
146 {"bipart", "nonbipart", "only bipartite graph"},
147 {"cycli", "cyclr", "???"},
148 {"floop", "", "without fermion loops of odd length"},
149#ifdef GRCC_QGRAF_OPT_TOPOL
150 {"topol", "?", "topology"},
151#endif
152};
153
154static int nOptQGDef = sizeof(optQGDef)/sizeof(OptQGDef);
155
156static int prlevel = 2;
157static ErExit *erExit = NULL;
158static void *erExitArg = NULL;
159
160//**************************************************************
161// Utility functions
162//==============================================================
163
164static void grcc_fprintf(FILE* out, const char* fmt, ...);
165static void erEnd(const char *msg);
166static Bool nextPart(int nelem, int nclist, int *clist, int *nl, int *r);
167static void prilist(int n, const int *a, const char *msg);
168static int *newArray(int size, int val);
169static int *deleteArray(int *a);
170static int **newMat(int n0, int n1, int val);
171static int **deleteMat(int **m, int n0);
172static void prIntArray(int n, int *p, const char *msg);
173static void prIntArrayErr(int n, int *p, const char *msg);
174static int *intdup(int n, int *v);
175static int *delintdup(int *v);
176static void bsort(int n, int *ord, int *a);
177static void sorti(int n, int *a);
178static int sortb(int n, int *a);
179static int toSList(int n, int *a);
180static int intSetAdd(int n, int *a, int v, const int size);
181static int intSListAdd(int n, int *a, int v, const int size);
182static int cmpArray(int na, int *a, int nb, int *b);
183static Bool leqArray(int n, int *a, int *b);
184static void prMomStr(int mom, const char *ms, int mn);
185static void listDiff(int na, int *a, int nb, int *b, int *np, int *p, int *nq, int *q, int *nr, int *r);
186static Bool isSubSList(int na, int *a, int nb, int *b);
187static int subtrSet(int na, int *a, int nb, int *b, int *c, int size);
188static int nextPerm(int nelem, int nclass, int *cl, int *r, int *q, int *p, int count);
189static BigInt ipow(int n, int p);
190static BigInt factorial(int n);
191
192// for debugging
193#ifdef CHECK
194static Bool isIn(int n, int *a, int v);
195#endif
196
197//==============================================================
198// class Options
199//--------------------------------------------------------------
200Options::Options(void)
201{
202 if (nOptDef != GRCC_OPT_Size) {
203 grcc_fprintf(GRCC_Stderr, "*** Options: inconsistent default values\n");
204 grcc_fprintf(GRCC_Stderr, "nOptDef=%d, GRCC_OPT_Size=%d\n",
205 nOptDef, GRCC_OPT_Size);
206 GRCC_ABORT();
207 }
208
209 model = NULL;
210 proc = NULL;
211 sproc = NULL;
212
213 outmg = NULL;
214 endmg = NULL;
215 outag = NULL;
216
217 argmg = NULL;
218 argemg = NULL;
219 argag = NULL;
220
221 setDefaultValues();
222
223 // QGraf options
224 if (nOptQGDef != GRCC_QGRAF_OPT_Size) {
225 grcc_fprintf(GRCC_Stderr, "*** Options: inconsistent default values\n");
226 grcc_fprintf(GRCC_Stderr, "nOptQGDef=%d, GRCC_QGRAF_OPT_Size=%d\n",
227 nOptQGDef, GRCC_QGRAF_OPT_Size);
228 GRCC_ABORT();
229 }
230 nqgopt = 0;
231 for (int j = 0; j < nOptQGDef; j++) {
232 qgref[nqgopt].name = optQGDef[j].name;
233 qgref[nqgopt].index = j;
234 qgref[nqgopt].sign = +1;
235 nqgopt++;
236 if (strlen(optQGDef[j].cname) > 0) {
237 qgref[nqgopt].name = optQGDef[j].cname;
238 qgref[nqgopt].index = j;
239 qgref[nqgopt].sign = -1;
240 nqgopt++;
241 }
242 }
243
244 // default values
245 for (int j = 0; j < GRCC_QGRAF_OPT_Size; j++) {
246 qgopt[j] = 0;
247 }
248
249 // for output
250 out = new Output(this);
251
252 // subrpocess
253 sproc = NULL;
254
255 // measuring time
256 time0 = 0.0;
257 time1 = 0.0;
258}
259
260//--------------------------------------------------------------
261Options::~Options(void)
262{
263 outmg = NULL;
264 outag = NULL;
265
266 argmg = NULL;
267 argag = NULL;
268
269 delete out;
270}
271
272//--------------------------------------------------------------
273void Options::setDefaultValues(void)
274{
275 int j;
276
277 // default values
278 for (j = 0; j < GRCC_OPT_Size; j++) {
279 values[j] = optDef[j].defaultv;
280 }
281
282 values[GRCC_OPT_Step] = GRCC_AGraph;
283
284 // print level
285 prlevel = 1;
286}
287
288//--------------------------------------------------------------
289void Options::setOldDefaultValues(void)
290{
291 int j;
292
293 // default values
294 for (j = 0; j < GRCC_OPT_Size; j++) {
295 values[j] = optDef0[j].defaultv;
296 }
297
298 values[GRCC_OPT_Step] = GRCC_AGraph;
299
300 // print level
301 prlevel = 1;
302}
303
304//--------------------------------------------------------------
305void Options::setOutMG(OutEGB *omg, void *pt)
306{
307 outmg = omg;
308 argmg = pt;
309}
310
311//--------------------------------------------------------------
312void Options::setEndMG(OutEGB *emg, void *pt)
313{
314 endmg = emg;
315 argemg = pt;
316}
317
318//--------------------------------------------------------------
319void Options::setOutAG(OutEG *oag, void *pt)
320{
321 outag = oag;
322 argag = pt;
323}
324
325//--------------------------------------------------------------
326void Options::setErExit(ErExit *ere, void *erearg)
327{
328 erExit = ere;
329 erExitArg = erearg;
330}
331
332//--------------------------------------------------------------
333void Options::printLevel(int l)
334{
335 prlevel = l;
336}
337
338//--------------------------------------------------------------
339void Options::setValue(int ind, int val)
340{
341 if (0 <= ind && ind < GRCC_OPT_Size) {
342 values[ind] = val;
343 } else {
344 if (prlevel > 0) {
345 grcc_fprintf(GRCC_Stderr, "*** Options::setValue : invalid index=%d ",
346 ind);
347 grcc_fprintf(GRCC_Stderr, "(val=%d)\n", val);
348 }
349 erEnd("Options::setValue : invalid index");
350 }
351}
352
353//--------------------------------------------------------------
354int Options::getValue(int ind)
355{
356 if (0 <= ind && ind < GRCC_OPT_Size) {
357 return values[ind];
358 } else {
359 if (prlevel > 0) {
360 grcc_fprintf(GRCC_Stderr, "*** Options::getValue : invalid index=%d\n", ind);
361 }
362 erEnd("Options::getValue : invalid index");
363 }
364 return -1;
365}
366
367//--------------------------------------------------------------
368void Options::setQGrafOpt(int *qg)
369{
370 // reset options : default is to generate all connected graphs
371
372#ifdef OLDDEFAULT
373 values[GRCC_OPT_1PI] = False;
374 values[GRCC_OPT_NoSelfLoop] = False;
375 values[GRCC_OPT_NoTadpole] = False;
376 values[GRCC_OPT_No1PtBlock] = False;
377 values[GRCC_OPT_No2PtL1PI] = False;
378 values[GRCC_OPT_NoExtSelf] = False;
379 values[GRCC_OPT_NoAdj2PtV] = False;
380 values[GRCC_OPT_Block] = False;
381 values[GRCC_OPT_SymmInitial] = False;
382 values[GRCC_OPT_SymmFinal] = False;
383#endif
384
385 for (int j = 0; j < GRCC_QGRAF_OPT_Size; j++) {
386 qgopt[j] = qg[j];
387 }
388
389 // {"onepi", "onepr"},
390 if (qgopt[GRCC_QGRAF_OPT_ONEPI] > 0) {
391 values[GRCC_OPT_1PI] = True;
392 } else if (qgopt[GRCC_QGRAF_OPT_ONEPI] < 0) {
393 values[GRCC_OPT_1PI] = False;
394 }
395
396 // {"onshell", "offshell"}
397 if (qgopt[GRCC_QGRAF_OPT_ONSHELL] > 0) {
398 values[GRCC_OPT_NoExtSelf] = 1;
399 } else if (qgopt[GRCC_QGRAF_OPT_ONSHELL] < 0) {
400 values[GRCC_OPT_NoExtSelf] = 0;
401 }
402
403 // {"nosigma", "sigma"}
404
405 // {"nosnail", "snail"},
406 if (qgopt[GRCC_QGRAF_OPT_NOSNAIL] > 0) {
407 values[GRCC_OPT_NoTadpole] = True;
408 values[GRCC_OPT_No1PtBlock] = True;
409 } else if (qgopt[GRCC_QGRAF_OPT_NOSNAIL] < 0) {
410 values[GRCC_OPT_NoTadpole] = False;
411 values[GRCC_OPT_No1PtBlock] = False;
412 }
413
414 // {"notadpole", "tadpole"}
415 if (qgopt[GRCC_QGRAF_OPT_NOTADPOLE] > 0) {
416 values[GRCC_OPT_NoTadpole] = True;
417 } else if (qgopt[GRCC_QGRAF_OPT_NOTADPOLE] < 0) {
418 values[GRCC_OPT_NoTadpole] = False;
419 }
420
421 // {"simple", "notsimple"},
422 if (qgopt[GRCC_QGRAF_OPT_SIMPLE] > 0) {
423 values[GRCC_OPT_NoSelfLoop] = True;
424 values[GRCC_OPT_NoMultiEdge] = True;
425 } else if (qgopt[GRCC_QGRAF_OPT_SIMPLE] < 0) {
426 values[GRCC_OPT_NoSelfLoop] = False;
427 values[GRCC_OPT_NoMultiEdge] = False;
428 }
429
430 // {"bipart", "nonbipart"},
431 // {"cycli", "cyclr"},
432
433#ifdef GRCC_QGRAF_OPT_TOPOL
434 // {"topol", ""},
435 if (qgopt[GRCC_QGRAF_OPT_TOPOL] > 0) {
436 values[GRCC_OPT_SymmInitial] = True;
437 values[GRCC_OPT_SymmFinal] = True;
438 }
439#endif
440}
441
442//--------------------------------------------------------------
443void Options::print(void)
444{
445 int j;
446
447 grcc_fprintf(GRCC_Stdout, "Options\n");
448 grcc_fprintf(GRCC_Stdout, "+++ GRCC_OPT_Size=%d, print level=%d: ",
449 GRCC_OPT_Size, prlevel);
450 grcc_fprintf(GRCC_Stdout, "symbol = value (default)\n");
451 for (j=0; j < GRCC_OPT_Size; j++) {
452 grcc_fprintf(GRCC_Stdout, " %4d GRCC_OPT_%-15s = %2d (%2d)\n",
453 j, optDef[j].name, values[j], optDef[j].defaultv);
454 }
455 grcc_fprintf(GRCC_Stdout, " outgrf=%s, outgrp=%s\n", out->outgrf, out->outgrp);
456 grcc_fprintf(GRCC_Stdout, " GRCC_QGRAF_OPT_Size=%d:\n", GRCC_QGRAF_OPT_Size);
457 for (j=0; j < GRCC_QGRAF_OPT_Size; j++) {
458 grcc_fprintf(GRCC_Stdout, " %4d %-10s = %2d\n", j, optQGDef[j].name, qgopt[j]);
459 }
460}
461
462//--------------------------------------------------------------
463const OptDef *Options::getDef(void)
464{
465 return optDef;
466}
467
468//--------------------------------------------------------------
469const OptDef *Options::getOldDef(void)
470{
471 return optDef0;
472}
473
474//--------------------------------------------------------------
475const OptQGDef *Options::getQGDef(void)
476{
477 return optQGDef;
478}
479
480//--------------------------------------------------------------
481void Options::setOutputF(Bool outf, const char *fname)
482{
483 values[GRCC_OPT_Outgrf] = outf;
484 out->setOutgrf(fname);
485}
486
487//--------------------------------------------------------------
488void Options::setOutputP(Bool outp, const char *fname)
489{
490 values[GRCC_OPT_Outgrp] = outp;
491 out->setOutgrp(fname);
492}
493
494//--------------------------------------------------------------
495void Options::printModel(void)
496{
497 if (prlevel > 0) {
498 if (model != NULL) {
499 model->prModel();
500 } else {
501 grcc_fprintf(GRCC_Stdout, "*** model is not defined\n");
502 }
503 }
504}
505
506//--------------------------------------------------------------
507void Options::outModel(void)
508{
509 if (out != NULL && model != NULL) {
510 out->outModelF();
511 out->outModelP();
512 }
513}
514
515//--------------------------------------------------------------
516void Options::begin(Model *mdl)
517{
518 model = mdl;
519 if (out != NULL) {
520 if (values[GRCC_OPT_Outgrf]) {
521 out->outBeginF(model, values[GRCC_OPT_Outgrf]);
522 if (model != NULL) {
523 out->outModelF();
524 }
525 }
526 if (values[GRCC_OPT_Outgrp]) {
527 out->outBeginP(model, values[GRCC_OPT_Outgrp]);
528 if (model != NULL) {
529 out->outModelP();
530 }
531 }
532 }
533}
534
535//--------------------------------------------------------------
536void Options::end(void)
537{
538 if (prlevel > 1) {
539 grcc_fprintf(GRCC_Stdout, "Optimization: ");
540#ifdef SIMPSEL
541 grcc_fprintf(GRCC_Stdout, "SIMPSEL=1 ");
542#else
543 grcc_fprintf(GRCC_Stdout, "SIMPSEL=0 ");
544#endif
545#ifdef MINMAXLEG
546 grcc_fprintf(GRCC_Stdout, "MINMAXLEG=1 ");
547#else
548 grcc_fprintf(GRCC_Stdout, "MINMAXLEG=0 ");
549#endif
550#ifdef OPTEXTONLY
551 grcc_fprintf(GRCC_Stdout, "OPTEXTONLY=1 ");
552#else
553 grcc_fprintf(GRCC_Stdout, "OPTEXTONLY=0 ");
554#endif
555 grcc_fprintf(GRCC_Stdout, "\n");
556 }
557
558 if (out != NULL && values[GRCC_OPT_Outgrf]) {
559 out->outEndF();
560 }
561 if (out != NULL && values[GRCC_OPT_Outgrp]) {
562 out->outEndP();
563 }
564 model = NULL;
565}
566//
567//--------------------------------------------------------------
568void Options::beginProc(Process *prc)
569{
570 proc = prc;
571 if (out != NULL && values[GRCC_OPT_Outgrf]) {
572 out->outProcBeginF(prc);
573 }
574 if (out != NULL && values[GRCC_OPT_Outgrp]) {
575 out->outProcBeginP(prc);
576 }
577 if (proc != NULL) {
578 proc->mgrcount = 0;
579 proc->agrcount = 0;
580 }
581}
582
583//--------------------------------------------------------------
584void Options::endProc(void)
585{
586 int k;
587
588 if (proc == NULL) {
589 if (out != NULL && values[GRCC_OPT_Outgrf]) {
590 out->outProcEndF();
591 }
592 if (out != NULL && values[GRCC_OPT_Outgrp]) {
593 out->outProcEndP();
594 }
595 return;
596 }
597 if (prlevel > 0) {
598 grcc_fprintf(GRCC_Stdout, "\n");
599 grcc_fprintf(GRCC_Stdout, "+++ Proc %d: ext=%d, loop=%d, ",
600 proc->id, proc->nExtern, proc->loop);
601 if (model != NULL) {
602 grcc_fprintf(GRCC_Stdout, "order=");
603 prIntArray(model->ncouple, proc->clist, ": ");
604 model->prParticleArray(proc->ninitl, proc->initlPart, "-->");
605 model->prParticleArray(proc->nfinal, proc->finalPart, "");
606 }
607 grcc_fprintf(GRCC_Stdout, " (%8.2f sec)\n", proc->sec);
608
609
610 grcc_fprintf(GRCC_Stdout, " Proc %d: Total M-Graphs=%ld, M-Graphs=",
611 proc->id, proc->nMGraphs);
612 proc->wMGraphs.print(" (Conn)\n");
613
614 grcc_fprintf(GRCC_Stdout, " Proc %d: Total M-Graphs=%ld, M-Graphs=",
615 proc->id, proc->nMOPI);
616 proc->wMOPI.print(" (1PI)\n");
617
618 grcc_fprintf(GRCC_Stdout, " Proc %d: Total A-Graphs=%ld, A-Graphs=",
619 proc->id, proc->nAGraphs);
620 proc->wAGraphs.print(" (Conn)\n");
621
622 grcc_fprintf(GRCC_Stdout, " Proc %d: Total A-Graphs=%ld, A-Graphs=",
623 proc->id, proc->nAOPI);
624 proc->wAOPI.print(" (1PI)\n");
625
626 grcc_fprintf(GRCC_Stdout, "# { %d,{", proc->ninitl);
627 for (k = 0; k < proc->ninitl; k++) {
628 if (k != 0) {
629 grcc_fprintf(GRCC_Stdout, ", ");
630 }
631 if (proc->model != NULL) {
632 grcc_fprintf(GRCC_Stdout, "\"%s\"", proc->model->particleName(proc->initlPart[k]));
633 } else {
634 grcc_fprintf(GRCC_Stdout, "%d", proc->initlPart[k]);
635 }
636 }
637 grcc_fprintf(GRCC_Stdout, "}, %d,{", proc->nfinal);
638 for (k = 0; k < proc->nfinal; k++) {
639 if (k != 0) {
640 grcc_fprintf(GRCC_Stdout, ", ");
641 }
642 if (proc->model != NULL) {
643 grcc_fprintf(GRCC_Stdout, "\"%s\"", proc->model->particleName(proc->finalPart[k]));
644 } else {
645 grcc_fprintf(GRCC_Stdout, "%d", proc->initlPart[k]);
646 }
647 }
648 grcc_fprintf(GRCC_Stdout, "}, ");
649 if (model != NULL) {
650 grcc_fprintf(GRCC_Stdout, "{");
651 for (k = 0; k < model->ncouple; k++) {
652 if (k != 0) {
653 grcc_fprintf(GRCC_Stdout, ", ");
654 }
655 grcc_fprintf(GRCC_Stdout, "%d", proc->clist[k]);
656 }
657 grcc_fprintf(GRCC_Stdout, "},");
658 }
659 grcc_fprintf(GRCC_Stdout, "},%6ldL,%6ldL,%3ldL, -1.0, %4.2f},\n",
660 proc->nAOPI, proc->wAOPI.num, proc->wAOPI.den, proc->sec);
661 }
662
663 if (out != NULL && values[GRCC_OPT_Outgrf]) {
664 out->outProcEndF();
665 }
666 if (out != NULL && values[GRCC_OPT_Outgrp]) {
667 out->outProcEndP();
668 }
669 proc = NULL;
670}
671
672//--------------------------------------------------------------
673void Options::beginSubProc(SProcess *sprc)
674{
675 sproc = sprc;
676
677 // 'beginProc' is called before
678 if (out != NULL && values[GRCC_OPT_Outgrf]) {
679 out->outSProcBeginF(sprc);
680 }
681 if (out != NULL && values[GRCC_OPT_Outgrp]) {
682 out->outSProcBeginP(sprc);
683 }
684 if (proc != NULL) {
685 return;
686 }
687 if (sprc != NULL) {
688 sproc->mgrcount = 0;
689 sproc->agrcount = 0;
690 }
691}
692
693//--------------------------------------------------------------
694void Options::endSubProc(void)
695{
696 MGraph *mgraph;
697
698 if (sproc == NULL) {
699 if (out != NULL && values[GRCC_OPT_Outgrf]) {
700 out->outProcEndF();
701 }
702 if (out != NULL && values[GRCC_OPT_Outgrp]) {
703 out->outProcEndP();
704 }
705 return;
706 }
707 mgraph = sproc->mgraph;
708 if (sproc != NULL) {
709 sproc->resultMGraph(mgraph->cDiag, mgraph->wscon,
710 mgraph->c1PI, mgraph->wsopi);
711 }
712
713 if (prlevel > 1) {
714 grcc_fprintf(GRCC_Stdout, "\n");
715 grcc_fprintf(GRCC_Stdout, "+++ Subproc %d: ext=%d, loop=%d, nodes=%d, edges=%d\n",
716 sproc->id, sproc->nExtern, sproc->loop,
717 sproc->nNodes, sproc->nEdges);
718
719 grcc_fprintf(GRCC_Stdout, " Subproc %d: Total M-Graphs=%ld, M-Wsum=",
720 sproc->id, sproc->nMGraphs);
721 sproc->wMGraphs.print(" (Conn)\n");
722
723 grcc_fprintf(GRCC_Stdout, " Subproc %d: Total M-Graphs=%ld, M-Wsum=",
724 sproc->id, sproc->nMOPI);
725 sproc->wMOPI.print(" (1PI)\n");
726
727 grcc_fprintf(GRCC_Stdout, " Subproc %d: Total A-Graphs=%ld, A-Wsum=",
728 sproc->id, sproc->nAGraphs);
729 sproc->wAGraphs.print(" (Conn)\n");
730
731 grcc_fprintf(GRCC_Stdout, " Subproc %d: Total A-Graphs=%ld, A-Wsum=",
732 sproc->id, sproc->nAOPI);
733 sproc->wAOPI.print(" (1PI)\n");
734 }
735 if (prlevel > 0) {
736 grcc_fprintf(GRCC_Stdout, "\n");
737 grcc_fprintf(GRCC_Stdout, "* Total %ld MGraphs; %ld 1PI", mgraph->cDiag, mgraph->c1PI);
738 grcc_fprintf(GRCC_Stdout, " wscon = ");
739 mgraph->wscon.print(" ( ");
740 mgraph->wsopi.print(" 1PI)\n");
741
742#ifdef MONITOR
743 grcc_fprintf(GRCC_Stdout, "* refine: %ld\n", mgraph->nCallRefine);
744 grcc_fprintf(GRCC_Stdout, "* discarded for refinement: %ld\n", mgraph->discardRefine);
745 grcc_fprintf(GRCC_Stdout, "* discarded for disconnected: %ld\n", mgraph->discardDisc);
746 grcc_fprintf(GRCC_Stdout, "* discarded for duplication: %ld\n", mgraph->discardIso);
747#endif
748 }
749
750 if (proc != NULL) {
751 return;
752 }
753 if (out != NULL && values[GRCC_OPT_Outgrf]) {
754 out->outProcEndF();
755 }
756 if (out != NULL && values[GRCC_OPT_Outgrp]) {
757 out->outProcEndP();
758 }
759}
760
761//--------------------------------------------------------------
762void Options::newMGraph(MGraph *mgr)
763{
764 MGraph *mgraph = mgr;
765
766 if (proc != NULL) {
767 proc->mgrcount++;
768 mgr->egraph->mId = proc->mgrcount;
769 } else if (sproc != NULL) {
770 sproc->mgrcount++;
771 mgr->egraph->mId = sproc->mgrcount;
772 }
773
774 if (out != NULL
775 && values[GRCC_OPT_Step] == GRCC_MGraph) {
776 if (values[GRCC_OPT_Outgrf]) {
777 out->outEGraphF(mgraph->egraph);
778 }
779 if (values[GRCC_OPT_Outgrp]) {
780 out->outEGraphP(mgraph->egraph);
781 }
782 }
783 if (sproc != NULL) {
784 sproc->endMGraph(mgr);
785 }
786 if (endmg != NULL) {
787 (*endmg)(mgr->egraph, argemg);
788 }
789}
790
791//--------------------------------------------------------------
792void Options::newAGraph(EGraph *egraph)
793{
794 Fraction sf, zr;
795
796 if (proc != NULL) {
797 proc->agrcount++;
798 egraph->sId = proc->agrcount;
799 } else if (sproc != NULL) {
800 sproc->agrcount++;
801 egraph->sId = sproc->agrcount;
802 }
803
804 if (sproc != NULL) {
805 zr = Fraction(0, 1);
806 if ((egraph->nsym)*(egraph->esym) != 0) {
807 sf = Fraction(egraph->extperm, egraph->nsym*egraph->esym);
808 } else {
809 sf = zr;
810 }
811 if (egraph->mgraph->opi) {
812 sproc->resultAGraph(1, sf, 1, sf);
813 } else {
814 sproc->resultAGraph(1, sf, 0, zr);
815 }
816 }
817
818 if (out != NULL && values[GRCC_OPT_Outgrf]) {
819 out->outEGraphF(egraph);
820 }
821 if (out != NULL && values[GRCC_OPT_Outgrp]) {
822 out->outEGraphP(egraph);
823 }
824 if (outag != NULL) {
825 (*outag)(egraph, argag);
826 }
827
828 sproc->endAGraph(egraph);
829}
830
831//==============================================================
832Output::Output(Options *optn)
833{
834 opt = optn;
835 model = NULL;
836 proc = NULL;
837 sproc = NULL;
838 outgrfp = NULL;
839 outgrpp = NULL;
840 procId = -1;
841 outgrf = NULL;
842 outgrp = NULL;
843 outproc = False;
844
845}
846
847//--------------------------------------------------------------
848Output::~Output(void)
849{
850 if (outgrfp != NULL) {
851 if (prlevel > 0) {
852 grcc_fprintf(GRCC_Stderr, "*** file has not been closed : \"%s\"\n",
853 outgrf);
854 }
855 fclose(outgrfp);
856 outgrfp = NULL;
857 erEnd("file has not been closed");
858 }
859 if (outgrf != NULL) {
860 free(outgrf);
861 outgrf = NULL;
862 }
863 if (outgrpp != NULL) {
864 if (prlevel > 0) {
865 grcc_fprintf(GRCC_Stderr, "*** file has not been closed : \"%s\"\n",
866 outgrp);
867 }
868 fclose(outgrpp);
869 outgrpp = NULL;
870 erEnd("file has not been closed");
871 }
872 if (outgrp != NULL) {
873 free(outgrp);
874 outgrp = NULL;
875 }
876}
877
878//--------------------------------------------------------------
879void Output::setOutgrf(const char *fname)
880{
881 if (outgrf != NULL && strcmp(outgrf, fname) == 0) {
882 return;
883 }
884
885 if (outgrf != NULL) {
886 // delete outgrf;
887 free(outgrf);
888 }
889 if (fname == NULL || strlen(fname) < 1) {
890 outgrf = NULL;
891 } else {
892 outgrf = strdup(fname);
893 }
894}
895
896//--------------------------------------------------------------
897void Output::setOutgrp(const char *fname)
898{
899 if (outgrp != NULL && strcmp(outgrp, fname) == 0) {
900 return;
901 }
902
903 if (outgrp != NULL) {
904 free(outgrp);
905 }
906 if (fname == NULL || strlen(fname) < 1) {
907 outgrp = NULL;
908 } else {
909 outgrp = strdup(fname);
910 }
911}
912
913//--------------------------------------------------------------
914Bool Output::outBeginF(Model *mdl, Bool pr)
915{
916 time_t tp;
917 struct tm *tm;
918 char sdate[MAXSTRLEN];
919
920 model = mdl;
921
922 if (outgrf == NULL || strlen(outgrf) < 1) {
923 outgrfp = NULL;
924 return True;
925 } else if (outgrfp != NULL) {
926 if (prlevel > 0) {
927 grcc_fprintf(GRCC_Stderr, "*** outBegin: \"%s\" is already opened\n",
928 outgrf);
929 }
930 erEnd("outBegin: file is already opened\n");
931 }
932
933 if (!pr) {
934 return True;
935 }
936 if ((outgrfp = fopen(outgrf, "w")) == NULL) {
937 if (prlevel > 0) {
938 grcc_fprintf(GRCC_Stderr, "*** outBegin: cannot open %s\n", outgrf);
939 }
940 return False;
941 }
942 tp = time(NULL);
943 tm = localtime(&tp);
944 strftime(sdate, MAXSTRLEN, "%Y/%m/%d %H:%M:%S", tm);
945
946 fprintf(outgrfp, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
947 fprintf(outgrfp, "%% Generated by grcc at \"%s\"\n", sdate);
948 fprintf(outgrfp, "Version={2,2,0,0};\n");
949 if (model != NULL) {
950 fprintf(outgrfp, "Model=\"./%s.mdl\";\n", model->name);
951 } else {
952 fprintf(outgrfp, "Model=\"./Phi34.mdl\";\n");
953 }
954
955
956 return True;
957}
958
959//--------------------------------------------------------------
960Bool Output::outBeginP(Model *mdl, Bool pr)
961{
962 time_t tp;
963 struct tm *tm;
964 char sdate[MAXSTRLEN];
965
966 model = mdl;
967
968 if (outgrp == NULL || strlen(outgrp) < 1) {
969 outgrpp = NULL;
970 return True;
971 } else if (outgrpp != NULL) {
972 if (prlevel > 0) {
973 grcc_fprintf(GRCC_Stderr, "*** outBegin: \"%s\" is already opened\n",
974 outgrp);
975 }
976 erEnd("outBegin: file is already opened\n");
977 }
978
979 if (!pr) {
980 return True;
981 }
982 if ((outgrpp = fopen(outgrp, "w")) == NULL) {
983 if (prlevel > 0) {
984 grcc_fprintf(GRCC_Stderr, "*** outBegin: cannot open %s\n", outgrp);
985 }
986 return False;
987 }
988 tp = time(NULL);
989 tm = localtime(&tp);
990 strftime(sdate, MAXSTRLEN, "%Y/%m/%d %H:%M:%S", tm);
991
992 fprintf(outgrpp, "################################\n");
993 fprintf(outgrpp, "# Generated by 'grcc' at \"%s\"\n", sdate);
994
995 return True;
996}
997
998//--------------------------------------------------------------
999void Output::outEndF(void)
1000{
1001 if (outgrfp == NULL) {
1002 return;
1003 }
1004 fprintf(outgrfp, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
1005 fprintf(outgrfp, "End=1;\n");
1006 fprintf(outgrfp, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
1007 fclose(outgrfp);
1008 outgrfp = NULL;
1009
1010 free(outgrf);
1011 outgrf = NULL;
1012}
1013
1014//--------------------------------------------------------------
1015void Output::outEndP(void)
1016{
1017 if (outgrpp == NULL) {
1018 return;
1019 }
1020 fprintf(outgrpp, "################################\n");
1021 fprintf(outgrpp, "# End\n");
1022 fprintf(outgrpp, "################################\n");
1023 fclose(outgrpp);
1024 outgrpp = NULL;
1025
1026 free(outgrp);
1027 outgrp = NULL;
1028}
1029
1030//--------------------------------------------------------------
1031void Output::outProcBeginF(Process *prc)
1032{
1033 int k, ex;
1034
1035 if (prc == NULL) {
1036 return;
1037 }
1038
1039 proc = prc;
1040 sproc = NULL;
1041 procId = proc->id;
1042
1043 if (outgrfp == NULL) {
1044 return;
1045 }
1046 if (outproc) {
1047 return;
1048 }
1049 outproc = True;
1050
1051 fprintf(outgrfp, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
1052 fprintf(outgrfp, "Process=%d;\n", proc->id);
1053 fprintf(outgrfp, "External=%d;\n", proc->ninitl+proc->nfinal);
1054 for (k = 0, ex = 0; k < proc->ninitl; k++, ex++) {
1055 fprintf(outgrfp, "%4d= initial %s;\n", ex,
1056 proc->model->particleName(proc->initlPart[k]));
1057 }
1058 for (k = 0; k < proc->nfinal; k++, ex++) {
1059 fprintf(outgrfp, "%4d= final %s;\n", ex,
1060 proc->model->particleName(proc->finalPart[k]));
1061 }
1062 fprintf(outgrfp, "Eend;\n");
1063 for (k = 0; k < proc->model->ncouple; k++) {
1064 fprintf(outgrfp, "%s=%d; ", proc->model->cnlist[k], proc->clist[k]);
1065 }
1066 fprintf(outgrfp, "Loop=%d;\n", proc->loop);
1067 fprintf(outgrfp, "OPI=%s;\n", (opt->values[GRCC_OPT_1PI] > 0? "Yes" : "No"));
1068 fprintf(outgrfp, "Assign=%s;\n", (opt->values[GRCC_OPT_Step]==GRCC_AGraph ? "Yes" : "No"));
1069 fprintf(outgrfp, "%% Options : dummy values\n");
1070 fprintf(outgrfp, "Expand=Yes; ExpMin=0; ExpMax=-1;\n");
1071 fprintf(outgrfp, "Block=No; Tadpole=Yes; Extself=Yes;\n");
1072 fprintf(outgrfp, "Selfe=Yes; Countert=No; AnyCT=No;Undefp=No;\n");
1073}
1074
1075//--------------------------------------------------------------
1076void Output::outProcBeginP(Process *prc)
1077{
1078 if (prc == NULL) {
1079 return;
1080 }
1081
1082 proc = prc;
1083 sproc = NULL;
1084 procId = proc->id;
1085
1086 if (outgrpp == NULL) {
1087 return;
1088 }
1089 if (outproc) {
1090 return;
1091 }
1092 outproc = True;
1093
1094 fprintf(outgrpp, "# Process=%d;\n", proc->id);
1095}
1096
1097//--------------------------------------------------------------
1098void Output::outProcBegin0(int next, int couple, int loop)
1099{
1100 int k, ex;
1101
1102 procId = 0;
1103
1104 if (outgrfp == NULL) {
1105 return;
1106 }
1107 if (outproc) {
1108 return;
1109 }
1110 outproc = True;
1111
1112 fprintf(outgrfp, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
1113 fprintf(outgrfp, "Process=%d;\n", procId);
1114 fprintf(outgrfp, "External=%d;\n", next);
1115 int ninit = (next + 1) / 2;
1116 for (k = 0, ex = 0; k < ninit; k++, ex++) {
1117 fprintf(outgrfp, "%4d= initial undef;\n", ex);
1118 }
1119 for (k = 0; k < next - ninit; k++, ex++) {
1120 fprintf(outgrfp, "%4d= final undef;\n", ex);
1121 }
1122 fprintf(outgrfp, "Eend;\n");
1123 fprintf(outgrfp, "GRCC_PHI=%d; ", couple);
1124 // fprintf(outgrfp, "PHI=%d; ", couple);
1125 fprintf(outgrfp, "Loop=%d;\n", loop);
1126 fprintf(outgrfp, "OPI=%s;\n", (opt->values[GRCC_OPT_1PI] > 0? "Yes" : "No"));
1127 fprintf(outgrfp, "Assign=No;\n");
1128 fprintf(outgrfp, "%% Options : dummy values\n");
1129 fprintf(outgrfp, "Expand=Yes; ExpMin=0; ExpMax=-1;\n");
1130 fprintf(outgrfp, "Block=No; Tadpole=Yes; Extself=Yes;\n");
1131 fprintf(outgrfp, "Selfe=Yes; Countert=No; AnyCT=No;Undefp=No;\n");
1132}
1133
1134//--------------------------------------------------------------
1135void Output::outSProcBeginF(SProcess *sprc)
1136{
1137 int j, k, ex;
1138 PNodeClass *pnc;
1139
1140 if (sprc == NULL) {
1141 return;
1142 }
1143
1144 sproc = sprc;
1145 procId = sproc->id;
1146 pnc = sproc->pnclass;
1147
1148 if (outgrfp == NULL) {
1149 return;
1150 }
1151 if (outproc) {
1152 return;
1153 }
1154 outproc = True;
1155 fprintf(outgrfp, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
1156 fprintf(outgrfp, "Process=%d;\n", sproc->id);
1157 fprintf(outgrfp, "External=%d;\n", sproc->nExtern);
1158
1159 ex = 0;
1160 for (j = 0; j < pnc->nclass; j++) {
1161 if (pnc->type[j] == GRCC_AT_Initial) {
1162 for (k = 0; k < pnc->count[j]; k++) {
1163 fprintf(outgrfp, "%4d= initial %s;\n", ex,
1164 model->particleName(pnc->particle[j]));
1165 ex++;
1166 }
1167 } else if (pnc->type[j] == GRCC_AT_Final) {
1168 for (k = 0; k < pnc->count[j]; k++) {
1169 fprintf(outgrfp, "%4d= final %s;\n", ex,
1170 model->particleName(-pnc->particle[j]));
1171 ex++;
1172 }
1173 }
1174 }
1175
1176 fprintf(outgrfp, "Eend;\n");
1177 for (k = 0; k < sproc->model->ncouple; k++) {
1178 fprintf(outgrfp, "%s=%d; ", sproc->model->cnlist[k], sproc->clist[k]);
1179 }
1180 fprintf(outgrfp, "Loop=%d;\n", sproc->loop);
1181 fprintf(outgrfp, "OPI=%s;\n", (opt->values[GRCC_OPT_1PI] > 0? "Yes" : "No"));
1182 fprintf(outgrfp, "Assign=%s;\n", (opt->values[GRCC_OPT_Step]==GRCC_AGraph ? "Yes" : "No"));
1183 fprintf(outgrfp, "%% Options : dummy values\n");
1184 fprintf(outgrfp, "Expand=Yes; ExpMin=0; ExpMax=-1;\n");
1185 fprintf(outgrfp, "Block=No; Tadpole=Yes; Extself=Yes;\n");
1186 fprintf(outgrfp, "Selfe=Yes; Countert=No; AnyCT=No;Undefp=No;\n");
1187}
1188
1189//--------------------------------------------------------------
1190void Output::outSProcBeginP(SProcess *sprc)
1191{
1192 if (sprc == NULL) {
1193 return;
1194 }
1195
1196 sproc = sprc;
1197 procId = sproc->id;
1198
1199 if (outgrpp == NULL) {
1200 return;
1201 }
1202 if (outproc) {
1203 return;
1204 }
1205 outproc = True;
1206 fprintf(outgrpp, "# SProcess=%d;\n", sproc->id);
1207}
1208
1209//--------------------------------------------------------------
1210void Output::outProcEndF(void)
1211{
1212 if (outgrfp == NULL) {
1213 return;
1214 }
1215 if (proc != NULL) {
1216 fprintf(outgrfp, "%%------------------------------\n");
1217 fprintf(outgrfp, "Pend=%d;\n", proc->id);
1218 } else if (sproc != NULL) {
1219 fprintf(outgrfp, "%%------------------------------\n");
1220 fprintf(outgrfp, "Pend=%d;\n", sproc->id);
1221 } else {
1222 fprintf(outgrfp, "%%------------------------------\n");
1223 fprintf(outgrfp, "Pend=1;\n");
1224 }
1225 fflush(outgrfp);
1226}
1227
1228//--------------------------------------------------------------
1229void Output::outProcEndP(void)
1230{
1231 if (outgrpp == NULL) {
1232 return;
1233 }
1234 fflush(outgrpp);
1235}
1236
1237//--------------------------------------------------------------
1238void Output::outEGraphF(EGraph *egraph)
1239{
1240 int nd, lg, ptcl, ed, intr, j, k, loop;
1241 Model *mdl = egraph->model;
1242 Bool popt;
1243 EFLine *fl;
1244
1245 if (outgrfp == NULL) {
1246 return;
1247 }
1248 fprintf(outgrfp, "%%------------------------------\n");
1249 if (egraph->assigned) {
1250 fprintf(outgrfp, "Graph=%ld;\n", egraph->sId);
1251 fprintf(outgrfp, "%% AGraph=%ld;\n", egraph->aId);
1252 } else {
1253 fprintf(outgrfp, "Graph=%ld;\n", egraph->mId);
1254 }
1255 fprintf(outgrfp, "Gtype=%ld;\n", egraph->mId);
1256 if (egraph->assigned) {
1257 fprintf(outgrfp, "Sfactor=%ld;\n",
1258 egraph->nsym * egraph->esym * egraph->fsign);
1259 } else {
1260 fprintf(outgrfp, "Sfactor=%ld;\n", egraph->nsym * egraph->esym);
1261 }
1262 fprintf(outgrfp, "%% ExtPerm=%ld; NSym=%ld; ESym=%ld; NSym1=%ld;"
1263 " Multp=%ld;\n",
1264 egraph->extperm, egraph->nsym, egraph->esym, egraph->nsym1,
1265 egraph->multp);
1266
1267 fprintf(outgrfp, "Vertex=%d;\n", egraph->nNodes - egraph->nExtern);
1268
1269 for (nd = 0; nd < egraph->nNodes; nd++) {
1270 fprintf(outgrfp, "%4d", nd);
1271 if (mdl != NULL && egraph->assigned && !egraph->isExternal(nd)) {
1272 intr = egraph->nodes[nd]->intrct;
1273 loop = mdl->interacts[intr]->loop;
1274 popt = False;
1275
1276 // not tree vertex
1277 if (loop > 0) {
1278 fprintf(outgrfp, "[loop=%d", loop);
1279 popt = True;
1280 }
1281
1282 // multiple coupling constants
1283 if (mdl->ncouple > 1) {
1284 if (popt) {
1285 fprintf(outgrfp, ";order={");
1286 } else {
1287 fprintf(outgrfp, "[order={");
1288 popt = True;
1289 }
1290 for (j = 0; j < mdl->interacts[intr]->nclist; j++) {
1291 if (j != 0) {
1292 fprintf(outgrfp, ",");
1293 }
1294 fprintf(outgrfp, "%d", mdl->interacts[intr]->clist[j]);
1295 }
1296 fprintf(outgrfp, "}");
1297 }
1298 if (popt) {
1299 fprintf(outgrfp, "]");
1300 }
1301 } else if (!egraph->isExternal(nd)) {
1302 loop = egraph->nodes[nd]->extloop;
1303 // not tree vertex
1304 if (loop > 0) {
1305 fprintf(outgrfp, "[loop=%d]", loop);
1306 }
1307 }
1308 fprintf(outgrfp, "={");
1309
1310 // list of legs
1311 for (lg = 0; lg < egraph->nodes[nd]->deg; lg++) {
1312 if (lg != 0) {
1313 fprintf(outgrfp, ", ");
1314 }
1315 ed = V2Iedge(egraph->nodes[nd]->edges[lg]);
1316 // fprintf(outgrfp, "%4d", egraph->nodes[nd]->edges[lg]);
1317 fprintf(outgrfp, "%4d", abs(egraph->nodes[nd]->edges[lg]));
1318 ptcl = egraph->edges[ed]->ptcl;
1319 if (mdl != NULL && ptcl != 0 && egraph->assigned) {
1320 if (egraph->nodes[nd]->edges[lg] < 0) {
1321 ptcl = mdl->normalParticle(-ptcl);
1322 } else {
1323 ptcl = mdl->normalParticle(ptcl);
1324 }
1325 fprintf(outgrfp, "[%s]", mdl->particleName(ptcl));
1326 } else {
1327 fprintf(outgrfp, "[undef]");
1328 }
1329 }
1330 fprintf(outgrfp, "};\n");
1331 }
1332 // print Fermion line as comment line
1333 if (egraph->nFlines >= 0) {
1334 fprintf(outgrfp, "%% FLines=%d; FSign=%d; sId=%ld;\n",
1335 egraph->nFlines, egraph->fsign, egraph->sId);
1336 }
1337 for (j = 0; j < egraph->nFlines; j++) {
1338 fl = egraph->flines[j];
1339 fprintf(outgrfp, "%% %4d", j);
1340 if (fl->ftype == FL_Open) {
1341 fprintf(outgrfp, "[FOpen]=[");
1342 } else if (fl->ftype == FL_Closed) {
1343 fprintf(outgrfp, "[FLoop]=[");
1344 } else {
1345 fprintf(outgrfp, " ?%d", fl->ftype);
1346 }
1347 for (k = 0; k < fl->nlist; k++) {
1348 if (k != 0) {
1349 fprintf(outgrfp, ", ");
1350 }
1351 fprintf(outgrfp, "%d", fl->elist[k]);
1352 }
1353 fprintf(outgrfp, "];\n");
1354 }
1355 fprintf(outgrfp, "Vend;\n");
1356 fprintf(outgrfp, "Gend;\n");
1357}
1358
1359//--------------------------------------------------------------
1360#ifdef NEWOUTPY
1361void Output::outEGraphP(EGraph *eg)
1362{
1363 if (outgrpp == NULL) {
1364 return;
1365 }
1366
1367 if (eg->assigned) {
1368 grcc_fprintf(GRCC_Stdout, "outEGraphP:egraph:egraph[%ld]\n", eg->mId-1);
1369 eg->printPy(outgrpp, eg->mId);
1370 return;
1371 } else {
1372 grcc_fprintf(GRCC_Stdout, "outEGraphP:mgraph:egraph[%ld]\n", eg->mId-1);
1373 eg->mgraph->printPy(outgrpp, eg->mId);
1374 return;
1375 }
1376}
1377#else
1378void Output::outEGraphP(EGraph *eg)
1379{
1380 int j, nd, lg, ed, k;
1381 ENode *node;
1382 static char undef[] = "Undef";
1383 char *s;
1384 EFLine *fl;
1385
1386 if (outgrpp == NULL) {
1387 return;
1388 }
1389
1390 if (eg->assigned) {
1391 fprintf(outgrpp, "egraph[%ld] = {\n", eg->sId-1);
1392 } else {
1393 fprintf(outgrpp, "egraph[%ld] = {\n", eg->mId-1);
1394 }
1395
1396 // process
1397 if (proc != NULL) {
1398 fprintf(outgrpp, " \"Process\": {\n");
1399 proc->outProcP(outgrpp);
1400 fprintf(outgrpp, " },\n");
1401 }
1402
1403 // graph
1404 fprintf(outgrpp, " \"GId\": [%ld, %ld, %ld],\n",
1405 eg->mId, eg->aId, eg->sId);
1406 fprintf(outgrpp, " \"GParam\": {\"Assigned\":%d, "
1407 "\"NNodes\":%d, \"NEdges\":%d, \"NFLines\":%d},\n",
1408 eg->assigned, eg->nNodes, eg->nEdges, eg->nFlines);
1409 fprintf(outgrpp, " \"Sym\": {\"FSign\":%d, \"NSym\":%ld, "
1410 "\"ESym\":%ld, \"NSym1\":%ld, \"Multp\":%ld},\n",
1411 eg->fsign, eg->nsym, eg->esym, eg->nsym1, eg->multp);
1412
1413 // nodes
1414 fprintf(outgrpp, " \"Nodes\": [\n");
1415 for (nd = 0; nd < eg->nNodes; nd++) {
1416 node = eg->nodes[nd];
1417 if (model==NULL) {
1418 s = undef;
1419 } else if(!eg->assigned) {
1420 if (eg->isExternal(nd)) {
1421 ed = Abs(eg->nodes[nd]->edges[0])-1;
1422 s = model->particleName(eg->edges[ed]->ptcl);
1423 } else {
1424 s = undef;
1425 }
1426 } else if (eg->isExternal(nd)) {
1427 s = model->particleName(node->intrct);
1428 } else {
1429 s = model->interacts[node->intrct]->name;
1430 }
1431 fprintf(outgrpp, " [%d, \"%s\", %d, [",
1432 nd, s, node->extloop);
1433 for (lg = 0; lg < eg->nodes[nd]->deg; lg++) {
1434 if (lg != 0) {
1435 fprintf(outgrpp, ", ");
1436 }
1437 fprintf(outgrpp, "%d", eg->nodes[nd]->edges[lg]);
1438 }
1439 fprintf(outgrpp, "]],\n");
1440 }
1441 fprintf(outgrpp, " ],\n");
1442
1443 // edges
1444 fprintf(outgrpp, " \"Edges\": [\n");
1445 for (ed = 0; ed < eg->nEdges; ed++) {
1446 if (model != NULL) {
1447 s = model->particleName(eg->edges[ed]->ptcl);
1448 fprintf(outgrpp, " [%d, \"%s\", [%d, %d]],\n",
1449 ed+1, s, eg->edges[ed]->nodes[0],
1450 eg->edges[ed]->nodes[1]);
1451 } else {
1452 fprintf(outgrpp, " [%d, \"Undef\", [%d, %d]],\n",
1453 ed+1, eg->edges[ed]->nodes[0],
1454 eg->edges[ed]->nodes[1]);
1455 }
1456 }
1457
1458 fprintf(outgrpp, " ],\n");
1459
1460 if (eg->nFlines >= 0) {
1461 // print Fermion line as comment line
1462 fprintf(outgrpp, " \"FLines\": [\n");
1463 for (j = 0; j < eg->nFlines; j++) {
1464 fl = eg->flines[j];
1465 fprintf(outgrpp, " [%d, ", j);
1466 if (fl->ftype == FL_Open) {
1467 fprintf(outgrpp, "\"FOpen\", ");
1468 } else if (fl->ftype == FL_Closed) {
1469 fprintf(outgrpp, "\"FLoop\", ");
1470 } else {
1471 fprintf(outgrpp, "\"Undef%d\", ", fl->ftype);
1472 }
1473 fprintf(outgrpp, "[");
1474 for (k = 0; k < fl->nlist; k++) {
1475 if (k != 0) {
1476 fprintf(outgrpp, ", ");
1477 }
1478 fprintf(outgrpp, "%d", fl->elist[k]);
1479 }
1480 fprintf(outgrpp, "]],\n");
1481 }
1482 fprintf(outgrpp, " ]\n");
1483 }
1484
1485 // end of a graph
1486 fprintf(outgrpp, "};\n");
1487}
1488#endif
1489
1490//--------------------------------------------------------------
1491void Output::outModelF(void)
1492{
1493 char *mdlfn;
1494 FILE *mdlfp;
1495 Particle *pt;
1496 Interaction *vt;
1497 int j, k, l, ln;
1498 const char *ptn;
1499
1500 if (model == NULL) {
1501 if (prlevel > 0) {
1502 grcc_fprintf(GRCC_Stderr, "*** Output::outModel : model is not defined\n");
1503 }
1504 return;
1505 }
1506 ln = strlen(model->name)+5;
1507 mdlfn = new char[ln];
1508 snprintf(mdlfn, ln, "%s.mdl", model->name);
1509
1510 if ((mdlfp = fopen(mdlfn, "w")) == NULL) {
1511 if (prlevel > 0) {
1512 grcc_fprintf(GRCC_Stderr, "*** Output::outModel : cannot open \"%s\"\n",
1513 mdlfn);
1514 }
1515 return;
1516 }
1517
1518 for (l = 0; l < 60; l++) { putc('%', mdlfp); } putc('\n', mdlfp);
1519 fprintf(mdlfp, "%% File \"%s\"\n", mdlfn);
1520 fprintf(mdlfp, "%% Generated by graph generater\n");
1521 fprintf(mdlfp, " Version={2,2,0};\n");
1522
1523 // copupling constants
1524 fprintf(mdlfp, " Order={");
1525 for (j = 0; j < model->ncouple; j++) {
1526 if (j != 0) {
1527 fprintf(mdlfp, ", ");
1528 }
1529 fprintf(mdlfp, "%s", model->cnlist[j]);
1530 }
1531 fprintf(mdlfp, "};\n");
1532
1533 for (l = 0; l < 60; l++) { putc('%', mdlfp); } putc('\n', mdlfp);
1534 fprintf(mdlfp, "%% particles\n");
1535 for (l = 0; l < 60; l++) { putc('%', mdlfp); } putc('\n', mdlfp);
1536 for (j = 1; j < model->nParticles; j++) {
1537 pt = model->particles[j];
1538 fprintf(mdlfp, " Particle=%s; Antiparticle=%s;\n",
1539 pt->name, pt->aname);
1540 ptn = pt->typeGName();
1541 fprintf(mdlfp, " PType=%s; Charge=0; Color=1; Mass=0; Width=0;\n", ptn);
1542 fprintf(mdlfp, " PCode=%d; Massless; \n", pt->pcode);
1543 fprintf(mdlfp, " Pend;\n");
1544 fprintf(mdlfp, "%%\n");
1545 }
1546 for (l = 0; l < 60; l++) { putc('%', mdlfp); } putc('\n', mdlfp);
1547 fprintf(mdlfp, "%% interactions\n");
1548 for (l = 0; l < 60; l++) { putc('%', mdlfp); } putc('\n', mdlfp);
1549 for (j = 0; j < model->nInteracts; j++) {
1550 vt = model->interacts[j];
1551 fprintf(mdlfp, " Vertex={");
1552 for (k = 0; k < vt->nplist; k++) {
1553 if (k != 0) {
1554 fprintf(mdlfp, ", ");
1555 }
1556 fprintf(mdlfp, "%s", model->particleName(vt->plist[k]));
1557 }
1558 fprintf(mdlfp, "}; ");
1559 for (k = 0; k < model->ncouple; k++) {
1560 fprintf(mdlfp, "%s=%d; ", model->cnlist[k], vt->clist[k]);
1561 }
1562 fprintf(mdlfp, "FName=%s; Vend;\n", vt->name);
1563 }
1564 for (l = 0; l < 60; l++) { putc('%', mdlfp); } putc('\n', mdlfp);
1565 fprintf(mdlfp, " Mend;\n");
1566 for (l = 0; l < 60; l++) { putc('%', mdlfp); } putc('\n', mdlfp);
1567 fclose(mdlfp);
1568 delete[] mdlfn;
1569}
1570
1571//--------------------------------------------------------------
1572void Output::outModelP(void)
1573{
1574 char *mdlfn;
1575 FILE *mdlfp;
1576 Particle *pt;
1577 Interaction *vt;
1578 int j, k, l, ln;
1579 const char *ptn;
1580
1581 if (model == NULL) {
1582 if (prlevel > 0) {
1583 grcc_fprintf(GRCC_Stderr, "*** Output::outModel : ");
1584 grcc_fprintf(GRCC_Stderr, "model is not defined\n");
1585 }
1586 return;
1587 }
1588 ln = strlen(model->name)+5;
1589 mdlfn = new char[ln];
1590 snprintf(mdlfn, ln, "%s.mdp", model->name);
1591
1592 if ((mdlfp = fopen(mdlfn, "w")) == NULL) {
1593 if (prlevel > 0) {
1594 grcc_fprintf(GRCC_Stderr, "*** Output::outModel : cannot open \"%s\"\n",
1595 mdlfn);
1596 }
1597 return;
1598 }
1599
1600 for (l = 0; l < 60; l++) { putc('#', mdlfp); } putc('\n', mdlfp);
1601 fprintf(mdlfp, "# File \"%s\"\n", mdlfn);
1602 fprintf(mdlfp, "# Generated by graph generater grcc\n");
1603
1604 // copupling constants
1605 fprintf(mdlfp, "Model={\n");
1606 fprintf(mdlfp, " \"Model\": [");
1607 fprintf(mdlfp, "\"%s\", %d, [",
1608 model->name, model->ncouple);
1609 for (j = 0; j < model->ncouple; j++) {
1610 if (j != 0) {
1611 fprintf(mdlfp, ", ");
1612 }
1613 fprintf(mdlfp, "\"%s\"", model->cnlist[j]);
1614 }
1615 fprintf(mdlfp, "], ");
1616 if (model->defpart == GRCC_DEFBYCODE) {
1617 fprintf(mdlfp, "\"ByCode\"");
1618 } else {
1619 fprintf(mdlfp, "\"ByName\"");
1620 }
1621 fprintf(mdlfp, "],\n");
1622
1623 fprintf(mdlfp, " \"Particles\": [\n");
1624 for (j = 1; j < model->nParticles; j++) {
1625 pt = model->particles[j];
1626 ptn = pt->typeName();
1627 fprintf(mdlfp, " [\"%s\", %d, \"%s\", %d, \"%s\", %d],\n",
1628 pt->name, pt->pcode, pt->aname, pt->acode,
1629 ptn, pt->extonly);
1630 }
1631 fprintf(mdlfp, " ],\n");
1632 fprintf(mdlfp, " \"Interactions\": [\n");
1633 for (j = 0; j < model->nInteracts; j++) {
1634 vt = model->interacts[j];
1635 fprintf(mdlfp, " [\"%s\", %d, %d, [", vt->name, vt->id, vt->nplist);
1636 for (k = 0; k < vt->nplist; k++) {
1637 if (k != 0) {
1638 fprintf(mdlfp, ", ");
1639 }
1640 if (model->defpart == GRCC_DEFBYCODE) {
1641 fprintf(mdlfp, "%d", vt->plist[k]);
1642 } else {
1643 fprintf(mdlfp, "\"%s\"", model->particleName(vt->plist[k]));
1644 }
1645 }
1646 fprintf(mdlfp, "], [");
1647 for (k = 0; k < model->ncouple; k++) {
1648 if (k != 0) {
1649 fprintf(mdlfp, ",");
1650 }
1651 fprintf(mdlfp, "%d", vt->clist[k]);
1652 }
1653 fprintf(mdlfp, "]],\n");
1654 }
1655 fprintf(mdlfp, " ],\n");
1656 fprintf(mdlfp, "};\n");
1657 fclose(mdlfp);
1658 delete[] mdlfn;
1659}
1660
1661//**************************************************************
1662// model.cc
1663
1664//==============================================================
1665
1666static const char *ptypenames[] = GRCC_PT_Table;
1667static const char *pgtypenames[] = GRCC_PT_GTable;
1668
1669//==============================================================
1670// class Particle
1671//--------------------------------------------------------------
1672Particle::Particle(Model *modl, int pid, PInput *pinp)
1673{
1674 static char buff[100];
1675 static int nbuff=100;
1676 int j;
1677
1678 mdl = modl; // the model
1679 id = pid; // id of this particle
1680 if (pinp->name == NULL || strlen(pinp->name) < 1) {
1681 if (pinp->pcode != 0) {
1682 snprintf(buff, nbuff, "pa%d", pinp->pcode);
1683 name = strdup(buff);
1684 } else {
1685 snprintf(buff, nbuff, "pi%d", pid);
1686 name = strdup(buff);
1687 }
1688 } else {
1689 name = strdup(pinp->name); // the name of the particle
1690 }
1691 if (pinp->aname == NULL) {
1692 if (pinp->acode != 0) {
1693 snprintf(buff, nbuff, "ap%d", Abs(pinp->acode));
1694 aname = strdup(buff);
1695 } else {
1696 snprintf(buff, nbuff, "ai%d", pid);
1697 aname = strdup(buff);
1698 }
1699 } else {
1700 aname = strdup(pinp->aname); // the name of the anti-particle
1701 }
1702 pcode = pinp->pcode;
1703 acode = pinp->acode;
1704 if (Abs(mdl->defpart) == GRCC_DEFBYCODE) {
1705 neutral = (pcode == acode);
1706 } else if (Abs(mdl->defpart) == GRCC_DEFBYNAME) {
1707 neutral = ((strcmp(name, aname)==0) ? True : False);
1708 }
1709
1710 // convert ptype string to its code.
1711 if (Abs(mdl->defpart) == GRCC_DEFBYCODE) {
1712 if (pinp->ptypec < GRCC_PT_Undef || pinp->ptypec > GRCC_PT_Size) {
1713 if (prlevel > 0) {
1714 grcc_fprintf(GRCC_Stderr, "*** particle type is not defined: %d\n",
1715 pinp->ptypec);
1716 }
1717 erEnd("particle type is not defined (illegal code)");
1718 }
1719 ptype = pinp->ptypec;
1720 } else if (Abs(mdl->defpart) == GRCC_DEFBYNAME) {
1721 if (pinp->ptypen == NULL) {
1722 erEnd("particle type is not defined (NULL)");
1723 }
1724 ptype = -1;
1725 for (j = 0; j < GRCC_PT_Size; j++) {
1726 if (strcmp(pinp->ptypen, ptypenames[j]) == 0) {
1727 ptype = j;
1728 break;
1729 }
1730 }
1731 if (ptype < 0) {
1732 if (prlevel > 0) {
1733 grcc_fprintf(GRCC_Stderr, "*** particle type \"%s\" is not defined\n",
1734 pinp->ptypen);
1735 }
1736 erEnd("particle type is not defined (name)");
1737 }
1738 }
1739 if (ptype == GRCC_PT_Undef && ptype != 0) {
1740 erEnd("illegal ptype");
1741 }
1742
1743 extonly = pinp->extonly;
1744 cmindeg = 0;
1745 cmaxdeg = 0;
1746}
1747
1748//--------------------------------------------------------------
1749Particle::~Particle(void)
1750{
1751 free(aname);
1752 free(name);
1753}
1754
1755//--------------------------------------------------------------
1756char *Particle::particleName(int p)
1757{
1758 if (p < 0) {
1759 return aname;
1760 } else {
1761 return name;
1762 }
1763}
1764
1765//--------------------------------------------------------------
1766int Particle::particleCode(int p)
1767{
1768 if (p < 0) {
1769 return acode;
1770 } else {
1771 return pcode;
1772 }
1773}
1774
1775//--------------------------------------------------------------
1776int Particle::isNeutral(void)
1777{
1778 return neutral;
1779}
1780
1781//--------------------------------------------------------------
1782const char *Particle::typeName(void)
1783{
1784 return ptypenames[ptype];
1785}
1786
1787//--------------------------------------------------------------
1788const char *Particle::typeGName(void)
1789{
1790 return pgtypenames[ptype];
1791}
1792
1793//--------------------------------------------------------------
1794char *Particle::aparticle(void)
1795{
1796 static char prtcl[] = "Particle";
1797
1798 if (isNeutral()) {
1799 return prtcl;
1800 } else {
1801 return aname;
1802 }
1803}
1804
1805//--------------------------------------------------------------
1806void Particle::prParticle(void)
1807{
1808 if (isNeutral()) {
1809 grcc_fprintf(GRCC_Stdout, "pid=%d, name=\"%s\", real_field, ", id, name);
1810 } else {
1811 grcc_fprintf(GRCC_Stdout, "pid=%d, name=\"%s\", aname=\"%s\", ", id, name, aname);
1812 }
1813 grcc_fprintf(GRCC_Stdout, "ptype=%s, pcode=%d, acode=%d, extonly=%d, cdeg=(%d,%d)\n",
1814 ptypenames[ptype], pcode, acode, extonly, cmindeg, cmaxdeg);
1815}
1816
1817//==============================================================
1818// class Interaction
1819//--------------------------------------------------------------
1820Interaction::Interaction(Model *modl, int iid, const char *nam, int icd, int *cpl, int nlgs, int *plst, int csm, int lp)
1821{
1822 static char buff[100];
1823 static int nbuff=100;
1824 static Bool prmsg = True;
1825 Particle *p;
1826 int j, ndir, sdir, jdir, nmaj, jmaj, ngho, sgho, jgho, ptcl;
1827 Bool ok;
1828
1829 mdl = modl; // the model
1830 id = iid; // id of this interaction
1831 icode = icd; // id of this interaction
1832 csum = csm; // the total orders of coupling constants
1833 nlegs = nlgs; // the size of plist[]
1834 loop = lp; // the number of loops
1835
1836 if (nam == NULL || strlen(nam) < 1) {
1837 snprintf(buff, nbuff, "vt%d", icd);
1838 name = strdup(buff);
1839 } else {
1840 name = strdup(nam); // the name of the interaction
1841 }
1842 nclist = mdl->ncouple;
1843 clist = new int[nclist];
1844 icode = icd;
1845 for (j = 0; j < mdl->ncouple; j++) {
1846 clist[j] = cpl[j];
1847 }
1848 plist = new int[nlegs];
1849 nplist = nlegs;
1850 for (j = 0; j < nlegs; j++) {
1851 plist[j] = plst[j];
1852 }
1853 nslist = 0;
1854 slist = NULL;
1855
1856 // check fermion number conservation
1857 ndir = 0;
1858 sdir = 0;
1859 jdir = 0;
1860 nmaj = 0;
1861 jmaj = 0;
1862 ngho = 0;
1863 sgho = 0;
1864 jgho = 0;
1865 ok = True;
1866 for (j = 0; j < nplist; j++) {
1867 if (plist[j] > 0) {
1868 p = mdl->particles[plist[j]];
1869 ptcl = 1;
1870 } else {
1871 p = mdl->particles[-plist[j]];
1872 ptcl = -1;
1873 }
1874
1875 if (p->ptype == GRCC_PT_Dirac) {
1876 ndir++;
1877 if (ptcl > 0) {
1878 sdir++;
1879 } else {
1880 sdir--;
1881 }
1882 if (Abs(sdir) == 1) {
1883 jdir = j;
1884 } else if ((Abs(sdir) == 0 && j != jdir + 1) || Abs(sdir) > 1) {
1885 grcc_fprintf(GRCC_Stderr, "*** Interaction: Dirac and anti-Dirac should "
1886 "arranged in pairs in an interaction.\n");
1887 ok = False;
1888 }
1889 } else if (p->ptype == GRCC_PT_Ghost) {
1890 ngho++;
1891 if (ptcl > 0) {
1892 sgho++;
1893 } else {
1894 sgho--;
1895 }
1896 if (Abs(sgho) == 1) {
1897 jgho = j;
1898 } else if ((Abs(sgho) == 0 && j != jgho + 1) || Abs(sgho) > 1) {
1899 grcc_fprintf(GRCC_Stderr, "*** Interaction: Ghost and anti-Ghost should "
1900 "arranged in pairs in an interaction.\n");
1901 ok = False;
1902 }
1903 } else if (p->ptype == GRCC_PT_Majorana) {
1904 nmaj++;
1905 if (nmaj % 2 == 1) {
1906 jmaj = j;
1907 } else if (j != jmaj + 1) {
1908 grcc_fprintf(GRCC_Stderr, "*** Interaction: two Majoranas should "
1909 "arranged in pairs in an interaction.\n");
1910 ok = False;
1911 }
1912 }
1913 }
1914 if (sdir != 0) {
1915 grcc_fprintf(GRCC_Stderr, "*** Interaction: Dirac number is not conserved\n");
1916 ok = False;
1917 }
1918 if (sgho != 0) {
1919 grcc_fprintf(GRCC_Stderr, "*** Interaction: Ghost number is not conserved\n");
1920 ok = False;
1921 }
1922 if (nmaj % 2 != 0) {
1923 grcc_fprintf(GRCC_Stderr, "*** Interaction: odd number of Majorana particles\n");
1924 ok = False;
1925 }
1926 if (ndir + nmaj + ngho > 2 && prmsg) {
1927 grcc_fprintf(GRCC_Stderr, "+++ Interaction: more than 2 "
1928 "Dirac/Majorana/Ghost "
1929 "particles are interacting.\n");
1930 grcc_fprintf(GRCC_Stderr, " Interaction has %d Dirac, %d Ghost "
1931 "and %d Majorana particles.\n",
1932 ndir, nmaj, ngho);
1933 grcc_fprintf(GRCC_Stderr, " Sign factors related to fermions may "
1934 "be inconsistent with your calculation method.\n");
1935 prmsg = False;
1936 }
1937 if (!ok) {
1938 prInteraction();
1939 erEnd("illegal Dirac/Majorana/Ghost interaction");
1940 }
1941}
1942
1943//--------------------------------------------------------------
1944Interaction::~Interaction(void)
1945{
1946 if (slist != NULL) {
1947 delete[] slist;
1948 }
1949 if (plist != NULL) {
1950 delete[] plist;
1951 }
1952 if (clist != NULL) {
1953 delete[] clist;
1954 }
1955 free(name);
1956}
1957
1958//--------------------------------------------------------------
1959void Interaction::prInteraction(void)
1960{
1961 int j;
1962
1963 grcc_fprintf(GRCC_Stdout, "vid=%d, icode=%d, name=\"%s\", loop=%d, csum=%d, cpl=",
1964 id, icode, name, loop, csum);
1965 prIntArray(mdl->ncouple, clist, ", legs=[");
1966 for (j = 0; j < nplist; j++) {
1967 if (j != 0) {
1968 grcc_fprintf(GRCC_Stdout, ", ");
1969 }
1970 grcc_fprintf(GRCC_Stdout, "%s", mdl->particleName(plist[j]));
1971 }
1972 grcc_fprintf(GRCC_Stdout, "];\n");
1973
1974}
1975
1976//==============================================================
1977// class Model
1978//--------------------------------------------------------------
1979Model::Model(MInput *minp)
1980{
1981 static PInput pundef = {"undef", "undef", 0, 0, "undef", 0, 0};
1982 int j;
1983
1984 if (minp->name == NULL || strlen(minp->name) < 1) {
1985 erEnd("model should have a name");
1986 }
1987 name = strdup(minp->name);
1988 ncouple = minp->ncouple;
1989 if (ncouple >= GRCC_MAXNCPLG) {
1990 erEnd("too many coupling constants in the model (GRCC_MAXNCPLG)");
1991 }
1992 // cnlist = minp->cnamlist;
1993 cnlist = new char*[ncouple];
1994 for (j = 0; j < ncouple; j++) {
1995 cnlist[j] = strdup(minp->cnamlist[j]);
1996 }
1997
1998 nParticles = 0;
1999 particles = new Particle*[GRCC_MAXMPARTICLES];
2000 for (j = 0; j < GRCC_MAXMPARTICLES; j++) {
2001 particles[j] = NULL;
2002 }
2003 pdef = False;
2004
2005 nInteracts = 0;
2006 interacts = new Interaction*[GRCC_MAXMINTERACT];
2007 for (j = 0; j < GRCC_MAXMINTERACT; j++) {
2008 interacts[j] = NULL;
2009 }
2010 vdef = False;
2011
2012 if (particles == NULL || interacts == NULL) {
2013 erEnd("memory allocation failed");
2014 }
2015
2016#ifdef UNIQINTR
2017 if (minp->defpart != GRCC_DEFBYNAME
2018 && minp->defpart != GRCC_DEFBYCODE) {
2019 erEnd("illegal value of defpart");
2020 }
2021#else
2022 if (Abs(minp->defpart) != GRCC_DEFBYNAME
2023 && Abs(minp->defpart) != GRCC_DEFBYCODE) {
2024 erEnd("illegal value of defpart");
2025 }
2026#endif
2027
2028 defpart = minp->defpart;
2029
2030 maxnlegs = 0;
2031 maxcpl = 0;
2032 maxloop = 0;
2033 ncplgcp = 0;
2034 cplgvl = NULL;
2035
2036 addParticle(&pundef);
2037}
2038
2039//--------------------------------------------------------------
2040Model::~Model(void)
2041{
2042 int j;
2043
2044 if (ncplgcp > 0) {
2045 for (j = ncplgcp-1; j >= 0; j--) {
2046 cplgvl[j] = delintdup(cplgvl[j]);
2047 }
2048 delete[] cplgvl;
2049 cplgnvl = delintdup(cplgnvl);
2050 cplglg = delintdup(cplglg);
2051 cplgcp = delintdup(cplgcp);
2052 }
2053
2054 for (j = GRCC_MAXMINTERACT-1; j >= 0; j--) {
2055 if (interacts[j] != NULL) {
2056 interacts[j]->slist = delintdup(interacts[j]->slist);
2057 delete interacts[j];
2058 interacts[j] = NULL;
2059 }
2060 }
2061 delete[] interacts;
2062 interacts = NULL;
2063
2064 for (j = GRCC_MAXMPARTICLES-1; j >= 0; j--) {
2065 if (particles[j] != NULL) {
2066 delete particles[j];
2067 particles[j] = NULL;
2068 }
2069 }
2070 delete[] particles;
2071 particles = NULL;
2072
2073 for (j=ncouple-1; j>=0; j--) {
2074 free(cnlist[j]);
2075 }
2076 delete[] cnlist;
2077
2078 free(name);
2079}
2080
2081//--------------------------------------------------------------
2082void Model::prModel(void)
2083{
2084 static char hdr[] = "#=================================================\n";
2085 static char hd1[] = "#-------------------------------------------------\n";
2086 int j;
2087
2088 grcc_fprintf(GRCC_Stdout, "%s", hdr);
2089 grcc_fprintf(GRCC_Stdout, "Model=\"%s\", ", name);
2090 grcc_fprintf(GRCC_Stdout, "coupling=[");
2091 for (j = 0; j < ncouple; j++) {
2092 if (j != 0) {
2093 grcc_fprintf(GRCC_Stdout, ", ");
2094 }
2095 grcc_fprintf(GRCC_Stdout, "\"%s\"", cnlist[j]);
2096 }
2097 grcc_fprintf(GRCC_Stdout, "];\n");
2098 grcc_fprintf(GRCC_Stdout, "%s", hd1);
2099 grcc_fprintf(GRCC_Stdout, "Particles=%d;\n", nParticles);
2100 for (j = 1; j < nParticles; j++) {
2101 particles[j]->prParticle();
2102 }
2103 grcc_fprintf(GRCC_Stdout, "EndParticle;\n");
2104 grcc_fprintf(GRCC_Stdout, "allPart (%d) = [", nallPart);
2105 for (j = 0; j < nallPart; j++) {
2106 if (j != 0) {
2107 grcc_fprintf(GRCC_Stdout, ", ");
2108 }
2109 grcc_fprintf(GRCC_Stdout, "%d", allPart[j]);
2110 }
2111 grcc_fprintf(GRCC_Stdout, "]\n");
2112
2113 grcc_fprintf(GRCC_Stdout, "%s", hd1);
2114 grcc_fprintf(GRCC_Stdout, "Interactions=%d;\n", nInteracts);
2115 for (j = 0; j < nInteracts; j++) {
2116 interacts[j]->prInteraction();
2117 }
2118 grcc_fprintf(GRCC_Stdout, "EndInteraction;\n");
2119 grcc_fprintf(GRCC_Stdout, "%s", hd1);
2120 grcc_fprintf(GRCC_Stdout, "InteractionTable;\n");
2121 grcc_fprintf(GRCC_Stdout, "# %d class in (total coupling, degree)\n", ncplgcp);
2122 for (j = 0; j < ncplgcp; j++) {
2123 grcc_fprintf(GRCC_Stdout, " class=%d: cp=%d, lg=%d, vl=", j, cplgcp[j], cplglg[j]);
2124 prIntArray(cplgnvl[j], cplgvl[j], "\n");
2125 }
2126 grcc_fprintf(GRCC_Stdout, "EndInteractionTable;\n");
2127 grcc_fprintf(GRCC_Stdout, "%s", hdr);
2128}
2129
2130//--------------------------------------------------------------
2131void Model::addParticle(PInput *pinp)
2132{
2133 int nid, aid, pid, pcd, acd;
2134
2135 if (nParticles >= GRCC_MAXMPARTICLES) {
2136 erEnd("particle table overflow (GRCC_MAXMPARTICLES)");
2137 }
2138
2139 // uniqueness check
2140 if (Abs(defpart) == GRCC_DEFBYCODE) {
2141 pcd = findParticleCode(pinp->pcode);
2142 acd = findParticleCode(pinp->acode);
2143 if (pcd > 0 || acd > 0) {
2144 if (prlevel > 0) {
2145 grcc_fprintf(GRCC_Stderr, "*** particle code [%d, %d] ",
2146 pinp->pcode, pinp->acode);
2147 grcc_fprintf(GRCC_Stderr, "is already used.\n");
2148 }
2149 erEnd("particle code is already defined");
2150 }
2151 } else if (Abs(defpart) == GRCC_DEFBYNAME) {
2152 if (pinp->name == NULL || pinp->aname == NULL ||
2153 strlen(pinp->name) < 1 || strlen(pinp->aname) < 1) {
2154 erEnd("no name of particle or anti-particle.");
2155 }
2156 nid = findParticleName(pinp->name);
2157 aid = findParticleName(pinp->aname);
2158 if (nid > 0 || aid > 0) {
2159 if (prlevel > 0) {
2160 grcc_fprintf(GRCC_Stderr, "*** particle name [%s, %s] ",
2161 pinp->name, pinp->aname);
2162 grcc_fprintf(GRCC_Stderr, "is already used.\n");
2163 }
2164 erEnd("particle name is already defined.");
2165 }
2166 }
2167
2168 pid = nParticles++;
2169 particles[pid] = new Particle(this, pid, pinp);
2170}
2171
2172//--------------------------------------------------------------
2173void Model::addParticleEnd(void)
2174{
2175 int p, ap;
2176
2177 pdef = True;
2178
2179#ifdef OPTEXTONLY
2180 nallPart = 0;
2181 for (p = nParticles-1; p >= 1; p--) {
2182 if (!particles[p]->extonly) {
2183 ap = antiParticle(p);
2184 if (ap != p) {
2185 allPart[nallPart++] = ap;
2186 }
2187 }
2188 }
2189 for (p = 1; p < nParticles; p++) {
2190 if (!particles[p]->extonly) {
2191 allPart[nallPart++] = p;
2192 }
2193 }
2194 sorti(nallPart, allPart);
2195#else
2196 nallPart = 0;
2197 for (p = nParticles-1; p >= 1; p--) {
2198 ap = antiParticle(p);
2199 if (ap != p) {
2200 allPart[nallPart++] = ap;
2201 }
2202 }
2203 for (p = 1; p < nParticles; p++) {
2204 allPart[nallPart++] = p;
2205 }
2206 sorti(nallPart, allPart);
2207#endif
2208}
2209
2210//--------------------------------------------------------------
2211void Model::addInteraction(IInput *iinp)
2212{
2213 int vid, nlegs, j, k, c;
2214 int csum, lp2, lp;
2215 int plist[GRCC_MAXLEGS];
2216
2217 if (!pdef) {
2218 erEnd("call 'addParticleEnd' before 'addInteraction'");
2219 }
2220 if (nInteracts >= GRCC_MAXMINTERACT) {
2221 erEnd("too many interactions in the model (GRCC_MAXMINTERACT)");
2222 }
2223 nlegs = iinp->nplistn;
2224 if (nlegs >= GRCC_MAXLEGS) {
2225 erEnd("too many legs in an interaction (GRCC_MAXLEGS)");
2226 }
2227
2228 // check identifier
2229 if (defpart == GRCC_DEFBYCODE) {
2230 if (iinp->icode < 0) {
2231 if (prlevel > 0) {
2232 grcc_fprintf(GRCC_Stderr, "*** vertex code %d should be positive\n",
2233 iinp->icode);
2234 }
2235 erEnd("vertex code should be positive");
2236 } else {
2237 vid = findInteractionCode(iinp->icode);
2238 if (vid >= 0) {
2239 if (prlevel > 0) {
2240 grcc_fprintf(GRCC_Stderr, "*** vertex code %d is already used\n",
2241 iinp->icode);
2242 }
2243 erEnd("vertex code is already used");
2244 }
2245 }
2246 } else if (defpart == GRCC_DEFBYNAME) {
2247 if (iinp->name == NULL || strlen(iinp->name) < 1) {
2248 erEnd("no name of vertex\n");
2249 }
2250 vid = findInteractionName(iinp->name);
2251 if (vid >= 0) {
2252 if (prlevel > 0) {
2253 grcc_fprintf(GRCC_Stderr, "*** vertex name %s is already used\n",
2254 iinp->name);
2255 erEnd("vertex name is already used");
2256 }
2257 }
2258 } else {
2259#ifdef UNIQINTR
2260 // defpart =< 0
2261 erEnd("illegal value of defpart");
2262#else
2263 // don't care about duplicated name/code of interaction
2264 ;
2265#endif
2266 }
2267 vid = nInteracts++;
2268
2269 for (j = 0; j < nlegs; j++) {
2270 if (Abs(defpart) == GRCC_DEFBYCODE) {
2271 plist[j] = findParticleCode(iinp->plistc[j]);
2272 if (plist[j] == 0) {
2273 if (prlevel > 0) {
2274 grcc_fprintf(GRCC_Stderr, "*** particle code %d ",
2275 iinp->plistc[j]);
2276 grcc_fprintf(GRCC_Stderr, "is not defined\n");
2277 }
2278 erEnd("particle is not defined (code)");
2279 }
2280 } else if (Abs(defpart) == GRCC_DEFBYNAME) {
2281 plist[j] = findParticleName(iinp->plistn[j]);
2282 if (plist[j] == 0) {
2283 if (prlevel > 0) {
2284 grcc_fprintf(GRCC_Stderr, "*** particle name %s ",
2285 iinp->plistn[j]);
2286 grcc_fprintf(GRCC_Stderr, "is not defined\n");
2287 }
2288 erEnd("particle is not defined (name)");
2289 }
2290 }
2291 }
2292
2293 csum = 0;
2294 for (j = 0; j < ncouple; j++) {
2295 c = iinp->cvallist[j];
2296 if (c < 0) {
2297 if (prlevel > 0) {
2298 grcc_fprintf(GRCC_Stderr, "*** illegal value of c-constants \n");
2299 for (k = 0; k < ncouple; k++) {
2300 grcc_fprintf(GRCC_Stderr, " %s = %d\n",
2301 cnlist[k], iinp->cvallist[k]);
2302 }
2303 }
2304 erEnd("illegal value of c-constants");
2305 }
2306 csum += c;
2307 }
2308 if (csum < 0) {
2309 if (prlevel > 0) {
2310 grcc_fprintf(GRCC_Stderr, "*** illegal total coupling-constants %d\n",
2311 csum);
2312 for (k = 0; k < ncouple; k++) {
2313 grcc_fprintf(GRCC_Stderr, " %s = %d\n",
2314 cnlist[k], iinp->cvallist[k]);
2315 }
2316 }
2317 erEnd("illegal value of c-constants");
2318 }
2319
2320 // assume : csum = nlegs - 2 + 2*loop
2321 lp2 = csum - nlegs + 2;
2322 if (lp2 % 2 != 0 || lp2 < 0) {
2323 if (prlevel > 0) {
2324 grcc_fprintf(GRCC_Stderr, "*** illegal coupling const : ");
2325 grcc_fprintf(GRCC_Stderr, "nlegs - 2 + 2*loop: 2*loop = %d\n", lp2);
2326 }
2327 erEnd("illegal value of c-constants");
2328 }
2329 lp = lp2/2;
2330
2331 maxnlegs = Max(maxnlegs, nlegs);
2332 maxloop = Max(maxloop , lp);
2333 maxcpl = Max(maxcpl , csum);
2334
2335 interacts[vid] = new Interaction(this, vid, iinp->name, iinp->icode,
2336 iinp->cvallist, nlegs, plist, csum, lp);
2337}
2338
2339//--------------------------------------------------------------
2340void Model::addInteractionEnd(void)
2341{
2342 int lst[GRCC_MAXMINTERACT];
2343 int tcp[GRCC_MAXMINTERACT], tlg[GRCC_MAXMINTERACT];
2344 int tnvl[GRCC_MAXMINTERACT], *tvl[GRCC_MAXMINTERACT];
2345 Interaction *vt;
2346 int cp, lg, j, k, p;
2347
2348 vdef = True;
2349 ncplgcp = 0;
2350 for (cp = 0; cp <= maxcpl; cp++) {
2351
2352 for (lg = 0; lg <= maxnlegs; lg++) {
2353 k = 0;
2354 for (j = 0; j < nInteracts; j++) {
2355 vt = interacts[j];
2356 if (vt->csum == cp && vt->nlegs == lg) {
2357 lst[k++] = j;
2358 }
2359 }
2360 if (k > 0) {
2361 tcp[ncplgcp] = cp;
2362 tlg[ncplgcp] = lg;
2363 tnvl[ncplgcp] = k;
2364 tvl[ncplgcp] = intdup(k, lst);
2365 ncplgcp++;
2366 }
2367 }
2368 }
2369 cplgcp = intdup(ncplgcp, tcp);
2370 cplglg = intdup(ncplgcp, tlg);
2371 cplgnvl = intdup(ncplgcp, tnvl);
2372 cplgvl = new int*[ncplgcp];
2373 for (j = 0; j < ncplgcp; j++) {
2374 if (cplgnvl[j] > 0) {
2375 cplgvl[j] = tvl[j];
2376 } else {
2377 cplgvl[j] = NULL;
2378 }
2379 }
2380
2381 for (j = 0; j < nInteracts; j++) {
2382 vt = interacts[j];
2383 if (vt->slist != NULL) {
2384 erEnd("addInteractionEnd: vt->nslist != NULL");
2385 }
2386 vt->slist = intdup(vt->nplist, vt->plist);
2387 vt->nslist = toSList(vt->nplist, vt->slist);
2388 }
2389
2390 for (p = 0; p < nParticles; p++) {
2391 particles[p]->cmindeg = 0;
2392 particles[p]->cmaxdeg = 0;
2393 }
2394 for (j = 0; j < nInteracts; j++) {
2395 vt = interacts[j];
2396 for (k = 0; k < vt->nplist; k++) {
2397 p = abs(vt->plist[k]);
2398 if (particles[p]->cmindeg == 0) {
2399 particles[p]->cmindeg = vt->nlegs;
2400 particles[p]->cmaxdeg = vt->nlegs;
2401 } else {
2402 particles[p]->cmindeg = Min(particles[p]->cmindeg, vt->nlegs);
2403 particles[p]->cmaxdeg = Max(particles[p]->cmaxdeg, vt->nlegs);
2404 }
2405 }
2406 }
2407}
2408
2409//--------------------------------------------------------------
2410int Model::findParticleName(const char *name)
2411{
2412 int j;
2413
2414 for (j = 0; j < nParticles; j++) {
2415 if (strcmp(name, particles[j]->name) == 0) {
2416 return j;
2417 }
2418 }
2419 for (j = 0; j < nParticles; j++) {
2420 if (strcmp(name, particles[j]->aname) == 0) {
2421 return -j;
2422 }
2423 }
2424 return 0;
2425}
2426
2427//--------------------------------------------------------------
2428int Model::findParticleCode(int pcd)
2429{
2430 int j;
2431
2432 for (j = 0; j < nParticles; j++) {
2433 if (pcd == particles[j]->pcode) {
2434 return j;
2435 } else if (pcd == particles[j]->acode) {
2436 return -j;
2437 }
2438 }
2439 return 0;
2440}
2441
2442//--------------------------------------------------------------
2443char *Model::particleName(int p)
2444{
2445 int q;
2446
2447 if (Abs(p) >= nParticles) {
2448 if (prlevel > 0) {
2449 grcc_fprintf(GRCC_Stderr, "\n*** Model::particleName: ");
2450 grcc_fprintf(GRCC_Stderr, "illegal particle id=%d\n", p);
2451 }
2452 erEnd("Model::particleName: illegal particle");
2453 }
2454 if (p < 0) {
2455 q = - p;
2456 } else {
2457 q = p;
2458 }
2459 return particles[q]->particleName(p);
2460}
2461
2462//--------------------------------------------------------------
2463int Model::particleCode(int p)
2464{
2465 int q;
2466
2467 if (Abs(p) >= nParticles) {
2468 grcc_fprintf(GRCC_Stderr, "\n*** Model::particleCode: illegal particle id=%d\n",
2469 p);
2470 erEnd("Model::particleCode: illegal particle");
2471 }
2472 if (p < 0) {
2473 q = - p;
2474 } else {
2475 q = p;
2476 }
2477 return particles[q]->particleCode(p);
2478}
2479
2480//--------------------------------------------------------------
2481void Model::prParticleArray(int n, int *a, const char *msg)
2482{
2483 int j;
2484
2485 grcc_fprintf(GRCC_Stdout, "[");
2486 for (j = 0; j < n; j++) {
2487 if (j != 0) {
2488 grcc_fprintf(GRCC_Stdout, ", ");
2489 }
2490 grcc_fprintf(GRCC_Stdout, "%s", particleName(a[j]));
2491 }
2492 grcc_fprintf(GRCC_Stdout, "]%s", msg);
2493}
2494
2495//--------------------------------------------------------------
2496int Model::findMClass(const int cpl, const int dgr)
2497{
2498 int j;
2499
2500 for (j = 0; j < ncplgcp; j++) {
2501 if (cplgcp[j] == cpl && cplglg[j] == dgr) {
2502 return j;
2503 }
2504 }
2505 return -1;
2506}
2507
2508//--------------------------------------------------------------
2509int Model::normalParticle(int pt)
2510{
2511 int ptc = Abs(pt);
2512 Particle *p;
2513
2514 if (ptc >= nParticles) {
2515 return 0;
2516 }
2517 p = particles[ptc];
2518 if (p->isNeutral()) {
2519 return ptc;
2520 } else {
2521 return pt;
2522 }
2523}
2524
2525//--------------------------------------------------------------
2526int Model::antiParticle(int pt)
2527{
2528 int ptc = Abs(pt);
2529 Particle *p;
2530
2531 p = particles[ptc];
2532 if (p->isNeutral()) {
2533 return ptc;
2534 } else {
2535 return -pt;
2536 }
2537}
2538
2539//--------------------------------------------------------------
2540int *Model::allParticles(int *len)
2541{
2542 *len = nallPart;
2543 return allPart;
2544}
2545
2546//--------------------------------------------------------------
2547int Model::findInteractionName(const char *name)
2548{
2549 int j;
2550
2551 for (j = 0; j < nInteracts; j++) {
2552 if (strcmp(name, interacts[j]->name) == 0) {
2553 return j;
2554 }
2555 }
2556 return -1;
2557}
2558
2559//--------------------------------------------------------------
2560int Model::findInteractionCode(int icd)
2561{
2562 int j;
2563
2564 for (j = 0; j < nInteracts; j++) {
2565 if (icd == interacts[j]->icode) {
2566 return j;
2567 }
2568 }
2569 return -1;
2570}
2571
2572//--------------------------------------------------------------
2573void Model::printMInput(MInput *min)
2574{
2575 grcc_fprintf(GRCC_Stdout, " \"Model\": [\"%s\", %d, [",
2576 min->name, min->ncouple);
2577 for (int j = 0; j < min->ncouple; j++) {
2578 if (j != 0) {
2579 grcc_fprintf(GRCC_Stdout, ", ");
2580 }
2581 grcc_fprintf(GRCC_Stdout, "\"%s\"", min->cnamlist[j]);
2582 }
2583 grcc_fprintf(GRCC_Stdout, "], ");
2584 if (min->defpart == GRCC_DEFBYCODE) {
2585 grcc_fprintf(GRCC_Stdout, "\"ByCode\"");
2586 } else {
2587 grcc_fprintf(GRCC_Stdout, "\"ByName\"");
2588 }
2589 grcc_fprintf(GRCC_Stdout, "],\n");
2590}
2591
2592//--------------------------------------------------------------
2593void Model::printPInput(PInput *pin)
2594{
2595 grcc_fprintf(GRCC_Stdout, " [\"%s\"(%d), \"%s\"(%d), \"%s\"(%d), %d],\n",
2596 pin->name, pin->pcode, pin->aname, pin->acode,
2597 pin->ptypen, pin->ptypec, pin->extonly);
2598}
2599
2600//--------------------------------------------------------------
2601void Model::printIInput(IInput *iin)
2602{
2603 int j;
2604
2605 grcc_fprintf(GRCC_Stdout, " [\"%s\"(%d), %d, [", iin->name, iin->icode, iin->nplistn);
2606 for (j = 0; j < iin->nplistn; j++) {
2607 if (j != 0) {
2608 grcc_fprintf(GRCC_Stdout, ", ");
2609 }
2610 grcc_fprintf(GRCC_Stdout, "\"%s\"(%d)", iin->plistn[j], iin->plistc[j]);
2611 }
2612 grcc_fprintf(GRCC_Stdout, "], [");
2613 for (j = 0; j < GRCC_MAXNCPLG; j++) {
2614 if (j != 0) {
2615 grcc_fprintf(GRCC_Stdout, ", ");
2616 }
2617 grcc_fprintf(GRCC_Stdout, "%d", iin->cvallist[j]);
2618 }
2619 grcc_fprintf(GRCC_Stdout, "],\n");
2620}
2621
2622//**************************************************************
2623// proc.cc
2624
2625//==============================================================
2626// class PNodeClass
2627//--------------------------------------------------------------
2628PNodeClass::PNodeClass(SProcess *spc, int nnods, int nclss, NCInput *cls)
2629{
2630 // Create a class of nodes
2631 // nnodes : # nodes
2632 // nclss : # classes
2633 // cls : table of class inputs
2634 //
2635 int j, k, nn, lp2;
2636 Bool ok = True;
2637
2638 sproc = spc;
2639 nnodes = nnods;
2640 nclass = nclss;
2641 deg = new int[nclass];
2642 type = new int[nclass];
2643 particle = new int[nclass];
2644 count = new int[nclass];
2645 couple = new int[nclass];
2646 cmindeg = new int[nclass];
2647 cmaxdeg = new int[nclass];
2648 for (j = 0; j < nclass; j++) {
2649 deg[j] = cls[j].cldeg;
2650 count[j] = cls[j].clnum;
2651 type[j] = cls[j].cltyp;
2652 cmindeg[j] = cls[j].cmind;
2653 cmaxdeg[j] = cls[j].cmaxd;
2654 particle[j] = cls[j].ptcl;
2655 couple[j] = cls[j].cple;
2656 lp2 = (couple[j]-deg[j]+2);
2657 if (!isATExternal(type[j]) && (lp2 % 2 != 0 || lp2 < 0)) {
2658 if (prlevel > 0) {
2659 grcc_fprintf(GRCC_Stderr, "*** PNodeClass: illegal loop: "
2660 ": 2*loop=cpl[%d](%d)-deg[%d](%d)+2 =2*loop = %d\n",
2661 j, couple[j], j, deg[j], lp2);
2662 for (k = 0; k < nclss; k++) {
2663 grcc_fprintf(GRCC_Stderr, "k=%d, deg=%d, typ=%d, ptcl=%d, ",
2664 k, deg[k], type[k], particle[k]);
2665 grcc_fprintf(GRCC_Stderr, "cpl=%d, cnt=%d\n",
2666 couple[k], count[k]);
2667 }
2668 }
2669 ok = False;
2670 }
2671 }
2672 if (!ok) {
2673 erEnd("PNodeClass: illegal loop");
2674 }
2675 cl2nd = new int[nclass+1];
2676 nd2cl = new int[nnodes];
2677 cl2mcl = new int[nnodes];
2678
2679 nn = 0;
2680 for (j = 0; j < nclass; j++) {
2681 cl2nd[j] = nn;
2682 for (k = 0; k < count[j]; k++, nn++) {
2683 nd2cl[nn] = j;
2684 }
2685 if (isATExternal(type[j])) {
2686 cl2mcl[j] = -1;
2687 } else {
2688 cl2mcl[j] = spc->model->findMClass(couple[j], deg[j]);
2689 if (cl2mcl[j] < 0) {
2690 if (prlevel > 0) {
2691 grcc_fprintf(GRCC_Stderr, "*** PNodeClass : no vertex : ");
2692 grcc_fprintf(GRCC_Stderr, "coupling=%d, degree=%d\n",
2693 couple[j], deg[j]);
2694 }
2695 erEnd("PNodeClass : no vertex");
2696 }
2697 }
2698 }
2699 cl2nd[nclass] = nnodes;
2700}
2701//--------------------------------------------------------------
2702PNodeClass::PNodeClass(SProcess *spc, int nnods, int nclss, int *dgs, int *typ, int *ptcl, int *cpl, int *cnt, int *cmind, int *cmaxd)
2703{
2704 // Create a class of nodes
2705 // nnodes : # nodes
2706 // nclss : # classes
2707 // dgs : degree of a node, which is common to the vertices in a class
2708 // typ : initial/final/vertex
2709 // ptcl : particle code or list of possible interactions
2710 // cpl : values of coupling constants.
2711 // cnt : the number of nodes in this class
2712 //
2713 int j, k, nn, lp2;
2714 Bool ok = True;
2715
2716 sproc = spc;
2717 nnodes = nnods;
2718 nclass = nclss;
2719 deg = new int[nclass];
2720 type = new int[nclass];
2721 particle = new int[nclass];
2722 count = new int[nclass];
2723 couple = new int[nclass];
2724 cmindeg = new int[nclass];
2725 cmaxdeg = new int[nclass];
2726 for (j = 0; j < nclass; j++) {
2727 deg[j] = dgs[j];
2728 type[j] = typ[j];
2729 particle[j] = ptcl[j];
2730 count[j] = cnt[j];
2731 couple[j] = cpl[j];
2732 cmindeg[j] = cmind[j];
2733 cmaxdeg[j] = cmaxd[j];
2734 lp2 = (cpl[j]-dgs[j]+2);
2735 if (!isATExternal(type[j]) && (lp2 % 2 != 0 || lp2 < 0)) {
2736 if (prlevel > 0) {
2737 grcc_fprintf(GRCC_Stderr, "*** PNodeClass: illegal loop: "
2738 ": 2*loop=cpl[%d](%d)-deg[%d](%d)+2 =2*loop = %d\n",
2739 j, cpl[j], j, dgs[j], lp2);
2740 for (k = 0; k < nclss; k++) {
2741 grcc_fprintf(GRCC_Stderr, "k=%d, dgs=%d, typ=%d, ptcl=%d, ",
2742 k, dgs[k], typ[k], ptcl[k]);
2743 grcc_fprintf(GRCC_Stderr, "cpl=%d, cnt=%d\n", cpl[k], cnt[k]);
2744 }
2745 }
2746 ok = False;
2747 }
2748 }
2749 if (!ok) {
2750 erEnd("PNodeClass: illegal loop");
2751 }
2752 cl2nd = new int[nclass+1];
2753 nd2cl = new int[nnodes];
2754 cl2mcl = new int[nnodes];
2755
2756 nn = 0;
2757 for (j = 0; j < nclass; j++) {
2758 cl2nd[j] = nn;
2759 for (k = 0; k < count[j]; k++, nn++) {
2760 nd2cl[nn] = j;
2761 }
2762 if (isATExternal(type[j])) {
2763 cl2mcl[j] = -1;
2764 } else {
2765 cl2mcl[j] = spc->model->findMClass(couple[j], deg[j]);
2766 if (cl2mcl[j] < 0) {
2767 if (prlevel > 0) {
2768 grcc_fprintf(GRCC_Stderr, "*** PNodeClass : no vertex : ");
2769 grcc_fprintf(GRCC_Stderr, "coupling=%d, degree=%d\n",
2770 couple[j], deg[j]);
2771 }
2772 erEnd("PNodeClass : no vertex");
2773 }
2774 }
2775 }
2776 cl2nd[nclass] = nnodes;
2777}
2778
2779//--------------------------------------------------------------
2780PNodeClass::~PNodeClass(void)
2781{
2782 delete[] cl2mcl;
2783 delete[] nd2cl;
2784 delete[] cl2nd;
2785 delete[] cmaxdeg;
2786 delete[] cmindeg;
2787 delete[] couple;
2788 delete[] count;
2789 delete[] particle;
2790 delete[] type;
2791 delete[] deg;
2792}
2793
2794//--------------------------------------------------------------
2795void PNodeClass::prPNodeClass(void)
2796{
2797 int j;
2798
2799 grcc_fprintf(GRCC_Stdout, "+++ PNodeClass: nclass=%d, nnodes=%d\n", nclass, nnodes);
2800 for (j = 0; j < nclass; j++) {
2801 prElem(j);
2802 }
2803 grcc_fprintf(GRCC_Stdout, "\n");
2804}
2805
2806//--------------------------------------------------------------
2807void PNodeClass::prElem(int j)
2808{
2809 int tp;
2810
2811 grcc_fprintf(GRCC_Stdout, "%3d: %-7s(%2d), ", j, GRCC_AT_NdStr(type[j]), type[j]);
2812 grcc_fprintf(GRCC_Stdout, "deg=%d, count=%d, nodes[%d--%d], couple=%d, cmindeg=%d, cmaxdeg=%d",
2813 deg[j], count[j], cl2nd[j], cl2nd[j+1], couple[j], cmindeg[j], cmaxdeg[j]);
2814 tp = type[j];
2815 if (isATExternal(tp)) {
2816 if (sproc->model != NULL) {
2817 grcc_fprintf(GRCC_Stdout, ", ptcl=%s ", sproc->model->particleName(particle[j]));
2818 } else {
2819 grcc_fprintf(GRCC_Stdout, ", ptcl=%d ", particle[j]);
2820 }
2821 }
2822 grcc_fprintf(GRCC_Stdout, "\n");
2823
2824}
2825
2826//==============================================================
2827// class SProcess
2828//--------------------------------------------------------------
2829SProcess::SProcess(Model *mdl, Process *prc, Options *opts, int sid, int *clst, int ncls, int *cdeg, int *ctyp, int *ptcl, int *cpl, int *cnum, int *cmind, int *cmaxd)
2830{
2831 // Construct a Subprocess object
2832 // mdl : model
2833 // prc : process (may be NULL)
2834 // opts : options
2835 // sid : id of the sprocess
2836 // ncls : the number of classes
2837 // cdeg[ncls] : the table of degrees of nodes.
2838 // ctyp[ncls] : the table of nodes in the classes
2839 // ptcl[ncls] : particle(External)/interaction code(Internal)
2840 // cpl[ncls] : the table of total order of coupling constants.
2841 // cnum[ncls] : the table of nodes in the classes
2842 // cmind[ncls] : the table of min(deg of connectable vertex)
2843 // cmaxd[ncls] : the table of max(deg of connectable vertex)
2844
2845 int j, cp, lp2, ndeg, nvrt, tcpl0;
2846 bool ok;
2847
2848 if (ncls < 1) {
2849 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: no class %d\n", ncls);
2850 erEnd("SProcess::SProcess: no Class");
2851 }
2852 id = sid;
2853 model = mdl;
2854 proc = prc;
2855 opt = opts;
2856 nclass = ncls;
2857
2858 nNodes = 0;
2859 nEdges = 0;
2860 nExtern = 0;
2861 tCouple = 0;
2862 loop = 0;
2863 mgraph = NULL;
2864 egraph = NULL;
2865 astack = NULL;
2866
2867 mgrcount = 0;
2868 agrcount = 0;
2869 extperm = 1;
2870
2871 // the results of the graph generation
2872 nMGraphs = 0; // the number of generated M-graphs
2873 nMOPI = 0; // the number of 1PI M-graphs
2874 wMGraphs.setValue(0,1); // the weighted sum of M-graphs
2875 wMOPI.setValue(0,1); // the weighted sum of 1PI M-graphs
2876
2877 nAGraphs = 0; // the number of generated A-graphs
2878 nAOPI = 0; // the number of 1PI A-graphs
2879 wAGraphs.setValue(0,1); // the weighted sum of A-graphs
2880 wAOPI.setValue(0,1); // the weighted sum of 1PI A-graphs
2881
2882 // check input
2883 nNodes = 0;
2884 nExtern = 0;
2885
2886 ndeg = 0;
2887 nvrt = 0;
2888 ok = True;
2889
2890 tcpl0 = 0;
2891 for (j = 0; j < model->ncouple; j++) {
2892 clist[j] = clst[j];
2893 tcpl0 += clist[j];
2894 }
2895 for (j = 0; j < nclass; j++) {
2896 cp = cpl[j];
2897 if (cp > 0) {
2898 lp2 = cpl[j] - cdeg[j] + 2;
2899 if (lp2 % 2 != 0 || lp2 < 0) {
2900 if (prlevel > 0) {
2901 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: illegal loop:"
2902 "class %d, cp=%d, deg=%d, lp2=%d\n",
2903 j, cp, cdeg[j], lp2);
2904 }
2905 ok = False;
2906 }
2907 }
2908 tCouple += cp*cnum[j];
2909 ndeg += cdeg[j]*cnum[j];
2910
2911 if (!isATExternal(ctyp[j])) {
2912 nvrt += cnum[j];
2913 } else if (isATExternal(ctyp[j])) {
2914 if (model->normalParticle(ptcl[j]) == 0) {
2915 if (prlevel > 0) {
2916 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: ");
2917 grcc_fprintf(GRCC_Stderr, "illegal particle code: ");
2918 grcc_fprintf(GRCC_Stderr, "code: class %d, ptcl=%d\n", j, ptcl[j]);
2919 }
2920 ok = False;
2921 } else {
2922 nExtern += cnum[j];
2923 }
2924 extperm *= factorial(cnum[j]);
2925
2926 } else {
2927 if (prlevel > 0) {
2928 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: illegal type: ");
2929 grcc_fprintf(GRCC_Stderr, "class %d, type=%d\n", j, ctyp[j]);
2930 }
2931 ok = False;
2932 }
2933 }
2934 if (tcpl0 != tCouple) {
2935 if (prlevel > 0) {
2936 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: ");
2937 grcc_fprintf(GRCC_Stderr, "illegal coupling constants:");
2938 grcc_fprintf(GRCC_Stderr, " %d != %d\n", tcpl0, tCouple);
2939 }
2940 ok = False;
2941 }
2942 if (ndeg == nExtern) {
2943 if (prlevel > 0) {
2944 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: ");
2945 grcc_fprintf(GRCC_Stderr, "no vertices: ");
2946 grcc_fprintf(GRCC_Stderr, "nExtern=%d, ndeg=%d\n", nExtern, ndeg);
2947 }
2948 ok = False;
2949 }
2950 if (ndeg % 2 == 0) {
2951 nEdges = ndeg/2;
2952 } else {
2953 if (prlevel > 0) {
2954 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: ");
2955 grcc_fprintf(GRCC_Stderr, "illegal total deg = %d (not even)\n", ndeg);
2956 }
2957 ok = False;
2958 }
2959 nNodes = nvrt + nExtern;
2960 if (nNodes >= GRCC_MAXNODES) {
2961 if (prlevel > 0) {
2962 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: ");
2963 grcc_fprintf(GRCC_Stderr, "too many nodes = %d\n", nNodes);
2964 grcc_fprintf(GRCC_Stderr, " nExtern=%d, nvert=%d (GRCC_MAXNODES)\n",
2965 nExtern, nvert);
2966 }
2967 ok = False;
2968 }
2969 if (!ok) {
2970 prSProcess();
2971 erEnd("SProcess::SProcess: illegal input");
2972 }
2973 if (proc == NULL) {
2974 opt->beginProc(NULL);
2975 }
2976
2977 lp2 = tCouple - nExtern + 2;
2978 if (lp2 % 2 != 0 || lp2 < 0) {
2979 if (prlevel > 0) {
2980 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: illegal loop: "
2981 "tCouple=%d, nExtern=%d, 2*loop=%d\n",
2982 tCouple, nExtern, lp2);
2983 }
2984 ok = False;
2985 }
2986 loop = lp2/2;
2987
2988 // stack for assignment
2989 if (opt->values[GRCC_OPT_Step] == GRCC_AGraph) {
2990 astack = new AStack(GRCC_MAXNSTACK, GRCC_MAXESTACK);
2991 }
2992
2993 // save to PNodeClass object
2994 pnclass = new PNodeClass(this, nNodes, nclass, cdeg, ctyp, ptcl, cpl, cnum, cmind, cmaxd);
2995}
2996
2997//--------------------------------------------------------------
2998SProcess::SProcess(Model *mdl, Process *prc, Options *opts, int sid, int *clst, int ncls, NCInput *cls)
2999{
3000 // Construct a Subprocess object
3001 // mdl : model
3002 // prc : process (may be NULL)
3003 // opts : options
3004 // sid : id of the sprocess
3005 // ncls : the number of classes
3006 // cls : input data of classes
3007
3008 int j, cp, lp2, ndeg, nvrt, tcpl0;
3009 bool ok;
3010
3011 if (ncls < 1) {
3012 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: no class %d\n", ncls);
3013 erEnd("SProcess::SProcess: no Class");
3014 }
3015 id = sid;
3016 model = mdl;
3017 proc = prc;
3018 opt = opts;
3019 nclass = ncls;
3020
3021 nNodes = 0;
3022 nEdges = 0;
3023 nExtern = 0;
3024 tCouple = 0;
3025 loop = 0;
3026 mgraph = NULL;
3027 egraph = NULL;
3028 astack = NULL;
3029
3030 mgrcount = 0;
3031 agrcount = 0;
3032 extperm = 1;
3033
3034 // the results of the graph generation
3035 nMGraphs = 0; // the number of generated M-graphs
3036 nMOPI = 0; // the number of 1PI M-graphs
3037 wMGraphs.setValue(0,1); // the weighted sum of M-graphs
3038 wMOPI.setValue(0,1); // the weighted sum of 1PI M-graphs
3039
3040 nAGraphs = 0; // the number of generated A-graphs
3041 nAOPI = 0; // the number of 1PI A-graphs
3042 wAGraphs.setValue(0,1); // the weighted sum of A-graphs
3043 wAOPI.setValue(0,1); // the weighted sum of 1PI A-graphs
3044
3045 // check input
3046 nNodes = 0;
3047 nExtern = 0;
3048
3049 ndeg = 0;
3050 nvrt = 0;
3051 ok = True;
3052
3053 tcpl0 = 0;
3054 for (j = 0; j < model->ncouple; j++) {
3055 clist[j] = clst[j];
3056 tcpl0 += clist[j];
3057 }
3058 for (j = 0; j < nclass; j++) {
3059 cp = cls[j].cple;
3060 if (cp > 0) {
3061 lp2 = cls[j].cple - cls[j].cldeg + 2;
3062 if (lp2 % 2 != 0 || lp2 < 0) {
3063 if (prlevel > 0) {
3064 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: illegal loop: "
3065 "class %d, cp=%d, deg=%d, lp2=%d\n",
3066 j, cp, cls[j].cldeg, lp2);
3067 }
3068 ok = False;
3069 }
3070 }
3071 tCouple += cp*cls[j].clnum;
3072 ndeg += cls[j].cldeg*cls[j].clnum;
3073
3074 if (!isATExternal(cls[j].cltyp)) {
3075 nvrt += cls[j].clnum;
3076 } else if (isATExternal(cls[j].cltyp)) {
3077 if (model->normalParticle(cls[j].ptcl) == 0) {
3078 if (prlevel > 0) {
3079 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: ");
3080 grcc_fprintf(GRCC_Stderr, "illegal particle code: ");
3081 grcc_fprintf(GRCC_Stderr, "code: class %d, ptcl=%d\n", j, cls[j].ptcl);
3082 }
3083 ok = False;
3084 } else {
3085 nExtern += cls[j].clnum;
3086 }
3087 extperm *= factorial(cls[j].clnum);
3088
3089 } else {
3090 if (prlevel > 0) {
3091 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: illegal type: ");
3092 grcc_fprintf(GRCC_Stderr, "class %d, type=%d\n", j, cls[j].cltyp);
3093 }
3094 ok = False;
3095 }
3096 }
3097 if (tcpl0 != tCouple) {
3098 if (prlevel > 0) {
3099 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: ");
3100 grcc_fprintf(GRCC_Stderr, "illegal coupling constants:");
3101 grcc_fprintf(GRCC_Stderr, " %d != %d\n", tcpl0, tCouple);
3102 }
3103 ok = False;
3104 }
3105 if (ndeg == nExtern) {
3106 if (prlevel > 0) {
3107 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: ");
3108 grcc_fprintf(GRCC_Stderr, "no vertices: ");
3109 grcc_fprintf(GRCC_Stderr, "nExtern=%d, ndeg=%d\n", nExtern, ndeg);
3110 }
3111 ok = False;
3112 }
3113 if (ndeg % 2 == 0) {
3114 nEdges = ndeg/2;
3115 } else {
3116 if (prlevel > 0) {
3117 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: ");
3118 grcc_fprintf(GRCC_Stderr, "illegal total deg = %d (not even)\n", ndeg);
3119 }
3120 ok = False;
3121 }
3122 nNodes = nvrt + nExtern;
3123 if (nNodes >= GRCC_MAXNODES) {
3124 if (prlevel > 0) {
3125 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: ");
3126 grcc_fprintf(GRCC_Stderr, "too many nodes = %d\n", nNodes);
3127 grcc_fprintf(GRCC_Stderr, " nExtern=%d, nvert=%d (GRCC_MAXNODES)\n",
3128 nExtern, nvert);
3129 }
3130 ok = False;
3131 }
3132 if (!ok) {
3133 erEnd("SProcess::SProcess: illegal input");
3134 }
3135 if (proc == NULL) {
3136 opt->beginProc(NULL);
3137 }
3138
3139 lp2 = tCouple - nExtern + 2;
3140 if (lp2 % 2 != 0 || lp2 < 0) {
3141 if (prlevel > 0) {
3142 grcc_fprintf(GRCC_Stderr, "*** SProcess::SProcess: illegal loop: "
3143 "tCouple=%d, nExtern=%d, 2*loop=%d\n",
3144 tCouple, nExtern, lp2);
3145 }
3146 ok = False;
3147 }
3148 loop = lp2/2;
3149
3150 // stack for assignment
3151 if (opt->values[GRCC_OPT_Step] == GRCC_AGraph) {
3152 astack = new AStack(GRCC_MAXNSTACK, GRCC_MAXESTACK);
3153 }
3154
3155 // save to PNodeClass object
3156 pnclass = new PNodeClass(this, nNodes, nclass, cls);
3157}
3158
3159//--------------------------------------------------------------
3160SProcess::~SProcess(void)
3161{
3162 delete pnclass;
3163 delete astack;
3164 delete mgraph;
3165 model = NULL;
3166}
3167
3168//--------------------------------------------------------------
3169void SProcess::prSProcess(void)
3170{
3171 grcc_fprintf(GRCC_Stdout, "\n");
3172 grcc_fprintf(GRCC_Stdout, "+++ Subprocess %d, class=%d\n", id, nclass);
3173 if (pnclass != NULL) {
3174 pnclass->prPNodeClass();
3175 } else {
3176 grcc_fprintf(GRCC_Stdout, " pnclass = NULL\n");
3177 }
3178}
3179
3180//--------------------------------------------------------------
3181BigInt SProcess::generate(void)
3182{
3183 // Entry point of Feynman graph generation
3184 int cldeg[GRCC_MAXNODES], clnum[GRCC_MAXNODES], cltyp[GRCC_MAXNODES];
3185 int cmind[GRCC_MAXNODES], cmaxd[GRCC_MAXNODES];
3186 int ncl;
3187 BigInt ng;
3188
3189 ncl = toMNodeClass(cltyp, cldeg, clnum, cmind, cmaxd);
3190
3191 opt->beginSubProc(this);
3192
3193 mgraph = new MGraph(id, ncl, cldeg, clnum, cltyp, cmind, cmaxd, opt);
3194
3195 ng = mgraph->generate();
3196
3197 opt->endSubProc();
3198
3199 delete mgraph;
3200 mgraph = NULL;
3201
3202 return ng;
3203}
3204
3205//--------------------------------------------------------------
3206int SProcess::toMNodeClass(int *cltyp, int *cldeg, int *clnum, int *cmind, int *cmaxd)
3207{
3208 int j;
3209
3210 for (j = 0; j < nclass; j++) {
3211 if (isATExternal(pnclass->type[j])) {
3212 cltyp[j] = -1;
3213 } else {
3214 cltyp[j] = (pnclass->couple[j]-pnclass->deg[j]+2)/2;
3215 }
3216 cldeg[j] = pnclass->deg[j];
3217 clnum[j] = pnclass->count[j];
3218 cmind[j] = pnclass->cmindeg[j];
3219 cmaxd[j] = pnclass->cmaxdeg[j];
3220 }
3221 return nclass;
3222}
3223
3224//--------------------------------------------------------------
3225void SProcess::assign(MGraph *mgr)
3226{
3227 PNodeClass *pnc;
3228
3229 pnc = match(mgr);
3230
3231 agraph = new Assign(this, mgr, pnc);
3232
3233#ifdef CHECK
3234 agraph->checkAG("SProcess::assign");
3235#endif
3236 delete pnc;
3237 delete agraph;
3238 agraph = NULL;
3239}
3240
3241//--------------------------------------------------------------
3242PNodeClass *SProcess::match(MGraph *mgr)
3243{
3244 PNodeClass *pnc = NULL;
3245
3246 int typ[GRCC_MAXNODES], dgs[GRCC_MAXNODES];
3247 int cnt[GRCC_MAXNODES], ptcl[GRCC_MAXNODES];
3248 int cpl[GRCC_MAXNODES];
3249 int n2m[GRCC_MAXNODES];
3250 int cmind[GRCC_MAXNODES], cmaxd[GRCC_MAXNODES];
3251 int j, k, l, nd, mc, mcl, mclss;
3252
3253 if (mgr->nNodes != nNodes) {
3254 if (prlevel > 0) {
3255 grcc_fprintf(GRCC_Stderr, "*** SProcess::match: different nNodes=%d != %d\n",
3256 nNodes, mgr->nNodes);
3257 }
3258 erEnd("SProcess::match: different nNodes");
3259 }
3260
3261 mcl = toMNodeClass(typ, dgs, cnt, cmind, cmaxd);
3262
3263 nd = 0;
3264 for (j = 0; j < mcl; j++) {
3265 for (k = 0; k < cnt[j]; k++, nd++) {
3266 n2m[nd] = j;
3267 }
3268 }
3269
3270 nd = 0;
3271 mclss = mgr->curcl->nClasses;
3272 for (j = 0; j < mclss; j++) {
3273 for (k = 0; k < mgr->curcl->clist[j]; k++, nd++) {
3274 mc = mgr->nodes[nd]->clss;
3275 if (mc != n2m[nd]) {
3276 if (prlevel > 0) {
3277 grcc_fprintf(GRCC_Stderr, "*** SProcess::match: ");
3278 grcc_fprintf(GRCC_Stderr, "inconsistent class\n");
3279 for (l = 0; l < nNodes; l++) {
3280 grcc_fprintf(GRCC_Stderr, " %d: %d, %d\n",
3281 j, mgr->nodes[l]->clss, n2m[l]);
3282 }
3283 }
3284 erEnd("SProcess::match: inconsistent class");
3285 }
3286 }
3287 }
3288 for (j = 0; j < mcl; j++) {
3289 dgs[j] = pnclass->deg[j];
3290 typ[j] = pnclass->type[j];
3291 ptcl[j] = pnclass->particle[j];
3292 cnt[j] = pnclass->count[j];
3293 cpl[j] = pnclass->couple[j];
3294 cmind[j] = pnclass->cmindeg[j];
3295 cmaxd[j] = pnclass->cmaxdeg[j];
3296 }
3297 pnc = new PNodeClass(this, nNodes, mcl, dgs, typ, ptcl, cpl, cnt, cmind, cmaxd);
3298
3299 return pnc;
3300}
3301
3302//--------------------------------------------------------------
3303void SProcess::resultMGraph(BigInt nmgraphs, Fraction mwsum, BigInt nmopi, Fraction mwopi)
3304{
3305 nMGraphs += nmgraphs;
3306 nMOPI += nmopi;
3307 wMGraphs.add(mwsum);
3308 wMOPI.add(mwopi);
3309}
3310
3311//--------------------------------------------------------------
3312void SProcess::resultAGraph(BigInt nmgraphs, Fraction mwsum, BigInt nmopi, Fraction mwopi)
3313{
3314 nAGraphs += nmgraphs;
3315 nAOPI += nmopi;
3316 wAGraphs.add(mwsum);
3317 wAOPI.add(mwopi);
3318}
3319
3320//--------------------------------------------------------------
3321void SProcess::endMGraph(MGraph *mgr)
3322{
3323 egraph = mgr->egraph;
3324
3325 if (opt->values[GRCC_OPT_Step] != GRCC_MGraph) {
3326 assign(mgr);
3327 }
3328}
3329
3330//--------------------------------------------------------------
3331void SProcess::endAGraph(EGraph *egr)
3332{
3333 egraph = egr;
3334}
3335
3336
3337//==============================================================
3338// class Process
3339//--------------------------------------------------------------
3340Process::Process(int pid, Model *modl, Options *optn, int nini, int *intlPrt, int nfin, int *finlPrt, int *coupling)
3341{
3342 // Define a process and construct a set of sprocesses
3343 // model : Model object
3344 // optn : Option object
3345 // initlPart : list of particle-id of initlPart particles
3346 // finalPart : list of particle-id of final particles
3347 // coupling : list of coupling constants
3348
3349 int j, lp2;
3350 Bool ok;
3351 char buff[MAXSTR];
3352
3353 id = pid;
3354 model = modl;
3355 opt = optn;
3356 ninitl = nini;
3357 nfinal = nfin;
3358 initlPart = intdup(ninitl, intlPrt);
3359 finalPart = intdup(nfinal, finlPrt);
3360
3361 // count total number of coupling constants.
3362 ctotal = 0;
3363 for (j = 0; j < GRCC_MAXNCPLG; j++) {
3364 if (j < model->ncouple) {
3365 clist[j] = coupling[j];
3366 ctotal += coupling[j];
3367 } else {
3368 clist[j] = 0;
3369 }
3370 }
3371 if (ctotal < 1) {
3372 erEnd("Process: coupling constant = 0");
3373 }
3374
3375 nExtern = 0;
3376 loop = -1;
3377 maxnlegs = 0;
3378 mgrcount = 0;
3379 agrcount = 0;
3380
3381 // table of sprocesses
3382 nSubproc = 0;
3383 sproc = NULL;
3384
3385 // the results of the graph generation
3386 nMGraphs = 0; // the number of generated M-graphs
3387 nMOPI = 0; // the number of 1PI M-graphs
3388 wMGraphs.setValue(0,1); // the weighted sum of M-graphs
3389 wMOPI.setValue(0,1); // the weighted sum of 1PI M-graphs
3390
3391 nAGraphs = 0; // the number of generated A-graphs
3392 nAOPI = 0; // the number of 1PI A-graphs
3393 wAGraphs.setValue(0,1); // the weighted sum of A-graphs
3394 wAOPI.setValue(0,1); // the weighted sum of 1PI A-graphs
3395
3396 ok = True;
3397
3398 // numbers
3399 nExtern = ninitl + nfinal;
3400 maxnlegs = Max(nExtern, model->maxnlegs);
3401
3402 // count loops
3403 lp2 = ctotal - nExtern + 2;
3404 if (lp2 % 2 != 0) {
3405 if (prlevel > 0) {
3406 grcc_fprintf(GRCC_Stderr, "*** cannot generate : 2*loop is odd : "
3407 "2*loop = %d, ctotal=%d, nExtern=%d\n",
3408 lp2, ctotal, nExtern);
3409 }
3410 ok = False;
3411 } else if (lp2 < 0) {
3412 if (prlevel > 0) {
3413 grcc_fprintf(GRCC_Stderr, "*** cannot make a connected graph : "
3414 "2*loop=%d, ctotal=%d, nExtern=%d\n",
3415 lp2, ctotal, nExtern);
3416 }
3417 ok = False;
3418 }
3419
3420 loop = lp2 / 2;
3421
3422 if (!ok) {
3423 if (prlevel > 0) {
3424 grcc_fprintf(GRCC_Stderr, "*** Process: illegal input: lp2 = %d\n", lp2);
3425 }
3426 erEnd("Process: illegal input");
3427 }
3428
3429 if (opt->out->outgrp != NULL) {
3430 snprintf(buff, MAXSTR, "out%d.prp", pid);
3431 prProcessP(buff);
3432 }
3433
3434 // construct sprocesses
3435 mkSProcess();
3436}
3437
3438//--------------------------------------------------------------
3439Process::~Process(void)
3440{
3441 initlPart = delintdup(initlPart);
3442 finalPart = delintdup(finalPart);
3443 for (int j = 0; j < nSubproc; j++) {
3444 delete sptbl[j];
3445 }
3446 // delete sproc;
3447}
3448
3449//--------------------------------------------------------------
3450void Process::prProcess(void)
3451{
3452 grcc_fprintf(GRCC_Stdout, "+++ process options : OPI = %d, (Step) = %d, coupling=%d: ",
3453 opt->values[GRCC_OPT_1PI], opt->values[GRCC_OPT_Step], ctotal);
3454 prIntArray(model->ncouple, clist, "\n");
3455}
3456
3457//--------------------------------------------------------------
3458void Process::prProcessP(const char *fname)
3459{
3460 FILE *fp;
3461
3462 if ((fp = fopen(fname, "w")) == NULL) {
3463 grcc_fprintf(GRCC_Stderr, "*** cannot open \"%s\"\n", fname);
3464 return;
3465 }
3466 fprintf(fp, "Process = {\n");
3467 outProcP(fp);
3468 fprintf(fp, "};\n");
3469 fclose(fp);
3470}
3471
3472//--------------------------------------------------------------
3473void Process::outProcP(FILE *fp)
3474{
3475 int j;
3476
3477 if (model == NULL) {
3478 return;
3479 }
3480 fprintf(fp, " \"Model\": \"%s\",\n", model->name);
3481 fprintf(fp, " \"Initial\": [");
3482 for (j = 0; j < ninitl; j++) {
3483 if (j != 0) {
3484 fprintf(fp, ", ");
3485 }
3486 fprintf(fp, "\"%s\"", model->particleName(initlPart[j]));
3487 }
3488 fprintf(fp, "],\n");
3489 fprintf(fp, " \"Final\": [");
3490 for (j = 0; j < nfinal; j++) {
3491 if (j != 0) {
3492 fprintf(fp, ", ");
3493 }
3494 fprintf(fp, "\"%s\"", model->particleName(finalPart[j]));
3495 }
3496 fprintf(fp, "],\n");
3497 fprintf(fp, " \"Couple\": [");
3498 for (j = 0; j < model->ncouple; j++) {
3499 if (j != 0) {
3500 fprintf(fp, ", ");
3501 }
3502 fprintf(fp, "%d", clist[j]);
3503 }
3504 fprintf(fp, "],\n");
3505 fprintf(fp, " \"Options\": {\n");
3506 for (j = 0; j < GRCC_OPT_Size; j++) {
3507 if (j == GRCC_OPT_Outgrf || j == GRCC_OPT_Outgrp) {
3508 continue;
3509 }
3510 fprintf(fp, " \"%s\":%d,\n", optDef[j].name, opt->values[j]);
3511 }
3512 fprintf(fp, " \"%s\":", optDef[GRCC_OPT_Outgrf].name);
3513 if (opt->out->outgrf != NULL) {
3514 fprintf(fp, "\"%s\",\n", opt->out->outgrf);
3515 } else {
3516 fprintf(fp, "0,\n");
3517 }
3518 fprintf(fp, " \"%s\":", optDef[GRCC_OPT_Outgrp].name);
3519 if (opt->out->outgrp != NULL) {
3520 fprintf(fp, "\"%s\",\n", opt->out->outgrp);
3521 } else {
3522 fprintf(fp, "0,\n");
3523 }
3524 fprintf(fp, " }\n");
3525}
3526
3527//--------------------------------------------------------------
3528void Process::mkSProcess(void)
3529{
3530 // Construct sprocesses
3531 // Each sprocess is a set of nodes whose degree and order of
3532 // coupling constants are determined.
3533 // Only the total coupling constants are considered here even if
3534 // two or more coupling constants are defined in the model
3535
3536 NCInput cls[GRCC_MAXMINTERACT];
3537 int r, j, k, lin2, nvtx, nleg, nc, n0;
3538 int nl[GRCC_MAXMINTERACT];
3539 double proct0 = 0, proct1 = 0;
3540
3541 if (model->ncplgcp < 1) {
3542 erEnd("function 'addInteractionEnd' has not been called");
3543 }
3544 // output file to start process
3545 opt->beginProc(this);
3546
3547 // starting time
3548 Second(&proct0);
3549
3550 // generate all possible number of (nl[i]),
3551 // \sum_i nl[i]*cplgcp[i] = (total number of coupling constants)
3552
3553 r = -1;
3554 nSubproc = 0;
3555 ngraphs = 0;
3556 nopi = 0;
3557 wgraphs = 0;
3558 wopi = 0;
3559
3560 // for partitions of (leg, order)
3561
3562 while (nextPart(ctotal, model->ncplgcp, model->cplgcp, nl, &r)) {
3563 // count the total number of vertices and legs.
3564 nvtx = 0;
3565 nleg = 0;
3566 for (j = 0; j < model->ncplgcp; j++) {
3567 nvtx += nl[j];
3568 nleg += nl[j]*model->cplglg[j];
3569 }
3570
3571 // count loops
3572 lin2 = nExtern + nleg;
3573 if (lin2 % 2 != 0) {
3574 continue;
3575 }
3576 loop = lin2/2 - nExtern - nvtx + 1;
3577 if (loop < 0) {
3578 continue;
3579 }
3580
3581 nc = 0;
3582 if (opt->values[GRCC_OPT_SymmInitial]) {
3583 n0 = nc;
3584 for (j = 0; j < ninitl; j++) {
3585 for (k = n0; k < nc; k++) {
3586 if (cls[k].ptcl == initlPart[j]) {
3587 cls[k].clnum++;
3588 break;
3589 }
3590 }
3591 if (k >= nc) {
3592 cls[nc].ptcl = initlPart[j];
3593 cls[nc].clnum = 1;
3594 cls[nc].cple = 0;
3595 cls[nc].clnum = 1;
3596 cls[nc].cldeg = 1;
3597 cls[nc].cltyp = GRCC_AT_Initial;
3598 cls[nc].ptcl = initlPart[j];
3599 cls[nc].cmind
3600 = model->particles[Abs(cls[nc].ptcl)]->cmindeg;
3601 cls[nc].cmaxd
3602 = model->particles[Abs(cls[nc].ptcl)]->cmaxdeg;
3603 if (opt->values[GRCC_OPT_NoExtSelf] > 0 && nExtern > 2) {
3604 cls[nc].cmind = Max(cls[nc].cmind, 3);
3605 }
3606 nc++;
3607 }
3608 }
3609 } else {
3610 for (j = 0; j < ninitl; j++) {
3611 cls[nc].ptcl = initlPart[j];
3612 cls[nc].clnum = 1;
3613 cls[nc].cple = 0;
3614 cls[nc].cldeg = 1;
3615 cls[nc].cltyp = GRCC_AT_Initial;
3616 cls[nc].cmind = model->particles[Abs(cls[nc].ptcl)]->cmindeg;
3617 cls[nc].cmaxd = model->particles[Abs(cls[nc].ptcl)]->cmaxdeg;
3618 if (opt->values[GRCC_OPT_NoExtSelf] > 0 && nExtern > 2) {
3619 cls[nc].cmind = Max(cls[nc].cmind, 3);
3620 }
3621 nc++;
3622 }
3623 }
3624 if (opt->values[GRCC_OPT_SymmFinal]) {
3625 n0 = nc;
3626 for (j = 0; j < nfinal; j++) {
3627 for (k = n0; k < nc; k++) {
3628 if (cls[k].ptcl == model->antiParticle(finalPart[j])) {
3629 cls[k].clnum++;
3630 break;
3631 }
3632 }
3633 if (k >= nc) {
3634 cls[nc].ptcl = model->antiParticle(finalPart[j]);
3635 cls[nc].clnum = 1;
3636 cls[nc].cple = 0;
3637 cls[nc].cldeg = 1;
3638 cls[nc].cltyp = GRCC_AT_Final;
3639 cls[nc].cmind
3640 = model->particles[Abs(cls[nc].ptcl)]->cmindeg;
3641 cls[nc].cmaxd
3642 = model->particles[Abs(cls[nc].ptcl)]->cmaxdeg;
3643 if (opt->values[GRCC_OPT_NoExtSelf] > 0 && nExtern > 2) {
3644 cls[nc].cmind = Max(cls[nc].cmind, 3);
3645 }
3646 nc++;
3647 }
3648 }
3649 } else {
3650 for (j = 0; j < nfinal; j++) {
3651 cls[nc].ptcl = model->antiParticle(finalPart[j]);
3652 cls[nc].cldeg = 1;
3653 cls[nc].cple = 0;
3654 cls[nc].clnum = 1;
3655 cls[nc].cltyp = GRCC_AT_Final;
3656 cls[nc].cmind = model->particles[Abs(cls[nc].ptcl)]->cmindeg;
3657 cls[nc].cmaxd = model->particles[Abs(cls[nc].ptcl)]->cmaxdeg;
3658 if (opt->values[GRCC_OPT_NoExtSelf] > 0 && nExtern > 2) {
3659 cls[nc].cmind = Max(cls[nc].cmind, 3);
3660 }
3661 nc++;
3662 }
3663 }
3664 for (j = 0; j < model->ncplgcp; j++) {
3665 if (nl[j] > 0) {
3666 cls[nc].ptcl = 0;
3667 cls[nc].cple = model->cplgcp[j];
3668 cls[nc].cldeg = model->cplglg[j];
3669 cls[nc].clnum = nl[j];
3670 // number of loops
3671 cls[nc].cltyp = (model->cplgcp[j] - model->cplglg[j] + 2)/2;
3672 cls[nc].cmind = 0;
3673 cls[nc].cmaxd = 0;
3674 nc++;
3675 }
3676 }
3677 // create a sprocess ??? to be rewritten
3678 sproc = new SProcess(model, this, opt, nSubproc, clist, nc, cls);
3679
3680 // list of sprocesses
3681 if (nSubproc >= GRCC_MAXSUBPROCS) {
3682 erEnd("Subclass: too many sprocesses (GRCC_MAXSUBPROCS)");
3683 }
3684 sptbl[nSubproc++] = sproc;
3685
3686 // generate M-graphs
3687 sproc->generate();
3688
3689 // summation of the numbers and weighted numbers of graphs
3690 nMGraphs += sproc->nMGraphs;
3691 nMOPI += sproc->nMOPI;
3692 wMGraphs.add(sproc->wMGraphs);
3693 wMOPI.add(sproc->wMOPI);
3694
3695 nAGraphs += sproc->nAGraphs;
3696 nAOPI += sproc->nAOPI;
3697 wAGraphs.add(sproc->wAGraphs);
3698 wAOPI.add(sproc->wAOPI);
3699
3700 if (nAGraphs > 0) {
3701 ngraphs = nAGraphs;
3702 } else {
3703 ngraphs = nAGraphs;
3704 }
3705 // delete sproc;
3706 // sproc = NULL;
3707 }
3708
3709 // ending time
3710 Second(&proct1);
3711 sec = proct1-proct0;
3712
3713 // output file to finish process
3714 opt->endProc();
3715}
3716
3717//**************************************************************
3718// mgraph.cc
3719//==============================================================
3720//--------------------------------------------------------------
3721MNodeClass::MNodeClass(int nnodes, int nclasses)
3722{
3723 // Input
3724 // nnodes : possible maximal number of nodes
3725 // nclasses : possible maximal number of classes
3726
3727 int j, k;
3728
3729 nNodes = nnodes;
3730 nClasses = nclasses;
3731 maxdeg = 0;
3732 for (j = 0; j < nNodes; j++) {
3733 for (k = 0; k < nNodes; k++) {
3734 clmat[j][k] = 0;
3735 }
3736 clist[j] = 0;
3737 ndcl[j] = 0;
3738 flist[j] = 0;
3739 clord[j] = 0;
3740 cmindeg[j] = 0;
3741 cmaxdeg[j] = 0;
3742 }
3743 flist[nNodes] = 0;
3744 flg0 = 0;
3745 flg1 = 0;
3746 flg2 = 0;
3747}
3748
3749//--------------------------------------------------------------
3750MNodeClass::~MNodeClass(void)
3751{
3752}
3753
3754//==============================================================
3755// class MNodeClass
3756//--------------------------------------------------------------
3757void MNodeClass::init(int *cl, int mxdeg, int **adjmat)
3758{
3759 // initialize the object
3760 // Argument
3761 // cl[j] : list of number of nodes in the j-th class
3762 // mxdeg : maximum degree to nodes
3763 // adjmat[j][k] : adjacency matrix
3764
3765 int j;
3766
3767 for (j = 0; j < nClasses; j++) {
3768 clist[j] = cl[j];
3769 clord[j] = j;
3770 }
3771 maxdeg = mxdeg;
3772 mkNdCl();
3773 mkClMat(adjmat);
3774 mkFlist();
3775 flg0 = 0;
3776 flg1 = 0;
3777 flg2 = 0;
3778}
3779
3780//--------------------------------------------------------------
3781void MNodeClass::copy(MNodeClass* mnc)
3782{
3783 // copy MNodeClass 'mnc' to this object
3784
3785 int j, k;
3786
3787 nClasses = mnc->nClasses;
3788 for (k = 0; k < nClasses; k++) {
3789 clist[k] = mnc->clist[k];
3790 }
3791 maxdeg = mnc->maxdeg;
3792 for (j = 0; j < nNodes; j++) {
3793 ndcl[j] = mnc->ndcl[j];
3794 clord[j] = mnc->clord[j];
3795 for (k = 0; k < nClasses; k++) {
3796 clmat[j][k] = mnc->clmat[j][k];
3797 }
3798 }
3799 for (k = 0; k < nClasses+1; k++) {
3800 flist[k] = mnc->flist[k];
3801 }
3802}
3803
3804//--------------------------------------------------------------
3805void MNodeClass::mkFlist(void)
3806{
3807 // Construct flist
3808 // The set of nodes in class 'c' is [flist[c],...,flist[c+1]-1]
3809
3810 int j, f;
3811
3812 f = 0;
3813 for (j = 0; j < nClasses; j++) {
3814 flist[j] = f;
3815 f += clist[j];
3816 }
3817 flist[nClasses] = f;
3818}
3819
3820//--------------------------------------------------------------
3821void MNodeClass::mkNdCl(void)
3822{
3823 // Construct ndcl
3824 // ndcl[nd] = (the class id in which node 'nd' belongs)
3825
3826 int c, k;
3827 int nd = 0;
3828
3829 for (c = 0; c < nClasses; c++) {
3830 for (k = 0; k < clist[c]; k++) {
3831 ndcl[nd++] = c;
3832 }
3833 }
3834}
3835
3836//--------------------------------------------------------------
3837int MNodeClass::clCmp(int nd0, int nd1, int cn)
3838{
3839 // Comparison of two nodes 'nd0' and 'nd1'
3840 // in lexicographic ordering of [class, connection configuration]
3841
3842 int cmp;
3843 // Wether two nodes are in a same class or not.
3844
3845 cmp = ndcl[nd0] - ndcl[nd1];
3846 if (cmp != 0) {
3847 return cmp;
3848 }
3849
3850 // Sign '-' signifies the reverse ordering
3851 cmp = - cmpMNCArray(clmat[nd0], clmat[nd1], cn);
3852 if (cmp != 0) {
3853 return cmp;
3854 }
3855 return cmp;
3856}
3857
3858//--------------------------------------------------------------
3859void MNodeClass::mkClMat(int **adjmat)
3860{
3861 // Construct a matrix 'clmat[nd][tc]' which is the number
3862 // of edges connecting 'nd' and all nodes in class 'tc'.
3863
3864 int nd, td, tc;
3865
3866 for (nd = 0; nd < nNodes; nd++) {
3867 for (td = 0; td < nNodes; td++) {
3868 tc = ndcl[td]; // another node
3869 if (nd == td) {
3870 clmat[nd][tc] += CLWIGHTD(adjmat[nd][td]);
3871 } else {
3872 clmat[nd][tc] += CLWIGHTO(adjmat[nd][td]);
3873 }
3874 }
3875 }
3876}
3877
3878//--------------------------------------------------------------
3879void MNodeClass::incMat(int nd, int td, int val)
3880{
3881 // Increase the number of edges by 'val' between 'nd' and 'td'.
3882
3883 int tdc = ndcl[td]; // class of 'td'
3884 clmat[nd][tdc] += val; // modify matrix 'clmat'.
3885}
3886
3887//--------------------------------------------------------------
3888void MNodeClass::printMat(void)
3889{
3890 // Print configuration matrix.
3891
3892 int j1, j2;
3893
3894 grcc_fprintf(GRCC_Stdout, "\n");
3895
3896 grcc_fprintf(GRCC_Stdout, "nClasses=%d", nClasses);
3897 grcc_fprintf(GRCC_Stdout, " clord="); prIntArray(nClasses, clord, "");
3898 grcc_fprintf(GRCC_Stdout, " flist="); prIntArray(nClasses, flist, "\n");
3899 grcc_fprintf(GRCC_Stdout, "flg = (%d, %d, %d)\n", flg0, flg1, flg2);
3900
3901 // the first line
3902 grcc_fprintf(GRCC_Stdout, "nd: cl: ");
3903 for (j2 = 0; j2 < nClasses; j2++) {
3904 grcc_fprintf(GRCC_Stdout, "%2d ", j2);
3905 }
3906 grcc_fprintf(GRCC_Stdout, "\n");
3907
3908 // print raw
3909 for (j1 = 0; j1 < nNodes; j1++) {
3910 grcc_fprintf(GRCC_Stdout, "%2d; %2d: [", j1, ndcl[j1]);
3911 for (j2 = 0; j2 < nClasses; j2++) {
3912 grcc_fprintf(GRCC_Stdout, " %2d", clmat[j1][j2]);
3913 }
3914 grcc_fprintf(GRCC_Stdout, "]\n");
3915 }
3916}
3917
3918//--------------------------------------------------------------
3919int MNodeClass::cmpMNCArray(int *a0, int *a1, int ma)
3920{
3921 int j, k;
3922
3923 for (k = 0; k < ma; k++) {
3924 j = clord[k];
3925 if (a0[j] < a1[j]) {
3926 return -1;
3927 } else if (a0[j] > a1[j]) {
3928 return 1;
3929 }
3930 }
3931 return 0;
3932}
3933
3934//--------------------------------------------------------------
3935void MNodeClass::reorder(MGraph *mg)
3936{
3937 int flg[GRCC_MAXNODES];
3938 int co, cn;
3939 int f0, f1, f2;
3940
3941 f0 = 0;
3942 f1 = 0;
3943 f2 = 0;
3944 for (co = 0; co < nClasses; co++) {
3945 cn = flist[co];
3946 if (mg->nodes[cn]->freelg < 1) {
3947 flg[co] = 0;
3948 f0++;
3949 } else if (mg->nodes[cn]->freelg < mg->nodes[cn]->deg) {
3950 flg[co] = mg->nodes[cn]->deg + maxdeg*clist[co];
3951 f1++;
3952 } else {
3953 flg[co] = maxdeg*(mg->nodes[cn]->deg + maxdeg*clist[co]);
3954 f2++;
3955 }
3956 }
3957 if (f0 < nClasses) {
3958 bsort(nClasses, clord, flg);
3959 }
3960 flg0 = f0;
3961 flg1 = f0 + f1;
3962 flg2 = f0 + f1 + f2;
3963}
3964
3965//==============================================================
3966// class MNode : nodes in MGraph
3967//--------------------------------------------------------------
3968MNode::MNode(int vid, int vclss, NCInput *mgi)
3969{
3970 // Arguments
3971 // vid : identifier of the vertex
3972 // vdeg : degree of the node
3973 // vextlp : external node (-1) or looped vertex
3974 // vclss : class of the node
3975
3976 id = vid; // id of the node
3977 clss = vclss; // class to which the node belongs
3978 deg = mgi->cldeg; // degree of the node
3979 freelg = mgi->cldeg; // number of free legs
3980 extloop = mgi->cltyp; // external node or not
3981 cmindeg = mgi->cmind; // min(deg of connectable vertex)
3982 cmaxdeg = mgi->cmaxd; // max(deg of connectable vertex)
3983}
3984
3985//--------------------------------------------------------------
3986MNode::MNode(int vid, int vdeg, int vextlp, int vclss, int cmin, int cmax)
3987{
3988 // Arguments
3989 // vid : identifier of the vertex
3990 // vdeg : degree of the node
3991 // vextlp : external node (-1) or looped vertex
3992 // vclss : class of the node
3993
3994 id = vid; // id of the node
3995 deg = vdeg; // degree of the node
3996 freelg = vdeg; // number of free legs
3997 clss = vclss; // class to which the node belongs
3998 extloop = vextlp; // external node or not
3999 cmindeg = cmin; // min(deg of connectable vertex)
4000 cmaxdeg = cmax; // max(deg of connectable vertex)
4001}
4002
4003//===============================================================
4004// class MGraph : scalar graph expressed by matrix form
4005//---------------------------------------------------------------
4006MGraph::MGraph(int pid, int ncl, int *cldeg, int *clnum, int *cltyp, int *cmind, int *cmaxd, Options *opts)
4007{
4008 int nn, ne, j, k;
4009
4010 // initial conditions
4011 nClasses = ncl;
4012 clist = new int[ncl];
4013 opt = opts;
4014 mId = -1;
4015
4016 mindeg = -1;
4017 maxdeg = -1;
4018 ne = 0;
4019 nn = 0;
4020 for (j = 0; j < nClasses; j++) {
4021 clist[j] = clnum[j];
4022 nn += clnum[j];
4023 ne += cldeg[j]*clnum[j];
4024 if (mindeg < 0) {
4025 mindeg = cldeg[j];
4026 } else {
4027 mindeg = Min(mindeg, cldeg[j]);
4028 }
4029 if (maxdeg < 0) {
4030 maxdeg = cldeg[j];
4031 } else {
4032 maxdeg = Max(maxdeg, cldeg[j]);
4033 }
4034 }
4035 if (ne % 2 != 0) {
4036 if (prlevel > 0) {
4037 grcc_fprintf(GRCC_Stderr, "Sum of degrees are not even\n");
4038 for (j = 0; j < nClasses; j++) {
4039 grcc_fprintf(GRCC_Stderr, "class %2d: %2d %2d %2d\n",
4040 j, cldeg[j], clnum[j], cltyp[j]);
4041 }
4042 }
4043 erEnd("illegal degrees of nodes");
4044 }
4045 pId = pid;
4046 nNodes = nn;
4047 nodes = new MNode*[nNodes];
4048 group = new SGroup();
4049#ifdef ORBITS
4050 orbits = new MOrbits();
4051#endif
4052
4053 nEdges = ne / 2;
4054 nLoops = nEdges - nNodes + 1;
4055
4056 egraph = new EGraph(nNodes, nEdges, maxdeg);
4057 nn = 0;
4058 nExtern = 0;
4059 for (j = 0; j < nClasses; j++) {
4060 for (k = 0; k < clist[j]; k++, nn++) {
4061 nodes[nn] = new MNode(nn, cldeg[j], cltyp[j], j, cmind[j], cmaxd[j]);
4062 egraph->setExtLoop(nn, cltyp[j]);
4063 if (cltyp[j] < 0) {
4064 nExtern++;
4065 }
4066 }
4067 }
4068 egraph->endSetExtLoop();
4069
4070 init();
4071}
4072
4073//---------------------------------------------------------------
4074MGraph::MGraph(int pid, int ncl, NCInput *mgi, Options *opts)
4075{
4076 int nn, ne, j, k;
4077
4078 // initial conditions
4079 nClasses = ncl;
4080 clist = new int[ncl];
4081 opt = opts;
4082 mId = -1;
4083
4084 mindeg = -1;
4085 maxdeg = -1;
4086 ne = 0;
4087 nn = 0;
4088 for (j = 0; j < nClasses; j++) {
4089 clist[j] = mgi[j].clnum;
4090 nn += mgi[j].clnum;
4091 ne += mgi[j].cldeg*mgi[j].clnum;
4092 if (mindeg < 0) {
4093 mindeg = mgi[j].cldeg;
4094 } else {
4095 mindeg = Min(mindeg, mgi[j].cldeg);
4096 }
4097 if (maxdeg < 0) {
4098 maxdeg = mgi[j].cldeg;
4099 } else {
4100 maxdeg = Max(maxdeg, mgi[j].cldeg);
4101 }
4102 }
4103 if (ne % 2 != 0) {
4104 if (prlevel > 0) {
4105 grcc_fprintf(GRCC_Stderr, "Sum of degrees are not even\n");
4106 for (j = 0; j < nClasses; j++) {
4107 grcc_fprintf(GRCC_Stderr, "class %2d: %2d %2d %2d\n",
4108 j, mgi[j].cldeg, mgi[j].clnum, mgi[j].cltyp);
4109 }
4110 }
4111 erEnd("illegal degrees of nodes");
4112 }
4113 pId = pid;
4114 nNodes = nn;
4115 if (nNodes < 0) {
4116 grcc_fprintf(GRCC_Stdout, "*** nNodes = %d\n", nNodes);
4117 erEnd("MGraph::MGrap : nNodes < 0");
4118 }
4119 nodes = new MNode*[nNodes];
4120 group = new SGroup();
4121#ifdef ORBITS
4122 orbits = new MOrbits();
4123#endif
4124
4125 nEdges = ne / 2;
4126 nLoops = nEdges - nNodes + 1;
4127
4128 egraph = new EGraph(nNodes, nEdges, maxdeg);
4129 nn = 0;
4130 nExtern = 0;
4131 for (j = 0; j < nClasses; j++) {
4132 for (k = 0; k < clist[j]; k++, nn++) {
4133 nodes[nn] = new MNode(nn, j, mgi+j);
4134 egraph->setExtLoop(nn, mgi[j].cltyp);
4135 if (mgi[j].cltyp < 0) {
4136 nExtern++;
4137 }
4138 }
4139 }
4140 egraph->endSetExtLoop();
4141
4142 init();
4143}
4144
4145//---------------------------------------------------------------
4146void MGraph::init(void)
4147{
4148 // generated set of graphs
4149 cDiag = 0;
4150 c1PI = 0;
4151 cNoTadpole = 0;
4152 cNoTadBlock = 0;
4153 c1PINoTadBlock = 0;
4154
4155 // the current graph
4156 adjMat = newMat(nNodes, nNodes, 0);
4157 nsym = ToBigInt(0);
4158 esym = ToBigInt(0);
4159 wscon = Fraction(0, 1);
4160 wsopi = Fraction(0, 1);
4161
4162 // current node classification
4163 curcl = new MNodeClass(nNodes, nClasses);
4164
4165 // table of n-edge connected components
4166 mconn = new MConn(nNodes, nEdges);
4167
4168 // measures of efficiency
4169 ngen = 0;
4170 ngconn = 0;
4171
4172#ifdef MONITOR
4173 nCallRefine = 0;
4174 discardRefine = 0;
4175 discardDisc = 0;
4176 discardIso = 0;
4177#endif
4178
4179 // work space for isIsomorphic
4180 modmat = newMat(nNodes, nNodes, 0);
4181
4182 // work space for bisearchME
4183 bidef = newArray(nNodes, 0);
4184 bilow = newArray(nNodes, 0);
4185 bicol = newArray(nNodes, 0);
4186 bicount = 0;
4187}
4188
4189//---------------------------------------------------------------
4190MGraph::~MGraph(void)
4191{
4192 int j;
4193
4194 // group->delGroup();
4195
4196 bicol = deleteArray(bicol);
4197 bilow = deleteArray(bilow);
4198 bidef = deleteArray(bidef);
4199
4200
4201 modmat = deleteMat(modmat, nNodes);
4202 delete mconn;
4203 delete curcl;
4204 adjMat = deleteMat(adjMat, nNodes);
4205#ifdef ORBITS
4206 delete orbits;
4207#endif
4208 delete egraph;
4209 delete group;
4210 for (j = 0; j < nNodes; j++) {
4211 delete nodes[j];
4212 nodes[j] = NULL;
4213 }
4214 delete[] nodes;
4215 delete[] clist;
4216
4217}
4218
4219//---------------------------------------------------------------
4220void MGraph::printAdjMat(MNodeClass *cl)
4221{
4222 int j1, j2;
4223
4224 grcc_fprintf(GRCC_Stdout, " ");
4225 for (j2 = 0; j2 < nNodes; j2++) {
4226 grcc_fprintf(GRCC_Stdout, " %2d", j2);
4227 }
4228 grcc_fprintf(GRCC_Stdout, "\n");
4229 for (j1 = 0; j1 < nNodes; j1++) {
4230 grcc_fprintf(GRCC_Stdout, "%2d : [", j1);
4231 for (j2 = 0; j2 < nNodes; j2++) {
4232 grcc_fprintf(GRCC_Stdout, " %2d", adjMat[j1][j2]);
4233 }
4234 grcc_fprintf(GRCC_Stdout, "] %2d\n", cl->ndcl[j1]);
4235 }
4236}
4237
4238//---------------------------------------------------------------
4239void MGraph::print(void)
4240{
4241 int j;
4242
4243 grcc_fprintf(GRCC_Stdout, "MGraph: pId=%d, cDiag=%ld, c1PI=%ld\n", pId, cDiag, c1PI);
4244 grcc_fprintf(GRCC_Stdout, " nNodes=%d, nEdges=%d, nExtern=%d, nLoops=%d "
4245 "mindeg=%d, maxdeg=%d, sym=(%ld, %ld)\n",
4246 nNodes, nEdges, nExtern, nLoops, mindeg, maxdeg, nsym, esym);
4247 grcc_fprintf(GRCC_Stdout, " Nodes=%d\n", nNodes);
4248 for (j = 0; j < nNodes; j++) {
4249 grcc_fprintf(GRCC_Stdout, " %2d: id=%d, deg=%d, clss=%d, extloop=%d, ",
4250 j, nodes[j]->id, nodes[j]->deg, nodes[j]->clss,
4251 nodes[j]->extloop);
4252 grcc_fprintf(GRCC_Stdout, "mind=%d, maxd=%d, freelg=%d\n",
4253 nodes[j]->cmindeg, nodes[j]->cmaxdeg, nodes[j]->freelg);
4254 }
4255
4256 curcl->printMat();
4257 grcc_fprintf(GRCC_Stdout, "\n");
4258
4259 printAdjMat(curcl);
4260}
4261
4262//---------------------------------------------------------------
4263void MGraph::printPy(FILE *fp, long mId)
4264{
4265 fprintf(fp, "#TGraph : (gseq, gid, nodes, amat)\n");
4266 fprintf(fp, "(%ld, (%d, %d),\n", mId, pId, -1);
4267 fprintf(fp, " [ # nodes: (cid, deg0, loop, part)\n");
4268 for (int j = 0; j < nNodes; j++) {
4269 fprintf(fp, " (%2d,%2d,%2d,%2d), # %2d\n",
4270 nodes[j]->clss, nodes[j]->deg, nodes[j]->extloop, 0, j);
4271 }
4272 fprintf(fp, " ],\n");
4273 fprintf(fp, " [\n");
4274 fprintf(fp, " #");
4275 for (int j2 = 0; j2 < nNodes; j2++) {
4276 fprintf(fp, " %4d", j2);
4277 }
4278 fprintf(fp, "\n");
4279 for (int j1 = 0; j1 < nNodes; j1++) {
4280 fprintf(fp, " [");
4281 for (int j2 = 0; j2 < nNodes; j2++) {
4282 fprintf(fp, " %2d, ", adjMat[j1][j2]);
4283 }
4284 fprintf(fp, "], # %2d\n", j1);
4285 }
4286 fprintf(fp, " ], # nodes\n");
4287 fprintf(fp, " [ # group of 2 elements\n");
4288 fprintf(fp, " [],\n");
4289 fprintf(fp, " ], # group\n");
4290 fprintf(fp, ")\n");
4291}
4292
4293//---------------------------------------------------------------
4294Bool MGraph::isConnected(void)
4295{
4296 // Check graph can be a connected one.
4297 // If a connected component without free leg is not the whole graph then
4298 // return False, otherwise return True.
4299
4300 int j, n, nv;
4301
4302 for (j = 0; j < nNodes; j++) {
4303 nodes[j]->visited = -1;
4304 }
4305 if (visit(0)) {
4306 return True;
4307 }
4308 nv = 0;
4309 for (n = 0; n < nNodes; n++) {
4310 if (nodes[n]->visited >= 0) {
4311 nv++;
4312 }
4313 }
4314 return (nv == nNodes);
4315}
4316
4317//---------------------------------------------------------------
4318Bool MGraph::visit(int nd)
4319{
4320 // Visiting connected node used for 'isConnected'
4321 // If child nodes has free legs, then this function returns True.
4322 // otherwise it returns False.
4323
4324 int td;
4325
4326 // This node has free legs.
4327 if (nodes[nd]->freelg > 0) {
4328 return True;
4329 }
4330 nodes[nd]->visited = 0;
4331 for (td = 0; td < nNodes; td++) {
4332 if ((adjMat[nd][td] > 0) && (nodes[td]->visited < 0)) {
4333 if (visit(td)) {
4334 return True;
4335 }
4336 }
4337 }
4338 // all the child nodes has no free legs.
4339 return False;
4340}
4341
4342//---------------------------------------------------------------
4343Bool MGraph::isIsomorphic(MNodeClass *cl)
4344{
4345 // Check whether the current graph is the Representative
4346 // of a isomorphic class.
4347 // nsym = symmetry factor by the permutation of nodes.
4348 // esym = symmetry factor by the permutation of edge.
4349 // If this graph is not a representative, then returns False.
4350
4351 int j1, j2, cmp, nself;
4352 int *perm;
4353
4354 nsym = ToBigInt(0);
4355 esym = ToBigInt(1);
4356
4357 group->newGroup(nNodes, cl->nClasses, cl->clist);
4358
4359#ifdef ORBITS
4360 orbits->initPerm(nNodes);
4361#endif
4362
4363 while (True) {
4364 perm = group->genNext();
4365
4366 if (perm == NULL) {
4367 // calculate permutations of edges
4368 esym = ToBigInt(1);
4369 for (j1 = 0; j1 < nNodes; j1++) {
4370 if (adjMat[j1][j1] > 0) {
4371 nself = adjMat[j1][j1]/2;
4372 esym *= factorial(nself);
4373 esym *= ipow(2, nself);
4374 }
4375 for (j2 = j1+1; j2 < nNodes; j2++) {
4376 if (adjMat[j1][j2] > 0) {
4377 esym *= factorial(adjMat[j1][j2]);
4378 }
4379 }
4380 }
4381 return True;
4382 }
4383
4384 permMat(nNodes, perm, adjMat, modmat);
4385 cmp = compMat(nNodes, adjMat, modmat);
4386 if (cmp < 0) {
4387 return False;
4388 } else if (cmp == 0) {
4389 // if ngroup < 0, symmetry group is $S_{-group}$.
4390 group->addGroup(perm);
4391
4392 nsym = nsym + ToBigInt(1);
4393#ifdef ORBITS
4394 orbits->fromPerm(perm);
4395#endif
4396 }
4397 }
4398}
4399
4400//---------------------------------------------------------------
4401void MGraph::permMat(int size, int *perm, int **mat0, int **mat1)
4402{
4403 // apply permutation to matrix 'mat0' and obtain 'mat1'
4404
4405 int j1, j2;
4406
4407 for (j1 = 0; j1 < size; j1++) {
4408 for (j2 = 0; j2 < size; j2++) {
4409 mat1[j1][j2] = mat0[perm[j1]][perm[j2]];
4410 }
4411 }
4412}
4413
4414//---------------------------------------------------------------
4415int MGraph::compMat(int size, int **mat0, int **mat1)
4416{
4417 // comparison of matrix
4418
4419 int j1, j2, cmp;
4420
4421 for (j1 = 0; j1 < size; j1++) {
4422 for (j2 = 0; j2 < size; j2++) {
4423 cmp = mat0[j1][j2] - mat1[j1][j2];
4424 if (cmp != 0) {
4425 return cmp;
4426 }
4427 }
4428 }
4429 return 0;
4430}
4431
4432//---------------------------------------------------------------
4433MNodeClass *MGraph::refineClass(MNodeClass *cl)
4434{
4435 // Refine the classification
4436 // cl : the current 'MNodeClass' object
4437 // cn : the class number
4438 // Returns (the new class number corresponds to 'cn') if OK, or
4439 // 'None' if ordering condition is not satisfied
4440
4441 MNodeClass *ccl = cl;
4442 MNodeClass *xcl = NULL;
4443 MNodeClass *ncl = NULL;
4444 int ucl[GRCC_MAXNODES];
4445 int ccn = cl->nClasses;
4446 int nucl, nce;
4447 int td, cmp;
4448 int nccl;
4449
4450#ifdef MONITOR
4451 nCallRefine++;
4452#endif
4453 nucl = 0;
4454 while (ccl->nClasses != nucl) { // repeat refinement.
4455 nce = 0;
4456 nucl = 0;
4457 for (td = 1; td < nNodes; td++) {
4458 // 'td' is the next node and the current node is 'td-1'.
4459 // Count up the number of the elements in the current class
4460 // corresponding to the current node
4461 nce++;
4462 cmp = ccl->clCmp(td-1, td, ccn);
4463
4464 // the ordering condition is not satisfied.
4465 if (cmp > 0) {
4466 if (ccl != cl) {
4467 delete ccl;
4468 }
4469 return NULL;
4470
4471 } else if (cmp < 0) {
4472 // 'td' is in the next class to the current node.
4473 ucl[nucl++] = nce; // close the current class
4474
4475 // start new class
4476 nce = 0;
4477 }
4478 // nothing to do for the case of 'cmp == 0'.
4479
4480 }
4481
4482 // close array 'ucl'.
4483 ucl[nucl++] = nce + 1;
4484
4485#ifdef CHECK
4486 // inconsistent
4487 if (nucl < ccl->nClasses) {
4488 erEnd("refineClasses : smaller number of classes");
4489 }
4490#endif
4491
4492 // preparation of the next repetition.
4493 xcl = new MNodeClass(nNodes, nucl);
4494 xcl->init(ucl, maxdeg, adjMat);
4495 ccn = xcl->nClasses;
4496
4497 nccl = ccl->nClasses;
4498
4499 if (ccl != cl) {
4500 delete ccl;
4501 }
4502 ccl = xcl;
4503 if (ccl->nClasses == nccl) {
4504 ccl->reorder(this);
4505 return ccl;
4506 }
4507
4508 nucl = 0;
4509 }
4510
4511 return ncl;
4512}
4513
4514//---------------------------------------------------------------
4515void MGraph::biconnME(void)
4516{
4517 // Count the number of 1PI components.
4518
4519 int j, j1, root, vr, next, nart;
4520 MCOpi mopi;
4521 MCBlock mblk;
4522 ULong momset;
4523
4524 // initialization
4525 bicount = 0;
4526 mconn->init();
4527 mconn->initCEdges(this);
4528
4529 for (j = 0; j < nNodes; j++) {
4530 bidef[j] = -1;
4531 bilow[j] = -1;
4532 bicol[j] = 0;
4533 }
4534 bipart = True;
4535
4536 // find a root for the root of bisearch
4537 // root must be an external node
4538 // or an vertex when there are not external nodes.
4539 root = -1;
4540 vr = -1;
4541 for (j = 0; j < nNodes; j++) {
4542 if (bidef[j] < 0) {
4543 if (isExternal(j)) {
4544 root = j;
4545 break;
4546 } else if (vr < 0) {
4547 vr = j;
4548 }
4549 }
4550 }
4551 // case (2)
4552 if (root < 0) {
4553 root = vr;
4554 }
4555
4556 if (root >= 0) {
4557 bisearchME(root, -1, 0, 1, &mopi, &mblk, &momset, &next, &nart);
4558
4559 mconn->nlpopic = 0;
4560 mconn->nctopic = 0;
4561 for (j = 0; j < mconn->nopic; j++) {
4562 if (mconn->opics[j].loop > 0) {
4563 mconn->nlpopic++;
4564 } else if (mconn->opics[j].ctloop > 0) {
4565 mconn->nctopic++;
4566 }
4567 }
4568
4569 mconn->ne0bridges = 0;
4570 mconn->ne1bridges = 0;
4571 for (j = 0; j < mconn->nbridges; j++) {
4572 if (mconn->bridges[j].next == 0) {
4573 mconn->ne0bridges++;
4574 }
4575 if (mconn->bridges[j].next == 1) {
4576 mconn->ne1bridges++;
4577 }
4578 }
4579
4580 mconn->nselfloops = 0;
4581 for (j = 0; j < nNodes; j++) {
4582 mconn->nselfloops += adjMat[j][j]/2;
4583 }
4584
4585 mconn->nmultiedges = 0;
4586 for (j = 0; j < nNodes; j++) {
4587 for (j1 = j+1; j1 < nNodes; j1++) {
4588 if (adjMat[j][j1] > 1) {
4589 mconn->nmultiedges++;
4590 }
4591 }
4592 }
4593
4594 mconn->na1blocks = 0;
4595 for (j = 0; j < mconn->nblocks; j++) {
4596 if (mconn->blocks[j].nartps == 1) {
4597 mconn->na1blocks++;
4598 }
4599 }
4600 mconn->neblocks = mconn->nblocks + mconn->nctopic;
4601
4602#ifdef CHECK
4603 if (True) {
4604 if (isExternal(root)) {
4605 momset |= MASK(root);
4606 }
4607 ULong m = 0;
4608 for (j = 0; j < nExtern; j++) {
4609 m |= MASK(j);
4610 }
4611 bool ok = True;
4612 if (momset != m) {
4613 grcc_fprintf(GRCC_Stdout, "*** momset = %ld != %ld\n", momset, m);
4614 ok = False;
4615 }
4616 if (mconn->nbacked != nLoops) {
4617 grcc_fprintf(GRCC_Stdout, "*** nbacked = %d != %c\n", mconn->nbacked, nLoops);
4618 ok = False;
4619 }
4620 if (! ok) {
4621 print();
4622 egraph->print();
4623 mconn->print();
4624 erEnd("biconnME: illegal connection");
4625 }
4626 }
4627#endif
4628
4629 // no vertex.
4630 } else {
4631 // no vertices
4632 // Connected ==> only when ex=2, loop=0
4633 mconn->nopic = 0;
4634 mconn->ne0bridges = 0;
4635 mconn->ne1bridges = 0;
4636 }
4637}
4638
4639//---------------------------------------------------------------
4640void MGraph::bisearchME(int nd, int pd, int ned, int col,
4641 MCOpi *mopi, MCBlock *mblk, ULong *momset, int *next, int *nart)
4642{
4643 // Search biconnected component
4644 // visit : pd --> nd --> td
4645 // ned : the number of edges between pd and nd.
4646 // Output
4647 //
4648 // |
4649 // x----+
4650 // | |
4651 // ----x pd |
4652 // | |
4653 // x----x nd | n art. pints.
4654 // | /|\ |
4655 // | / | \ |
4656 // m art p. x-x | x-x
4657 // n1 x n3
4658 // n2
4659 //
4660 // output of bisearchME(n1, nd, ...) ==> npart = m
4661 // output of bisearchME(n2, nd, ...) ==> npart = 1
4662 // output of bisearchME(n3, nd, ...) ==> npart = n
4663 //
4664 // output of bisearchME(nd, pd, ...) ==> npart = n+1
4665 // n1 => block of (m+1) articulation points
4666 // n2 => block of 2 articulation points
4667 // n3 => no block
4668 //
4669 Bool newv;
4670 int td, td0, lp, conn, next1, nart1, nart2, nvisit, ndart;
4671 int opit, opit0, blkt, l;
4672 MCOpi mopi1;
4673 MCBlock mblk1;
4674 ULong momset1, momset2, momset3;
4675
4676 mopi->init();
4677 mblk->init();
4678
4679 *momset = 0; // # the set of momenta
4680 *next = 0; // # external below 'nd' inclusive
4681 *nart = 0; // # articulation points 'nd' inclusive
4682 nart1 = 0; // # articulation points below 'nd'
4683 nart2 = 0; // # 'nd' is articulation point then 1
4684 ndart = 0; // # the number of blocks attached to 'nd'
4685
4686 newv = (bidef[nd] < 0);
4687 if (! newv) {
4688 grcc_fprintf(GRCC_Stdout, "*** nd=%d, pd=%d, bidef[nd]=%d\n", nd, pd, bidef[nd]);
4689 erEnd("bisearchME: illegal connection");
4690 }
4691
4692 bidef[nd] = bicount;
4693 bilow[nd] = bicount;
4694 bicol[nd] = col;
4695 bicount++;
4696
4697 opit0 = mconn->opistkptr;
4698
4699 if (pd < 0) {
4700 mconn->pushNode(nd);
4701 }
4702
4703 // external node and not the root
4704 if (isExternal(nd)) {
4705 if (pd >= 0) {
4706 // not the root
4707 *momset = MASK(nd);
4708 mopi->next = 1;
4709 mopi->nlegs = 1;
4710 mopi->mom0lg = 0;
4711 mblk->nartps = 1;
4712 *next = 1;
4713 *nart = 1;
4714 mconn->addCEdge(nd, pd, *momset);
4715 return;
4716 }
4717 }
4718
4719 nvisit = 0;
4720 td0 = -1;
4721 for (td = 0; td < nNodes; td++) {
4722 conn = adjMat[nd][td];
4723
4724 // td is not adjacent to nd
4725 if (conn < 1) {
4726 continue;
4727 }
4728 nvisit++;
4729 td0 = td;
4730
4731 momset1 = 0;
4732
4733 // external node
4734 if (isExternal(td) && bidef[td] < 0) {
4735 bicol[td] = - col;
4736 (*next)++;
4737 ndart++;
4738 mconn->addArtic(nd, 1);
4739 mblk->nartps++;
4740 nart2 = 1;
4741 momset1 = MASK(td);
4742 mopi->nlegs++;
4743 mopi->next++;
4744 mconn->addCEdge(td, nd, momset1);
4745 *momset |= momset1;
4746 if (newv) {
4747 mconn->pushNode(td);
4748 }
4749
4750 // self-loop : pd --> nd --> nd
4751 } else if (td == nd) {
4752 lp = conn/2;
4753 mopi->loop += lp;
4754 mopi->nedges += lp;
4755 ndart += lp;
4756 bipart = False;
4757 mconn->addArtic(nd, lp);
4758 mconn->addBlockSelf(nd, lp);
4759 mblk->nartps++;
4760 nart2 = 1;
4761 for (l = 0; l < lp; l++) {
4762 int m = nExtern + mconn->nbacked;
4763 mconn->nbacked++;
4764 momset1 = MASK(m);
4765 mconn->addCEdge(td, nd, momset1);
4766 }
4767
4768 // back to the parent : pd --> nd --> pd, pd is a vertex
4769 } else if (td == pd) {
4770 if (ned > 1) {
4771 bilow[nd] = Min(bilow[nd], bidef[pd]);
4772 mopi->loop += ned - 1;
4773 mblk->loop += ned - 1;
4774 } else {
4775 // cancel this visit
4776 nvisit--;
4777 }
4778
4779 // td is already visited
4780 } else if (bidef[td] >= 0) {
4781 bipart &= (bicol[td] == - col);
4782 bilow[nd] = Min(bilow[nd], bidef[td]);
4783 if (bidef[nd] >= bidef[td]) {
4784 // new back-edge is found
4785 mopi->loop += conn;
4786 mopi->nedges += conn;
4787 mblk->loop += conn;
4788 mconn->pushEdge(td, nd);
4789 for (l = 0; l < conn; l++) {
4790 int m = nExtern + mconn->nbacked;
4791 mconn->nbacked++;
4792 momset1 = MASK(m);
4793 *momset |= momset1;
4794 mconn->addCEdge(td, nd, momset1);
4795 }
4796 } else {
4797 // reverse direction of back-edge
4798 int cn = 0;
4799
4800 for (int ed = 0; ed < mconn->sedges; ed++) {
4801 if (mconn->cedges[ed].nodes[0] == nd &&
4802 mconn->cedges[ed].nodes[1] == td &&
4803 mconn->cedges[ed].momdir > 0) {
4804 cn++;
4805 *momset &= ~ (mconn->cedges[ed].momset);
4806 } else if (mconn->cedges[ed].nodes[1] == nd &&
4807 mconn->cedges[ed].nodes[0] == td &&
4808 mconn->cedges[ed].momdir < 0) {
4809 cn++;
4810 *momset &= ~ (mconn->cedges[ed].momset);
4811 }
4812 }
4813 if (cn != conn) {
4814 grcc_fprintf(GRCC_Stdout, "*** revisit back-ed (%d --> %d) cn=%d != conn=%d\n",
4815 nd, td, cn, conn);
4816 grcc_fprintf(GRCC_Stdout, " sedges = %d\n", mconn->sedges);
4817 for (int ed = 0; ed < mconn->sedges; ed++) {
4818 grcc_fprintf(GRCC_Stdout, " %d : (%d --> %d) : [%2d*%2ld]\n", ed,
4819 mconn->cedges[ed].nodes[0],
4820 mconn->cedges[ed].nodes[1],
4821 mconn->cedges[ed].momdir,
4822 mconn->cedges[ed].momset);
4823 }
4824 print();
4825 egraph->print();
4826 mconn->print();
4827 erEnd("bisearchME: illegal connection");
4828 }
4829 }
4830
4831 // new node
4832 } else if (bidef[td] < 0) {
4833
4834 // stack pointer
4835 if (pd < 0 && isExternal(nd)) {
4836 opit = opit0;
4837 } else {
4838 opit = mconn->opistkptr;
4839 }
4840 blkt = mconn->blkstkptr;
4841 mblk1.init();
4842
4843 mconn->pushEdge(nd, td);
4844
4845 // visit child
4846 bisearchME(td, nd, adjMat[td][nd], - col,
4847 &mopi1, &mblk1, &momset1, &next1, &nart1);
4848
4849 // momset
4850 momset2 = 0;
4851 for (l = 0; l < conn - 1; l++) {
4852 int m = nExtern + mconn->nbacked;
4853 mconn->nbacked++;
4854 momset3 = MASK(m);
4855 mconn->addCEdge(nd, td, momset3);
4856 momset2 |= momset3;
4857 }
4858 mconn->addCEdge(td, nd, momset1 | momset2);
4859 *momset |= momset1;
4860 // articulation point of bridge
4861 if (bilow[td] > bidef[nd]) {
4862
4863 // new OPI component (not including 'td')
4864 int mom0lg = (momset1 == 0) ? 1 : 0;
4865 mopi1.nlegs++;
4866 mopi1.mom0lg += mom0lg;
4867
4868 mconn->addOPIc(&mopi1, opit);
4869
4870 mopi1.init();
4871 mopi1.nlegs = 1;
4872 mopi1.mom0lg = mom0lg;
4873 if (pd >= 0 || !isExternal(nd)) {
4874 // opi
4875 mconn->addBridge(nd, td, next1, nExtern);
4876
4877 // block
4878 ndart++;
4879 mconn->addArtic(nd, 1);
4880 // discard nparts from nodes below td
4881 mblk1.nartps = 2;
4882 mconn->addBlock(&mblk1, blkt);
4883 mblk1.init();
4884 mblk1.nartps = 1;
4885
4886 nart1 = 0;
4887 nart2 = 1; // nd is an articulation point
4888 }
4889 } else if (bilow[td] == bidef[nd]) {
4890 // articulation point of a block
4891 mopi1.nedges += conn;
4892 if (pd >= 0 || !isExternal(nd)) {
4893 ndart++;
4894 mconn->addArtic(nd, 1);
4895 mblk1.nartps++;
4896 mconn->addBlock(&mblk1, blkt);
4897 mblk1.init();
4898 mblk1.nartps = 1;
4899 nart1 = 0;
4900 nart2 = 1; // nd is an articulation point
4901 }
4902
4903 } else {
4904 // inside a block
4905 mopi1.nedges += conn;
4906 }
4907
4908 bilow[nd] = Min(bilow[nd], bilow[td]);
4909 mopi->nlegs += mopi1.nlegs;
4910 mopi->next += mopi1.next;
4911 mopi->loop += mopi1.loop;
4912 mopi->nedges += mopi1.nedges;
4913 mopi->ctloop += mopi1.ctloop;
4914 mopi->mom0lg += mopi1.mom0lg;
4915
4916 mblk->nartps += mblk1.nartps;
4917 mblk->loop += mblk1.loop;
4918
4919 *next += next1;
4920 *nart += nart1;
4921 } // of "if (bidef[td] < 0)"
4922 } // end of for
4923
4924 // no connection except for 'pd'==>'nd'. Then 'nd' is an art. point
4925 if (nvisit == 0) {
4926 nart2 = 1;
4927 }
4928 *nart += nart2;
4929
4930 // add # loop inside counter terms
4931 if (newv) {
4932 if (pd >= 0) {
4933 mconn->pushNode(nd);
4934 }
4935 mopi->ctloop += Max(0, nodes[nd]->extloop);
4936 }
4937
4938 // 'nd' is the root node
4939 if (pd < 0) {
4940 if (isExternal(nd)) {
4941 if (td0 >= 0) {
4942 mconn->addArtic(td0, 1);
4943 }
4944 if (mconn->nopic > 0) {
4945 (mconn->opics[mconn->nopic-1].next)++;
4946 }
4947 } else {
4948 mconn->addOPIc(mopi, opit0);
4949 if (ndart == 1) {
4950 // 'nd' has only 1 child
4951 // the root is not really an art. point
4952 (*nart)--;
4953 mconn->addArtic(nd, -1);
4954 (mconn->blocks[mconn->nblocks-1].nartps)--;
4955 }
4956 }
4957 }
4958}
4959
4960//---------------------------------------------------------------
4961BigInt MGraph::generate(void)
4962{
4963 // Generate graphs
4964 // the generation process starts from 'connectClass'.
4965
4966 MNodeClass *cl;
4967
4968 // Initial classification of nodes.
4969 cl = new MNodeClass(nNodes, nClasses);
4970 cl->init(clist, maxdeg, adjMat);
4971 cl->reorder(this);
4972 connectClass(cl);
4973
4974 delete cl;
4975
4976 return cDiag;
4977}
4978
4979//---------------------------------------------------------------
4980void MGraph::connectClass(MNodeClass *cl)
4981{
4982 // Connect nodes in a class to others
4983
4984 int sc, sn;
4985 MNodeClass *xcl;
4986
4987 xcl = refineClass(cl);
4988
4989 if (xcl == NULL) {
4990#ifdef MONITOR
4991 discardRefine++;
4992#endif
4993 } else {
4994 if (xcl->flg0 >= xcl->nClasses) {
4995 newGraph(xcl);
4996 } else {
4997 sc = xcl->clord[xcl->flg0];
4998 sn = xcl->flist[sc];
4999 connectNode(xcl->flg0, sn, xcl);
5000 }
5001 }
5002 if (xcl != cl && xcl != NULL) {
5003 delete xcl;
5004 }
5005}
5006
5007//------------------------------------------------------------
5008void MGraph::connectNode(int so, int ss, MNodeClass *cl)
5009{
5010 int sc, sn;
5011
5012 sc = cl->clord[so];
5013 if (ss >= cl->flist[sc+1]) {
5014 connectClass(cl);
5015 return;
5016 }
5017
5018 for (sn = ss; sn < cl->flist[sc+1]; sn++) {
5019 connectLeg(so, sn, so, sn, cl);
5020 return;
5021 }
5022}
5023
5024//------------------------------------------------------------
5025void MGraph::connectLeg(int so, int sn, int to, int ts, MNodeClass *cl)
5026{
5027 // Add one connection between two legs.
5028 // 1. select another node to connect
5029 // 2. determine multiplicity of the connection
5030
5031 int sc, tc, tn, maxself, nc2, nc, maxcon, ts1, ncm, to1;
5032
5033 sc = cl->clord[so];
5034
5035#ifdef CHECK
5036 if (sn >= cl->flist[sc+1]) {
5037 erEnd("connectLeg : illegal control");
5038 return;
5039 }
5040#endif
5041
5042 // There remains no free legs in the node 'sn' : move to next node.
5043 if (nodes[sn]->freelg < 1) {
5044
5045 if (!isConnected()) {
5046#ifdef MONITOR
5047 discardDisc++;
5048#endif
5049 } else {
5050 // next node in the current class.
5051 connectNode(so, sn+1, cl);
5052 }
5053 return;
5054 }
5055
5056 // connect a free leg of the current node 'sn'.
5057 for (to1 = to; to1 < cl->nClasses; to1++) {
5058 tc = cl->clord[to1];
5059 if (to1 == to) {
5060 ts1 = ts;
5061 } else {
5062 ts1 = cl->flist[tc];
5063 }
5064#ifdef MINMAXLEG
5065 if (ts1 >= nNodes) {
5066 continue;
5067 }
5068 if ((nodes[sn]->cmindeg > 0 && nodes[ts1]->deg < nodes[sn]->cmindeg)
5069 ||(nodes[sn]->cmaxdeg > 0 && nodes[ts1]->deg > nodes[sn]->cmaxdeg)
5070 | (nodes[ts1]->cmindeg > 0 && nodes[sn]->deg < nodes[ts1]->cmindeg)
5071 ||(nodes[ts1]->cmaxdeg > 0 && nodes[sn]->deg > nodes[ts1]->cmaxdeg)) {
5072 continue;
5073 }
5074#endif
5075 for (tn = ts1; tn < cl->flist[tc+1]; tn++) {
5076 if (sc == tc && sn > tn) {
5077 continue;
5078
5079 } else if (nodes[tn]->freelg < 1) {
5080 continue;
5081
5082 // self-loop
5083 } else if (sn == tn) {
5084 if (opt->values[GRCC_OPT_NoSelfLoop] > 0) {
5085 continue;
5086 }
5087 if (nNodes > 1) {
5088 // there are two or more nodes in the graph :
5089 // avoid disconnected graph
5090 maxself = Min((nodes[sn]->freelg)/2, (nodes[sn]->deg-1)/2);
5091 } else {
5092 // there is only one node the graph.
5093 maxself = nodes[sn]->freelg/2;
5094 }
5095
5096 if ((nExtern > 1) && (opt->values[GRCC_OPT_1PI] > 0
5097 || opt->values[GRCC_OPT_NoTadpole] > 0)
5098 && nNodes > 1) {
5099 // there are two or more nodes in the graph :
5100 // avoid to generate tadpole
5101 maxself = Min((nodes[sn]->deg-2)/2, maxself);
5102 }
5103
5104 // for the number of connection.
5105 for (nc2 = maxself; nc2 > 0; nc2--) {
5106 nc = 2*nc2;
5107 ncm = CLWIGHTD(nc);
5108 adjMat[sn][sn] = nc;
5109 nodes[sn]->freelg -= nc;
5110 cl->incMat(sn, tn, ncm);
5111
5112 // next connection
5113 connectLeg(so, sn, to1, tn+1, cl);
5114
5115 // restore the configuration
5116 cl->incMat(tn, sn, - ncm);
5117 adjMat[sn][sn] = 0;
5118 nodes[sn]->freelg += nc;
5119 }
5120
5121 // connections between different nodes.
5122 } else {
5123 // maximum possible connection number
5124 maxcon = Min(nodes[sn]->freelg, nodes[tn]->freelg);
5125
5126 // avoid disconnected graphs.
5127 if (nNodes > 2 && nodes[sn]->deg == nodes[tn]->deg) {
5128 maxcon = Min(maxcon, nodes[sn]->deg-1);
5129 }
5130
5131 if (opt->values[GRCC_OPT_NoMultiEdge] > 0) {
5132 maxcon = Min(maxcon, 1);
5133 }
5134
5135#ifdef CHECK
5136 if ((adjMat[sn][tn] != 0) ||
5137 (adjMat[sn][tn] != adjMat[tn][sn])) {
5138 grcc_fprintf(GRCC_Stdout, "*** inconsistent connection: sn=%d, tn=%d",
5139 sn, tn);
5140 printAdjMat(cl);
5141 erEnd("inconsistent connection ");
5142 }
5143#endif
5144
5145 // vary number of connections
5146 for (nc = maxcon; nc > 0; nc--) {
5147 ncm = CLWIGHTO(nc);
5148 adjMat[sn][tn] = nc;
5149 adjMat[tn][sn] = nc;
5150 nodes[sn]->freelg -= nc;
5151 nodes[tn]->freelg -= nc;
5152 cl->incMat(sn, tn, ncm);
5153 cl->incMat(tn, sn, ncm);
5154
5155 // next connection
5156 connectLeg(so, sn, to1, tn+1, cl);
5157
5158 // restore configuration
5159 cl->incMat(sn, tn, - ncm);
5160 cl->incMat(tn, sn, - ncm);
5161 adjMat[sn][tn] = 0;
5162 adjMat[tn][sn] = 0;
5163 nodes[sn]->freelg += nc;
5164 nodes[tn]->freelg += nc;
5165 }
5166 }
5167 }
5168 }
5169}
5170
5171//------------------------------------------------------------
5172Bool MGraph::isOptM(void)
5173{
5174 Bool ok = True;
5175
5176 opi = (mconn->nopic == 1);
5177 opiloop = (mconn->nlpopic <= 1);
5178 tadpole = (mconn->ne0bridges >= ((nExtern == 1) ? 0 : 1));
5179 selfloop = (mconn->nselfloops > 0);
5180 multiedge = (mconn->nmultiedges > 0);
5181 tadblock = (mconn->na1blocks > 0);
5182 block = (mconn->neblocks <= 1);
5183 extself = (mconn->ne1bridges > 0);
5184
5185 if (opt->values[GRCC_OPT_1PI] > 0) {
5186 ok = ok && opi;
5187 } else if (opt->values[GRCC_OPT_1PI] < 0) {
5188 ok = ok && !opi;
5189 }
5190 if (opt->values[GRCC_OPT_NoExtSelf] > 0) {
5191 ok = ok && !extself;
5192 } else if (opt->values[GRCC_OPT_NoExtSelf] < 0) {
5193 ok = ok && extself;
5194 }
5195 if (opt->values[GRCC_OPT_NoTadpole] > 0) {
5196#ifdef OLDOPT
5197 ok = ok && !tadpole;
5198#else
5199 if (nExtern > 1) {
5200 ok = ok && !tadpole;
5201 }
5202#endif
5203 } else if (opt->values[GRCC_OPT_NoTadpole] < 0) {
5204#ifdef OLDOPT
5205 ok = ok && !tadpole;
5206#else
5207 if (nExtern > 1) {
5208 ok = ok && tadpole;
5209 }
5210#endif
5211 }
5212 if (opt->values[GRCC_OPT_NoSelfLoop] > 0) {
5213 } else if (opt->values[GRCC_OPT_NoSelfLoop] < 0) {
5214 ok = ok && selfloop;
5215 }
5216 if (opt->values[GRCC_OPT_NoMultiEdge] > 0) {
5217 } else if (opt->values[GRCC_OPT_NoMultiEdge] < 0) {
5218 ok = ok && multiedge;
5219 }
5220 if (opt->values[GRCC_OPT_No1PtBlock] > 0) {
5221 if (nExtern > 1) {
5222 ok = ok && !tadblock;
5223 }
5224 } else if (opt->values[GRCC_OPT_No1PtBlock] < 0) {
5225 if (nExtern > 1) {
5226 ok = ok && tadblock;
5227 }
5228 }
5229 if (opt->values[GRCC_OPT_Block] > 0) {
5230 ok = ok && block;
5231 } else if (opt->values[GRCC_OPT_Block] < 0) {
5232 ok = ok && !block;
5233 }
5234 return ok;
5235}
5236
5237//------------------------------------------------------------
5238void MGraph::newGraph(MNodeClass *cl)
5239{
5240 // A new candidate diagram is obtained.
5241 // It may be a disconnected graph
5242 //
5243 // Things to be done in the steps followed by this function.
5244 // 1. convert data format which treat the edges as objects.
5245 // 2. definition of loop momenta to the edges.
5246 // 3. analysis of loop structure in a graph.
5247 // 4. assignment of particles to edges and vertices to nodes
5248 // 5. recalculate symmetry factor
5249
5250 int connected;
5251 MNodeClass *xcl;
5252 Bool ok;
5253
5254 ngen++;
5255
5256 // refine class and check ordering condition
5257 xcl = refineClass(cl);
5258 if (xcl == NULL) {
5259#ifdef MONITOR
5260 discardRefine++;
5261#endif
5262
5263 // check whether this is a connected graph or not.
5264 } else {
5265 connected = isConnected();
5266 if (!connected) {
5267#ifdef MONITOR
5268 discardDisc++;
5269#endif
5270
5271 // connected graph : check isomorphism of the graph
5272 } else {
5273 ngconn++;
5274 if (!isIsomorphic(xcl)) {
5275#ifdef MONITOR
5276 discardIso++;
5277#endif
5278
5279 // We got a new connected and a unique representation of a class.
5280 } else {
5281 biconnME();
5282 if (isOptM()) {
5283 egraph->fromMGraph(this);
5284 if (egraph->isOptE()) {
5285 curcl->copy(xcl);
5286#ifdef ORBITS
5287 orbits->toOrbits();
5288#endif
5289 ok = True;
5290 if (opt->outmg != NULL) {
5291 if (opt->proc != NULL) {
5292 egraph->mId = opt->proc->mgrcount + 1;
5293 egraph->sId = opt->proc->agrcount + 1;
5294 } else if (opt->sproc != NULL) {
5295 egraph->mId = opt->sproc->mgrcount + 1;
5296 egraph->sId = opt->sproc->agrcount + 1;
5297 } else {
5298 egraph->mId = cDiag;
5299 }
5300 ok = (*(opt->outmg))(egraph, opt->argmg);
5301 }
5302
5303 if (ok) {
5304 // # generated graphs
5305 cDiag++;
5306 wscon.add(1, nsym*esym);
5307
5308 // # generated 1PI graphs
5309 if (opi) {
5310 wsopi.add(1, nsym*esym);
5311 c1PI++;
5312 }
5313
5314 // # no tadpoles
5315 if (!tadpole) {
5316 cNoTadpole++;
5317 }
5318 // # no tadblocks
5319 if (!tadblock) {
5320 cNoTadBlock++;
5321 if (opi) {
5322 c1PINoTadBlock++;
5323 }
5324 }
5325
5326#ifdef MONITOR
5327 grcc_fprintf(GRCC_Stdout, "\n");
5328 grcc_fprintf(GRCC_Stdout, "Graph : %ld (%ld)", cDiag, ngen);
5329 grcc_fprintf(GRCC_Stdout, " sym. factor = (%ld*%ld)\n", nsym, esym);
5330 printAdjMat(cl);
5331 // cl->printMat();
5332# ifdef ORBITS
5333 orbits->print();
5334# endif
5335#endif
5336 // go to next step
5337 opt->newMGraph(this);
5338 } else {
5339 }
5340 } else {
5341 }
5342 } else {
5343 ;
5344 }
5345 }
5346 }
5347 }
5348 if (xcl != cl && xcl != NULL) {
5349 delete xcl;
5350 }
5351}
5352
5353//==============================================================
5354// class MOrbits: orbits of nodes
5355//--------------------------------------------------------------
5356MOrbits::MOrbits(void)
5357{
5358 nOrbits = 0;
5359 nNodes = 0;
5360}
5361
5362//--------------------------------------------------------------
5363MOrbits::~MOrbits(void)
5364{
5365}
5366
5367//--------------------------------------------------------------
5368void MOrbits::print(void)
5369{
5370 int c;
5371
5372 grcc_fprintf(GRCC_Stdout, "Orbits : nOrbits=%d: nd2or=", nOrbits);
5373 prIntArray(nNodes, nd2or, "\n");
5374 for (c = 0; c < nOrbits; c++) {
5375 grcc_fprintf(GRCC_Stdout, " %2d: (%2d -- %2d) :", c, flist[c], flist[c+1]-1);
5376 prIntArray(flist[c+1]-flist[c], or2nd+flist[c], "\n");
5377 }
5378}
5379
5380//---------------------------------------------------------------
5381void MOrbits::initPerm(int nnodes)
5382{
5383 int j;
5384
5385 nNodes = nnodes;
5386 for (j = 0; j < nNodes; j++) {
5387 nd2or[j] = j;
5388 }
5389}
5390
5391//---------------------------------------------------------------
5392void MOrbits::fromPerm(int *perm)
5393{
5394 // update the orbits of nodes by the permutation
5395
5396 int j, j1, k, l;
5397
5398 for (j = 0; j < nNodes; j++) {
5399 if (nd2or[j] != j) {
5400 // not the first element of an old orbit
5401 continue;
5402 }
5403 // merge orbits to orbit 'j'
5404 k = j;
5405 for (j1 = 0; j1 < nNodes && (k = perm[k]) != j; j1++) {
5406 if (nd2or[k] == j) {
5407 // 'k' is already in 'j'
5408 ;
5409 } else {
5410 // old orbit 'k' had several elements: merge to orbit 'j'
5411 for (l = 0; l < nNodes; l++) {
5412 if (nd2or[l] == k) {
5413 nd2or[l] = j;
5414 }
5415 }
5416 }
5417 }
5418#ifdef CHECK
5419 if (j1 >= nNodes) {
5420 grcc_fprintf(GRCC_Stdout, "*** fromPerm: illegal control: j=%d, k=%d\n", j, k);
5421 grcc_fprintf(GRCC_Stdout, "perm=");
5422 prIntArray(nNodes, perm, " nd2or=");
5423 prIntArray(nNodes, nd2or, "\n");
5424 erEnd("fromPerm: illegal control");
5425 }
5426#endif
5427 }
5428}
5429
5430//--------------------------------------------------------------
5431void MOrbits::toOrbits(void)
5432{
5433 // fill elements from 'nd2or'
5434 int nd, nel, k, lor;
5435
5436 lor = -1;
5437 nel = 0;
5438 nOrbits = 0;
5439 for (nd = 0; nd < nNodes; nd++) {
5440 if (nd2or[nd] > lor) {
5441 // lowest element of a new orbit
5442 lor = nd2or[nd];
5443 flist[nOrbits++] = nel;
5444 for (k = nd; k < nNodes; k++) {
5445 if (nd2or[k] == lor) {
5446 or2nd[nel++] = k;
5447 }
5448 }
5449 }
5450 }
5451 flist[nOrbits] = nNodes;
5452}
5453
5454//**************************************************************
5455// n-edge connected components
5456//============================================================
5457// class MCEdge
5458//------------------------------------------------------------
5459MCEdge::MCEdge(void)
5460{
5461 ;
5462}
5463
5464//------------------------------------------------------------
5465MCEdge::~MCEdge(void)
5466{
5467 ;
5468}
5469
5470//============================================================
5471// class MCOpi: one n-edge connected component
5472//------------------------------------------------------------
5473MCOpi::MCOpi(void)
5474{
5475 init();
5476}
5477
5478//------------------------------------------------------------
5479MCOpi::~MCOpi(void)
5480{
5481 nodes = NULL;
5482}
5483
5484//------------------------------------------------------------
5485void MCOpi::init(void)
5486{
5487 nodes = NULL;
5488 nnodes = 0;
5489 nlegs = 0;
5490 next = 0;
5491 nedges = 0;
5492 loop = 0;
5493 ctloop = 0;
5494 mom0lg = 0;
5495}
5496
5497//============================================================
5498// class MCBridge
5499//------------------------------------------------------------
5500MCBridge::MCBridge(void)
5501{
5502}
5503
5504//------------------------------------------------------------
5505MCBridge::~MCBridge(void)
5506{
5507}
5508
5509//============================================================
5510// class MCBlock
5511//------------------------------------------------------------
5512MCBlock::MCBlock(void)
5513{
5514 init();
5515}
5516
5517//------------------------------------------------------------
5518MCBlock::~MCBlock(void)
5519{
5520}
5521
5522//------------------------------------------------------------
5523void MCBlock::init(void)
5524{
5525 edges = NULL;
5526 nmedges = 0;
5527 nartps = 0;
5528 loop = 0;
5529}
5530
5531//============================================================
5532// class MConn: table of n-edge connected components
5533//------------------------------------------------------------
5534MConn::MConn(int nnod, int nedg)
5535{
5536 // nnod : the number of nodes
5537 // nedg : the number of edges
5538
5539 snodes = nnod;
5540 sedges = nedg;
5541
5542 cedges = new MCEdge[sedges];
5543 opics = new MCOpi[snodes];
5544 bridges = new MCBridge[sedges];
5545 blocks = new MCBlock[sedges];
5546 articuls = new int[snodes];
5547
5548 // workspace
5549 opisp = new int[snodes];
5550 opistk = new int[snodes];
5551 blksp = new Edge2n[sedges];
5552 blkstk = new Edge2n[sedges];
5553 init();
5554}
5555
5556//------------------------------------------------------------
5557MConn::~MConn(void)
5558{
5559 delete[] blkstk;
5560 delete[] blksp;
5561 delete[] opistk;
5562 delete[] opisp;
5563
5564 delete[] articuls;
5565 delete[] blocks;
5566 delete[] bridges;
5567 delete[] opics;
5568 delete[] cedges;
5569}
5570
5571//------------------------------------------------------------
5572void MConn::init(void)
5573{
5574 int j;
5575
5576 nopic = 0;
5577 nlpopic = 0;
5578 nbacked = 0;
5579 nctopic = 0;
5580 nbridges = 0;
5581 ne0bridges = 0;
5582 ne1bridges = 0;
5583 nselfloops = 0;
5584 nmultiedges = 0;
5585 nbacked = 0;
5586
5587 nblocks = 0;
5588 na1blocks = 0;
5589 narticuls = 0;
5590 neblocks = 0;
5591
5592 opistkptr = 0;
5593 nopisp = 0;
5594 blkstkptr = 0;
5595 nblksp = 0;
5596
5597 for (j = 0; j < snodes; j++) {
5598 articuls[j] = 0;
5599 }
5600}
5601
5602//------------------------------------------------------------
5603void MConn::pushNode(int nd)
5604{
5605 if (opistkptr >= snodes) {
5606 erEnd("MConn::pushNode: opistkptr >= snodes");
5607 }
5608 opistk[opistkptr++] = nd;
5609}
5610
5611//------------------------------------------------------------
5612void MConn::pushEdge(int n0, int n1)
5613{
5614 if (blkstkptr >= sedges) {
5615 erEnd("MConn::pushEdge: blkstkptr >= sedges");
5616 }
5617 if (n0 <= n1) {
5618 blkstk[blkstkptr][0] = n0;
5619 blkstk[blkstkptr][1] = n1;
5620 } else {
5621 blkstk[blkstkptr][0] = n1;
5622 blkstk[blkstkptr][1] = n0;
5623 }
5624 blkstkptr++;
5625}
5626
5627
5628//------------------------------------------------------------
5629void MConn::initCEdges(MGraph *mg)
5630{
5631 int ed, n0, n1, e;
5632
5633 ed = 0;
5634 for (n0 = 0; n0 < mg->nNodes; n0++) {
5635 for (e = 0; e < mg->adjMat[n0][n0]/2; e++, ed++) {
5636 cedges[ed].nodes[0] = n0;
5637 cedges[ed].nodes[1] = n0;
5638 cedges[ed].momdir = 0;
5639 }
5640 for (n1 = n0+1; n1 < mg->nNodes; n1++) {
5641 for (e = 0; e < mg->adjMat[n0][n1]; e++, ed++) {
5642 cedges[ed].nodes[0] = n0;
5643 cedges[ed].nodes[1] = n1;
5644 cedges[ed].momdir = 0;
5645 }
5646 }
5647 }
5648 if (ed != sedges) {
5649 grcc_fprintf(GRCC_Stdout, "*** ed=%d != sedges=%d\n", ed, sedges);
5650 erEnd("MConn::initCEdge: table overflow");
5651 }
5652}
5653
5654//------------------------------------------------------------
5655void MConn::addCEdge(int n0, int n1, ULong momset)
5656{
5657 int m0, m1, dir, ed;
5658
5659 if (n0 <= n1) {
5660 m0 = n0;
5661 m1 = n1;
5662 dir = 1;
5663 } else {
5664 m0 = n1;
5665 m1 = n0;
5666 dir = -1;
5667 }
5668 for (ed = 0; ed < sedges; ed++) {
5669 if (cedges[ed].nodes[0] == m0 && cedges[ed].nodes[1] == m1 &&
5670 cedges[ed].momdir == 0) {
5671 cedges[ed].momdir = dir;
5672 cedges[ed].momset = momset;
5673 return;
5674 }
5675 }
5676}
5677
5678//------------------------------------------------------------
5679void MConn::addOPIc(MCOpi *mopi, int stp)
5680{
5681 int j, nn;
5682
5683 if (nopic >= snodes) {
5684 erEnd("MConn::addOPIc: table overflow");
5685 }
5686
5687 nn = opistkptr - stp;
5688 for (j = 0; j < nn; j++) {
5689 opisp[nopisp+j] = opistk[stp+j];
5690 }
5691 opics[nopic].nnodes = nn;
5692 opics[nopic].nlegs = mopi->nlegs;
5693 opics[nopic].nedges = mopi->nedges;
5694 opics[nopic].next = mopi->next;
5695 opics[nopic].loop = mopi->loop;
5696 opics[nopic].ctloop = mopi->ctloop;
5697 opics[nopic].mom0lg = mopi->mom0lg;
5698 opics[nopic].nodes = opisp + nopisp;
5699 nopisp += nn;
5700 opistkptr = stp;
5701
5702 nopic++;
5703}
5704
5705//------------------------------------------------------------
5706void MConn::addBridge(int n0, int n1, int nex, int nextot)
5707{
5708 if (nbridges >= sedges) {
5709 erEnd("MConn::addBridge: table overflow");
5710 }
5711 if (n0 <= n1) {
5712 bridges[nbridges].nodes[0] = n0;
5713 bridges[nbridges].nodes[1] = n1;
5714 } else {
5715 bridges[nbridges].nodes[0] = n1;
5716 bridges[nbridges].nodes[1] = n0;
5717 }
5718 bridges[nbridges].next = Min(nex, nextot-nex);
5719 nbridges++;
5720}
5721
5722//------------------------------------------------------------
5723void MConn::addArtic(int nd, int mul)
5724{
5725 articuls[nd] += mul;
5726 if (articuls[nd] == mul) {
5727 narticuls++;
5728 } else if (articuls[nd] == 0) {
5729 narticuls--;
5730 }
5731}
5732
5733//------------------------------------------------------------
5734void MConn::addBlock(MCBlock *mblk, int stp)
5735{
5736 int j, nn;
5737
5738 if (nopic >= snodes) {
5739 erEnd("MConn::addOPIc: table overflow");
5740 }
5741
5742 nn = blkstkptr - stp;
5743 for (j = 0; j < nn; j++) {
5744 blksp[nblksp+j][0] = blkstk[stp+j][0];
5745 blksp[nblksp+j][1] = blkstk[stp+j][1];
5746 }
5747 blocks[nblocks].edges = blksp + nblksp;
5748 blocks[nblocks].nmedges = nn;
5749 blocks[nblocks].nartps = mblk->nartps;
5750 blocks[nblocks].loop = mblk->loop;
5751 nblksp += nn;
5752 blkstkptr = stp;
5753
5754 nblocks++;
5755}
5756
5757//------------------------------------------------------------
5758void MConn::addBlockSelf(int nd, int mult)
5759{
5760 MCBlock mblk;
5761 int j, stp;
5762
5763 mblk.edges = NULL;
5764 mblk.nmedges = 0;
5765 mblk.nartps = 1;
5766 mblk.loop = 1;
5767
5768 for (j = 0; j < mult; j++) {
5769 stp = blkstkptr;
5770 pushEdge(nd, nd);
5771 addBlock(&mblk, stp);
5772 }
5773}
5774
5775//------------------------------------------------------------
5776void MConn::print(void)
5777{
5778 int j, k;
5779
5780 grcc_fprintf(GRCC_Stdout, "+++ MConn object: snodes=%d, sedges=%d\n", snodes, sedges);
5781 grcc_fprintf(GRCC_Stdout, " nopic=%d, nlpopic=%d, nbacked=%d, nctopic=%d, "
5782 "nbridges=%d, ne0bridges=%d, ne1bridges=%d\n",
5783 nopic, nlpopic, nbacked, nctopic,
5784 nbridges, ne0bridges, ne1bridges);
5785 grcc_fprintf(GRCC_Stdout, " nblocks=%d, neblocks=%d, na1blocks=%d, narticuls=%d, nselfloop=%d\n",
5786 nblocks, neblocks, na1blocks, narticuls, nselfloops);
5787 grcc_fprintf(GRCC_Stdout, " nmultiedges=%d\n", nmultiedges);
5788
5789 grcc_fprintf(GRCC_Stdout, " cEdges (%d)\n", sedges);
5790 if (sedges > 0) {
5791 for (j = 0; j < sedges; j++) {
5792 grcc_fprintf(GRCC_Stdout, " %2d: (%d,%d)[%2d*%2ld] \n", j,
5793 cedges[j].nodes[0], cedges[j].nodes[1],
5794 cedges[j].momdir, cedges[j].momset);
5795 }
5796 }
5797 grcc_fprintf(GRCC_Stdout, "\n");
5798
5799 grcc_fprintf(GRCC_Stdout, " 1PI components (%d)\n", nopic);
5800 for (j = 0; j < nopic; j++) {
5801 grcc_fprintf(GRCC_Stdout, " %d: nleg=%d, nnodes=%d, nedge=%d, ",
5802 j, opics[j].nlegs, opics[j].nnodes, opics[j].nedges);
5803 grcc_fprintf(GRCC_Stdout, "next=%d, loop=%d, ctlp=%d: m0lg=%d [",
5804 opics[j].next, opics[j].loop, opics[j].ctloop,
5805 opics[j].mom0lg);
5806 for (k = 0; k < opics[j].nnodes; k++) {
5807 grcc_fprintf(GRCC_Stdout, " %d", opics[j].nodes[k]);
5808 }
5809 grcc_fprintf(GRCC_Stdout, "]\n");
5810 }
5811
5812 grcc_fprintf(GRCC_Stdout, " bridges (%d)\n", nbridges);
5813 if (nbridges > 0) {
5814 grcc_fprintf(GRCC_Stdout, " ");
5815 for (j = 0; j < nbridges; j++) {
5816 grcc_fprintf(GRCC_Stdout, "(%d,%d)[mom=%d] ",
5817 bridges[j].nodes[0], bridges[j].nodes[1], bridges[j].next);
5818 }
5819 grcc_fprintf(GRCC_Stdout, "\n");
5820 }
5821
5822 grcc_fprintf(GRCC_Stdout, " blocks (%d)\n", nblocks);
5823 for (j = 0; j < nblocks; j++) {
5824 grcc_fprintf(GRCC_Stdout, " %d: nmedges=%d, nartps=%d, loop=%d: [",
5825 j, blocks[j].nmedges, blocks[j].nartps, blocks[j].loop);
5826 for (k = 0; k < blocks[j].nmedges; k++) {
5827 grcc_fprintf(GRCC_Stdout, " (%d,%d)", blocks[j].edges[k][0], blocks[j].edges[k][1]);
5828 }
5829 grcc_fprintf(GRCC_Stdout, "]\n");
5830 }
5831
5832 grcc_fprintf(GRCC_Stdout, " articulation points (%d)\n", narticuls);
5833 if (narticuls > 0) {
5834 grcc_fprintf(GRCC_Stdout, " ");
5835 for (j = 0; j < snodes; j++) {
5836 if (articuls[j] != 0) {
5837#if 0
5838 grcc_fprintf(GRCC_Stdout, "%d(%d) ", j, articuls[j]);
5839#else
5840 grcc_fprintf(GRCC_Stdout, "%d ", j);
5841#endif
5842 }
5843 }
5844 grcc_fprintf(GRCC_Stdout, "\n");
5845 }
5846}
5847
5848//------------------------------------------------------------
5849void MConn::prEdges(void)
5850{
5851 int j;
5852
5853 grcc_fprintf(GRCC_Stdout, " cEdges (%d)", sedges);
5854 if (sedges > 0) {
5855 for (j = 0; j < sedges; j++) {
5856 if (j % 5 == 0) {
5857 grcc_fprintf(GRCC_Stdout, "\n ");
5858 }
5859 grcc_fprintf(GRCC_Stdout, "(%d,%d)[%2d*%3ld] ",
5860 cedges[j].nodes[0], cedges[j].nodes[1],
5861 cedges[j].momdir, cedges[j].momset);
5862 }
5863 grcc_fprintf(GRCC_Stdout, "\n");
5864 }
5865}
5866
5867//**************************************************************
5868// sgroup.cc
5869//==============================================================
5870// compile options
5871//============================================================
5872// table of group elements
5873//------------------------------------------------------------
5874SGroup::SGroup(void)
5875{
5876 // should be called before graph generation
5877 nnodes = -1;
5878 nelem = 0;
5879 elem = NULL;
5880}
5881
5882//------------------------------------------------------------
5883SGroup::~SGroup(void)
5884{
5885 int j;
5886
5887 if (elem != NULL) {
5888 for (j = GRCC_MAXGROUP-1; j >= 0; j--) {
5889 if (elem[j] != NULL) {
5890 delete[] elem[j];
5891 elem[j] = NULL;
5892 }
5893 }
5894 delete[] elem;
5895 elem = NULL;
5896 }
5897}
5898
5899//------------------------------------------------------------
5900void SGroup::print(void)
5901{
5902 int j;
5903
5904 grcc_fprintf(GRCC_Stdout, "SGroup : nnodes = %d, nelem=%ld, cgen=%d, csav=%d\n",
5905 nnodes, nelem, cgen, csav);
5906 grcc_fprintf(GRCC_Stdout, " eclass =");
5907 prIntArray(neclass, eclass, "\n");
5908 for (j = 0; j < nelem; j++) {
5909 grcc_fprintf(GRCC_Stdout, " %4d: ", j);
5910 prIntArray(nnodes, elem[j], "\n");
5911 }
5912}
5913
5914//------------------------------------------------------------
5915void SGroup::newGroup(int nnd, int nclss, int *clss)
5916{
5917 int j;
5918
5919 clearGroup();
5920 nnodes = nnd;
5921 neclass = nclss;
5922
5923 if (neclass > GRCC_MAXNODES) {
5924 erEnd("newGroup : too many classes (GRCC_MAXNODES)");
5925 }
5926 for (j = 0; j < neclass; j++) {
5927 eclass[j] = clss[j];
5928 }
5929
5930 nelem = 0;
5931 if (elem == NULL) {
5932 elem = new int*[GRCC_MAXGROUP];
5933 for (j = 0; j < GRCC_MAXGROUP; j++) {
5934 elem[j] = NULL;
5935 }
5936 }
5937}
5938
5939//------------------------------------------------------------
5940void SGroup::clearGroup(void)
5941{
5942 nelem = 0;
5943 csav = -1;
5944 cgen = -1;
5945}
5946
5947//------------------------------------------------------------
5948void SGroup::delGroup(void)
5949{
5950 int j;
5951
5952 for (j = 0; j < GRCC_MAXGROUP; j++) {
5953 if (elem[j] != NULL) {
5954 delete[] elem[j];
5955 elem[j] = NULL;
5956 }
5957 }
5958 delete[] elem;
5959 elem = NULL;
5960 clearGroup();
5961}
5962
5963//------------------------------------------------------------
5964int *SGroup::genNext(void)
5965{
5966 cgen = nextPerm(nnodes, neclass, eclass, pgr, pgq, permg, cgen);
5967 if (cgen < 0) {
5968 return NULL;
5969 }
5970 return permg;
5971}
5972
5973//------------------------------------------------------------
5974void SGroup::addGroup(int *p)
5975{
5976 int j;
5977
5978 if (nelem >= GRCC_MAXGROUP) {
5979 erEnd("addGroup : too many elements (GRCC_MAXGROUP)");
5980 }
5981 if (elem[nelem] == NULL) {
5982 elem[nelem] = new int[GRCC_MAXNODES];
5983 }
5984 for (j = 0; j < nnodes; j++) {
5985 elem[nelem][j] = p[j];
5986 }
5987 nelem++;
5988}
5989
5990//------------------------------------------------------------
5991BigInt SGroup::nElem(void)
5992{
5993 return nelem;
5994}
5995
5996//------------------------------------------------------------
5997int *SGroup::nextElem(void)
5998{
5999 if (nelem < 0) {
6000 cgen = nextPerm(nelem, neclass, eclass,
6001 psr, psq, perms, cgen);
6002 return perms;
6003 }
6004 if (cgen < 0) {
6005 cgen = 0;
6006 }
6007 if (cgen >= nelem) {
6008 return NULL;
6009 } else {
6010 return elem[cgen++];
6011 }
6012}
6013
6014//**************************************************************
6015// egraph.cc
6016// Generate scalar connected Feynman graphs.
6017//==============================================================
6018static const char *GRCC_ND_names[] = GRCC_ND_NAMES;
6019static const char *GRCC_ED_names[] = GRCC_ED_NAMES;
6020
6021//==============================================================
6022// class ENode
6023//--------------------------------------------------------------
6024ENode::ENode(void)
6025{
6026 id = -1;
6027 egraph = NULL;
6028 edges = NULL;
6029 maxdeg = 0;
6030 deg = 0;
6031
6032 klow = NULL;
6033 extloop = 0;
6034 ndtype = GRCC_ND_Undef;
6035
6036 intrct = -1;
6037}
6038
6039//--------------------------------------------------------------
6040ENode::ENode(EGraph *egrph, int loops, int sdeg)
6041
6042{
6043 id = -1;
6044 egraph = egrph;
6045 edges = NULL;
6046 maxdeg = sdeg;
6047 deg = 0;
6048
6049 klow = NULL;
6050 extloop = 0;
6051 ndtype = GRCC_ND_Undef;
6052
6053 intrct = -1;
6054
6055 edges = new int[sdeg];
6056 klow = new int[loops+1];
6057}
6058
6059//--------------------------------------------------------------
6060ENode::~ENode(void)
6061{
6062 if (klow != NULL) {
6063 delete[] klow;
6064 delete[] edges;
6065 klow = NULL;
6066 edges = NULL;;
6067 }
6068}
6069
6070//--------------------------------------------------------------
6071void ENode::copy(ENode *en)
6072{
6073 int d;
6074
6075 deg = en->deg;
6076 extloop = en->extloop;
6077 ndtype = en->ndtype;
6078 for (d = 0; d < deg; d++) {
6079 edges[d] = en->edges[d];
6080 }
6081}
6082
6083//--------------------------------------------------------------
6084void ENode::initAss(EGraph *egrph, int nid, int sdg)
6085{
6086 id = nid;
6087 egraph = egrph;
6088 maxdeg = sdg;
6089}
6090
6091//--------------------------------------------------------------
6092void ENode::setId(EGraph *egrph, const int nid)
6093{
6094 id = nid;
6095 egraph = egrph;
6096}
6097
6098//--------------------------------------------------------------
6099void ENode::setExtern(int typ, int pt)
6100{
6101 intrct = pt;
6102 if (typ == GRCC_AT_Initial || typ == GRCC_AT_Final) {
6103 extloop = typ;
6104 } else {
6105 grcc_fprintf(GRCC_Stderr, "** ENode::setExternal:: illegal typ=%d\n",
6106 typ);
6107 erEnd("ENode::setExternal:: illegal typ");
6108 }
6109}
6110
6111//--------------------------------------------------------------
6112void ENode::setType(int typ)
6113{
6114#ifdef CHECK
6115 if (ndtype != GRCC_ND_Undef && ndtype != typ) {
6116 grcc_fprintf(GRCC_Stderr, "*** ndtype is already defined : old=%d, new = %d\n",
6117 ndtype, typ);
6118 erEnd("ndtype is already defined");
6119 }
6120#endif
6121 ndtype = typ;
6122}
6123
6124//--------------------------------------------------------------
6125void ENode::print(void)
6126{
6127 int j;
6128
6129 grcc_fprintf(GRCC_Stdout, "Enode %d deg=%d, extl=%2d, intr=%d ",
6130 id, deg, extloop, intrct);
6131 if (egraph->bicount > 0) {
6132 grcc_fprintf(GRCC_Stdout, "(%-8s) ", GRCC_ND_names[ndtype]);
6133 }
6134 grcc_fprintf(GRCC_Stdout, "edge=[");
6135 for (j = 0; j < deg; j++) {
6136 grcc_fprintf(GRCC_Stdout, " %2d", edges[j]);
6137 }
6138 grcc_fprintf(GRCC_Stdout, "]\n");
6139}
6140
6141//==============================================================
6142// class EEdge
6143//--------------------------------------------------------------
6144EEdge::EEdge(void)
6145{
6146 id = -1;
6147 egraph = NULL;
6148 nodes[0] = -1;
6149 nodes[1] = -1;
6150 // nlegs[0] = -1;
6151 // nlegs[1] = -1;
6152 ptcl = GRCC_PT_Undef;
6153 deleted = False;
6154
6155 edtype = GRCC_ED_Undef;
6156 cut = False;
6157
6158 emom = NULL;
6159 lmom = NULL;
6160
6161 momset = 0;
6162 momdir = 0;
6163}
6164
6165//--------------------------------------------------------------
6166EEdge::EEdge(EGraph *egrph, int nedges, int nloops)
6167{
6168 id = -1;
6169 egraph = egrph;
6170 nodes[0] = -1;
6171 nodes[1] = -1;
6172 nlegs[0] = -1;
6173 nlegs[1] = -1;
6174 ptcl = GRCC_PT_Undef;
6175 deleted = False;
6176
6177 edtype = GRCC_ED_Undef;
6178 cut = False;
6179
6180 emom = new int[nedges];
6181 lmom = new int[nloops];
6182}
6183
6184//--------------------------------------------------------------
6185EEdge::~EEdge(void)
6186{
6187 if (lmom != NULL) {
6188 delete[] lmom;
6189 }
6190 if (emom != NULL) {
6191 delete[] emom;
6192 }
6193}
6194
6195//--------------------------------------------------------------
6196void EEdge::copy(EEdge *ee)
6197{
6198 nodes[0] = ee->nodes[0];
6199 nodes[1] = ee->nodes[1];
6200 id = ee->id;
6201 ext = ee->ext;
6202 dir = ee->dir;
6203 edtype = ee->edtype;
6204 cut = ee->cut;
6205}
6206
6207//--------------------------------------------------------------
6208void EEdge::setId(EGraph *egrph, const int eid)
6209{
6210 id = eid;
6211 egraph = egrph;
6212}
6213
6214//--------------------------------------------------------------
6215void EEdge::setType(int typ)
6216{
6217#ifdef CHECK
6218 if (edtype != GRCC_ED_Undef) {
6219 erEnd("edtype is already defined");
6220 }
6221#endif
6222 edtype = typ;
6223}
6224
6225//--------------------------------------------------------------
6226void EEdge::setEMom(int nedges, int *em, int dir)
6227{
6228 int e;
6229
6230 for (e = 0; e < nedges; e++) {
6231 if (em[e] != 0) {
6232 emom[e] = dir;
6233 }
6234 }
6235}
6236
6237//--------------------------------------------------------------
6238void EEdge::setLMom(int k, int dir)
6239{
6240 lmom[k] = dir;
6241}
6242
6243//--------------------------------------------------------------
6244void EEdge::print(void)
6245{
6246 int zero, n, k;
6247
6248 grcc_fprintf(GRCC_Stdout, "Edge %2d ext=%d ptcl=%2d ", id, ext, ptcl);
6249 if (egraph == NULL || !egraph->assigned) {
6250 grcc_fprintf(GRCC_Stdout, "[%d, %d]", nodes[0], nodes[1]);
6251 } else {
6252 grcc_fprintf(GRCC_Stdout, "[(%d,%d), (%d,%d))", nodes[0], nlegs[0], nodes[1], nlegs[1]);
6253 }
6254 if (momdir != 0) {
6255 grcc_fprintf(GRCC_Stdout, "[%2d*%2lu]", momdir, momset);
6256 }
6257
6258 if (egraph != NULL && egraph->bicount > 0) {
6259 if (cut) {
6260 grcc_fprintf(GRCC_Stdout, " %-9s ", "Cut");
6261 } else {
6262 grcc_fprintf(GRCC_Stdout, " %-9s ", GRCC_ED_names[edtype]);
6263 }
6264 grcc_fprintf(GRCC_Stdout, "c%2d: ", opicomp);
6265 grcc_fprintf(GRCC_Stdout, "%s%d =", (ext)?"Q":"p", id);
6266 zero = True;
6267 for (n = 0; n < egraph->nEdges; n++) {
6268 if (emom[n] != 0) {
6269 prMomStr(emom[n], "Q", n);
6270 zero = False;
6271 }
6272 }
6273 for (k = 0; k < egraph->nLoops; k++) {
6274 if (lmom[k] != 0) {
6275 prMomStr(lmom[k], "k", k);
6276 zero = False;
6277 }
6278 }
6279 if (zero) {
6280 grcc_fprintf(GRCC_Stdout, " 0");
6281 }
6282 } else {
6283 if (egraph == NULL) {
6284 grcc_fprintf(GRCC_Stdout, " egraph=NULL");
6285 } else {
6286 grcc_fprintf(GRCC_Stdout, " egraph->bicount=%d", egraph->bicount);
6287 }
6288 }
6289 grcc_fprintf(GRCC_Stdout, "\n");
6290}
6291
6292//==============================================================
6293// class EFLine
6294//--------------------------------------------------------------
6295EFLine::EFLine(void)
6296{
6297 ftype = FL_Open;
6298 fkind = 0;
6299 nlist = 0;
6300}
6301
6302//--------------------------------------------------------------
6303void EFLine::print(const char *msg)
6304{
6305 if (ftype == FL_Open) {
6306 grcc_fprintf(GRCC_Stdout, " Open");
6307 } else if (ftype == FL_Closed) {
6308 grcc_fprintf(GRCC_Stdout, " Loop");
6309 } else {
6310 grcc_fprintf(GRCC_Stdout, " ?%d", ftype);
6311 }
6312 if (fkind == GRCC_PT_Dirac) {
6313 grcc_fprintf(GRCC_Stdout, " Dirac");
6314 } else if (fkind == GRCC_PT_Majorana) {
6315 grcc_fprintf(GRCC_Stdout, " Major");
6316 } else if (fkind == GRCC_PT_Ghost) {
6317 grcc_fprintf(GRCC_Stdout, " Ghost");
6318 } else {
6319 grcc_fprintf(GRCC_Stdout, " ?%d", fkind);
6320 }
6321 grcc_fprintf(GRCC_Stdout, " len=%d ", nlist);
6322 prIntArray(nlist, elist, msg);
6323}
6324
6325//==============================================================
6326// class EGraph
6327//--------------------------------------------------------------
6328EGraph::EGraph(int nnodes, int nedges, int mxdeg)
6329{
6330 // Arguments
6331 // nnodes : the number of nodes
6332 // nedges : the number of edges
6333 // mxdeg : the maximum number of degrees of nodes
6334
6335 int j;
6336
6337 opt = NULL;
6338 mgraph = NULL;
6339 econn = NULL;
6340
6341 sNodes = nnodes;
6342 sEdges = nedges;
6343 sMaxdeg = mxdeg;
6344 sLoops = sEdges - sNodes + 1; // assume connected graph
6345
6346 pId = -1;
6347 mId = -1;
6348 aId = -1;
6349 sId = 0;
6350 gSubId = -1;
6351 assigned = False;
6352
6353 nNodes = sNodes;
6354 nEdges = sEdges;
6355 nLoops = 0;
6356 nExtern = 0;
6357
6358 nsym = 1;
6359 esym = 1;
6360 extperm = 1;
6361 nsym1 = 1;
6362 multp = 1;
6363 totalc = 0;
6364
6365 nodes = new ENode*[sNodes];
6366 for (j = 0; j < sNodes; j++) {
6367 nodes[j] = new ENode(this, sNodes, sMaxdeg);
6368 }
6369 edges = new EEdge*[sEdges];
6370 for (j = 0; j < sEdges; j++) {
6371 edges[j] = new EEdge(this, sEdges, sLoops);
6372 }
6373
6374 bidef = new int[sNodes];
6375 bilow = new int[sNodes];
6376 bicount = -1;
6377
6378 extMom = new int[sEdges+1];
6379
6380 fsign = 1;
6381 nFlines = -1;
6382 for (j = 0; j < GRCC_MAXFLINES; j++) {
6383 flines[j] = NULL;
6384 }
6385}
6386
6387//--------------------------------------------------------------
6388EGraph::~EGraph(void)
6389{
6390 int j;
6391
6392 for (j = GRCC_MAXFLINES-1; j >= 0; j--) {
6393 if (flines[j] != NULL) {
6394 delete flines[j];
6395 flines[j] = NULL;
6396 }
6397 }
6398
6399 delete[] extMom;
6400
6401 delete[] bilow;
6402 delete[] bidef;
6403
6404 for (j = 0; j < sEdges; j++) {
6405 delete edges[j];
6406 edges[j] = NULL;
6407 }
6408 delete[] edges;
6409
6410 for (j = 0; j < sNodes; j++) {
6411 delete nodes[j];
6412 nodes[j] = NULL;
6413 }
6414 delete[] nodes;
6415
6416}
6417
6418//--------------------------------------------------------------
6419void EGraph::copy(EGraph *eg)
6420{
6421 int nd, ed;
6422
6423#ifdef CHECK
6424 if (sNodes < eg->nNodes || sEdges < eg->nEdges ||
6425 sMaxdeg < eg->sMaxdeg || sLoops < eg->nLoops) {
6426 erEnd("EGraph::copy: sizes are too small");
6427 }
6428#endif
6429 model = eg->model;
6430 proc = eg->proc;
6431 sproc = eg->sproc;
6432 mgraph = eg->mgraph;
6433 opt = mgraph->opt;
6434 econn = mgraph->mconn;
6435
6436 pId = eg->pId;
6437 mId = eg->mId;
6438 gSubId = eg->gSubId;
6439 nNodes = eg->nNodes;
6440 nEdges = eg->nEdges;
6441 nExtern = eg->nExtern;
6442 nLoops = eg->nLoops;
6443
6444 for (nd = 0; nd < nNodes; nd++) {
6445 nodes[nd]->copy(eg->nodes[nd]);
6446 }
6447 for (ed = 0; ed < nEdges; ed++) {
6448 edges[ed]->copy(eg->edges[ed]);
6449 }
6450
6451 nsym = eg->nsym;
6452 esym = eg->esym;
6453 extperm = eg->extperm;
6454 nsym1 = eg->nsym1;
6455 multp = eg->multp;
6456
6457 bicount = -1;
6458}
6459
6460//--------------------------------------------------------------
6461void EGraph::setExtLoop(int nd, int val)
6462{
6463 // set the node 'nd' being an external node (-1) or a looped vertex
6464 nodes[nd]->extloop = val;
6465}
6466
6467//--------------------------------------------------------------
6468void EGraph::endSetExtLoop(void)
6469{
6470 // end of calling 'setExtLoop'.
6471
6472 int n;
6473
6474 nExtern = 0;
6475 for (n = 0; n < nNodes; n++) {
6476 if (isExternal(n)) {
6477 nExtern++;
6478 }
6479 }
6480}
6481
6482//--------------------------------------------------------------
6483void EGraph::fromDGraph(DGraph *dg)
6484{
6485 int deg[GRCC_MAXNODES];
6486 int maxdeg, nextern, nconn, tc;
6487 int n0, n1, e;
6488
6489 if (dg->nnodes > GRCC_MAXNODES) {
6490 grcc_fprintf(GRCC_Stderr, "*** too many nodes (GRCC_MAXNODES)\n");
6491 GRCC_ABORT();
6492 }
6493 if (dg->nedges > GRCC_MAXEDGES) {
6494 grcc_fprintf(GRCC_Stderr, "*** too many edges (GRCC_MAXEDGES)\n");
6495 GRCC_ABORT();
6496 }
6497
6498 for (e = 0; e < dg->nedges; e++) {
6499 if (dg->edges[e][0] >= dg->nnodes || dg->edges[e][0] >= dg->nnodes) {
6500 grcc_fprintf(GRCC_Stderr, "*** undefined node:");
6501 grcc_fprintf(GRCC_Stderr, "edge[%d] = {%d, %d}\n",
6502 e, dg->edges[e][0], dg->edges[e][0]);
6503 GRCC_ABORT();
6504 }
6505 }
6506
6507 for (n0 = 0; n0 < dg->nnodes; n0++) {
6508 deg[n0] = 0;
6509 }
6510 for (e = 0; e < dg->nedges; e++) {
6511 deg[dg->edges[e][0]]++;
6512 deg[dg->edges[e][1]]++;
6513 }
6514 maxdeg = 0;
6515 nextern = 0;
6516 for (n0 = 0; n0 < dg->nnodes; n0++) {
6517 maxdeg = Max(maxdeg, deg[n0]);
6518 if (deg[n0] == 1) {
6519 nextern++;
6520 } if (deg[n0] < 0) {
6521 grcc_fprintf(GRCC_Stderr, "+++ node %d is isolated\n", n0);
6522 }
6523 }
6524
6525 mgraph = NULL;
6526 model = NULL;
6527 proc = NULL;
6528 sproc = NULL;
6529 opt = NULL;
6530
6531 nNodes = dg->nnodes;
6532 nEdges = dg->nedges;
6533 nLoops = 0;
6534 nExtern = nextern;
6535
6536 pId = 0;
6537 mId = 0;
6538 aId = 0;
6539 gSubId = 0;
6540 nsym = 1;
6541 nsym1 = 1;
6542 esym = 1;
6543 extperm = 1;
6544 multp = 1;
6545 maxdeg = maxdeg;
6546
6547 for (n0 = 0; n0 < dg->nnodes; n0++) {
6548 nodes[n0]->deg = 0;
6549 nodes[n0]->extloop = dg->nodes[n0].extloop;
6550 }
6551 for (e = 0; e < dg->nedges; e++) {
6552 n0 = dg->edges[e][0];
6553 n1 = dg->edges[e][1];
6554 edges[e]->nodes[0] = n0;
6555 edges[e]->nodes[1] = n1;
6556 edges[e]->ext = (isExternal(n0) || isExternal(n1));
6557 edges[e]->momdir = 0;
6558
6559 nodes[n0]->edges[nodes[n0]->deg++] = I2Vedge(e, -1);
6560 nodes[n1]->edges[nodes[n1]->deg++] = I2Vedge(e, +1);
6561 }
6562 for (n0 = 0; n0 < dg->nnodes; n0++) {
6563 nodes[n0]->setId(this, n0);
6564 nodes[n0]->intrct = dg->nodes[n0].intrct;
6565 }
6566
6567 for (e = 0; e < nEdges; e++) {
6568 edges[e]->setId(this, e);
6569 }
6570 tc = 0;
6571 for (n0 = 0; n0 < nNodes; n0++) {
6572 if (isExternal(n0)) {
6573 setExtern(n0, 1, GRCC_AT_Initial);
6574 } else {
6575 tc += 2*nodes[n0]->extloop + nodes[n0]->deg - 2;
6576 }
6577 }
6578 totalc = tc;
6579
6580 // get the number of connected components
6581 nconn = connComp();
6582 nLoops = nEdges - nNodes + nconn;
6583
6584 bicount = -1;
6585}
6586
6587
6588//--------------------------------------------------------------
6589void EGraph::fromMGraph(MGraph *mg)
6590{
6591 // construct EGraph from adjacency matrix.
6592 // This function should be called after
6593 // EGraph(), setExtLoop() and endSetExtLoop().
6594
6595 int n0, n1, m0, m1, ed, e;
6596 int j, ni, nf;
6597 PNodeClass *pnc;
6598 int k;
6599
6600#ifdef CHECK
6601 if (sNodes < mg->nNodes || sEdges < mg->nEdges || sMaxdeg < mg->maxdeg) {
6602 erEnd("EGraph::fromMGraph: sizes are too small");
6603 }
6604 if (sLoops < mg->nLoops) {
6605 grcc_fprintf(GRCC_Stdout, "too small sLoops : %d < %d\n", sLoops, mg->nLoops);
6606 erEnd("too small sLoops");
6607 }
6608#endif
6609 mgraph = mg;
6610 opt = mgraph->opt;
6611 econn = mgraph->mconn;
6612 sproc = opt->sproc;
6613 if (sproc == NULL) {
6614 proc = NULL;
6615 model = NULL;
6616 } else {
6617 proc = sproc->proc;
6618 model = sproc->model;
6619 }
6620
6621 nNodes = mg->nNodes;
6622 nEdges = mg->nEdges;
6623 nLoops = mg->nLoops;
6624 nExtern = mg->nExtern;
6625 pId = mg->pId;
6626 mId = mg->cDiag;
6627 aId = -1;
6628 if (opt->proc != NULL) {
6629 mId = mg->opt->proc->mgrcount;
6630 sId = mg->opt->proc->agrcount;
6631 } else if (mg->opt->sproc != NULL) {
6632 mId = mg->opt->sproc->mgrcount;
6633 sId = mg->opt->sproc->agrcount;
6634 } else {
6635 mId = mg->cDiag;
6636 sId = mg->cDiag;
6637 }
6638 gSubId = 0;
6639 nsym = mg->nsym;
6640 esym = mg->esym;
6641 extperm = 1;
6642 nsym1 = nsym;
6643 multp = 1;
6644 maxdeg = mg->maxdeg;
6645
6646 totalc = 0;
6647 if (proc != NULL) {
6648 for (j = 0; j < proc->model->ncouple; j++) {
6649 totalc += proc->clist[j];
6650 }
6651 }
6652 for (ed = 0; ed < nEdges; ed++) {
6653 edges[ed]->edtype = GRCC_ED_Undef;
6654 }
6655
6656 ed = 0;
6657 for (n0 = 0; n0 < nNodes; n0++) {
6658 nodes[n0]->deg = 0;
6659 }
6660 for (n0 = 0; n0 < nNodes; n0++) {
6661 for (e = 0; e < mg->adjMat[n0][n0]/2; e++, ed++) {
6662 edges[ed]->nodes[0] = n0;
6663 edges[ed]->nodes[1] = n0;
6664 nodes[n0]->edges[nodes[n0]->deg++] = I2Vedge(ed, -1);
6665 nodes[n0]->edges[nodes[n0]->deg++] = I2Vedge(ed, +1);
6666 edges[ed]->ext = isExternal(n0);
6667 }
6668 for (n1 = n0+1; n1 < nNodes; n1++) {
6669 for (e = 0; e < mg->adjMat[n0][n1]; e++, ed++) {
6670 edges[ed]->nodes[0] = n0;
6671 edges[ed]->nodes[1] = n1;
6672 nodes[n0]->edges[nodes[n0]->deg++] = I2Vedge(ed, -1);
6673 nodes[n1]->edges[nodes[n1]->deg++] = I2Vedge(ed, +1);
6674 edges[ed]->ext = (isExternal(n0) || isExternal(n1));
6675 }
6676 }
6677 }
6678#ifdef CHECK
6679 if (ed != nEdges) {
6680 grcc_fprintf(GRCC_Stdout, "*** EGraph::init: ed=%d != nEdges=%d\n",
6681 ed, nEdges+1);
6682 erEnd("EGraph::init: illegal connection");
6683 }
6684#endif
6685
6686 for (j = 0; j < nNodes; j++) {
6687 nodes[j]->setId(this, j);
6688 nodes[j]->intrct = mg->nodes[j]->extloop;
6689 }
6690
6691 for (j = 0; j < nEdges; j++) {
6692 edges[j]->setId(this, j);
6693 }
6694
6695 ni = 0;
6696 nf = 0;
6697 if (proc != NULL) {
6698 ni = proc->ninitl;
6699 for (j = 0; j < ni; j++) {
6700 setExtern(j, proc->initlPart[j], GRCC_AT_Initial);
6701 }
6702
6703 nf = proc->nfinal;
6704 for (j = 0; j < nf; j++) {
6705 setExtern(j+ni, proc->finalPart[j], GRCC_AT_Final);
6706 }
6707 nExtern = ni + nf;
6708 } else if (sproc != NULL) {
6709 pnc = sproc->pnclass;
6710 for (j = 0; j < sproc->pnclass->nclass; j++) {
6711 if (pnc->type[j] == GRCC_AT_Initial
6712 || pnc->type[j] == GRCC_AT_External) {
6713 for (k = pnc->cl2nd[j]; k < pnc->cl2nd[j+1]; k++) {
6714 setExtern(j, k, GRCC_AT_Initial);
6715 ni++;
6716 }
6717 } else if (sproc->pnclass->type[j] == GRCC_AT_Final) {
6718 for (k = pnc->cl2nd[j]; k < pnc->cl2nd[j+1]; k++) {
6719 setExtern(j, k, GRCC_AT_Final);
6720 nf++;
6721 }
6722 }
6723
6724 }
6725 nExtern = ni + nf;
6726 }
6727 totalc = 0;
6728 for (j = 0; j < nNodes; j++) {
6729 if (!isExternal(j)) {
6730 totalc += 2*nodes[j]->extloop + nodes[j]->deg - 2;
6731 }
6732 }
6733
6734 for (ed = 0; ed < nEdges; ed++) {
6735 edges[ed]->momdir = 0;
6736 }
6737 for (e = 0; e < econn->sedges; e++) {
6738 m0 = econn->cedges[e].nodes[0];
6739 m1 = econn->cedges[e].nodes[1];
6740
6741 bool found = False;
6742 for (ed = 0; ed < nEdges; ed++) {
6743 if (edges[ed]->momdir != 0) {
6744 continue;
6745 }
6746 n0 = edges[ed]->nodes[0];
6747 n1 = edges[ed]->nodes[1];
6748 if (m0 == n0 && m1 == n1) {
6749 edges[ed]->momdir = econn->cedges[e].momdir;
6750 edges[ed]->momset = econn->cedges[e].momset;
6751 found = True;
6752 break;
6753 } else if (m0 == n1 && m1 == n0) {
6754 edges[ed]->momdir = - econn->cedges[e].momdir;
6755 edges[ed]->momset = econn->cedges[e].momset;
6756 found = True;
6757 break;
6758 }
6759 }
6760
6761 if (! found) {
6762 grcc_fprintf(GRCC_Stdout, "*** EGraph::fromMGraph:edge (%d->%d) is not found\n",
6763 m0, m1);
6764 }
6765 }
6766
6767 bicount = -1;
6768}
6769
6770//--------------------------------------------------------------
6771ENode *EGraph::setExtern(int n0, int pt, int ndtyp)
6772{
6773 ENode *nd;
6774 int npt, ept, eg;
6775
6776 nd = nodes[n0];
6777 if (nd->deg != 1) {
6778 if (prlevel > 0) {
6779 grcc_fprintf(GRCC_Stderr, "*** illegal external particle %d, %d, %d\n",
6780 n0,pt,ndtyp);
6781 }
6782 erEnd("illegal external particle");
6783 }
6784
6785 // particle comes into the node
6786 if (ndtyp == GRCC_AT_Initial) {
6787 npt = pt;
6788 } else if (ndtyp == GRCC_AT_Final) {
6789 npt = -pt;
6790 } else {
6791 npt = 0;
6792 if (prlevel > 0) {
6793 grcc_fprintf(GRCC_Stderr, "*** illegal type of an external particle : "
6794 "node = %d, particle = %d, type = %d", n0, pt, ndtyp);
6795 }
6796 erEnd("illegal type of an external particle");
6797 }
6798
6799 // edge attached to the external node
6800 eg = n0;
6801
6802 // particle flows on e from leg=0 to 1.
6803 if (model != NULL){
6804 npt = model->normalParticle(npt);
6805 ept = model->normalParticle(npt);
6806 } else {
6807 npt = 0;
6808 ept = 0;
6809 }
6810
6811 nd->setExtern(ndtyp, npt);
6812 edges[eg]->ptcl = ept;
6813
6814 return nd;
6815}
6816
6817//--------------------------------------------------------------
6818void EGraph::print(void)
6819{
6820 // print the EGraph
6821
6822 int nd, ed, nlp;
6823
6824 nlp = nEdges - nNodes + 1;
6825 grcc_fprintf(GRCC_Stdout, "\nEGraph\n");
6826 grcc_fprintf(GRCC_Stdout, " pId=%d, gSubId=%ld, mId=%ld, aId=%ld, sId=%ld\n",
6827 pId, gSubId, mId, aId, sId);
6828 grcc_fprintf(GRCC_Stdout, " sNodes=%d, sEdges=%d, sMaxdeg=%d, sLoops=%d\n",
6829 sNodes, sEdges, sMaxdeg, sLoops);
6830 grcc_fprintf(GRCC_Stdout, " nNodes=%d, nEdges=%d, nExtern=%d, nLoops=%d, totalc=%d\n",
6831 nNodes, nEdges, nExtern, nlp, totalc);
6832 grcc_fprintf(GRCC_Stdout, " ");
6833 if (model == NULL) {
6834 grcc_fprintf(GRCC_Stdout, "model=NULL,");
6835 } else {
6836 grcc_fprintf(GRCC_Stdout, "model=\"%s\",", model->name);
6837 }
6838 if (proc == NULL) {
6839 grcc_fprintf(GRCC_Stdout, "proc=NULL,");
6840 } else {
6841 grcc_fprintf(GRCC_Stdout, "proc=%d,", proc->id);
6842 }
6843 if (sproc == NULL) {
6844 grcc_fprintf(GRCC_Stdout, "sproc=NULL,");
6845 } else {
6846 grcc_fprintf(GRCC_Stdout, "sproc=%d,", sproc->id);
6847 }
6848 grcc_fprintf(GRCC_Stdout, "\n");
6849 grcc_fprintf(GRCC_Stdout, " assigned=%d, sym = (%ld * %ld) ",
6850 assigned, nsym, esym);
6851 grcc_fprintf(GRCC_Stdout, "extperm=%ld, nsym1=%ld, multp=%ld\n",
6852 extperm, nsym1, multp);
6853
6854 grcc_fprintf(GRCC_Stdout, " Nodes\n");
6855 for (nd = 0; nd < nNodes; nd++) {
6856 if (isExternal(nd)) {
6857 grcc_fprintf(GRCC_Stdout, " %2d Extern ", nd);
6858 } else {
6859 grcc_fprintf(GRCC_Stdout, " %2d Vertex ", nd);
6860 }
6861 nodes[nd]->print();
6862 }
6863 grcc_fprintf(GRCC_Stdout, " Edges\n");
6864 for (ed = 0; ed < nEdges; ed++) {
6865 if (edges[ed]->ext) {
6866 grcc_fprintf(GRCC_Stdout, " %2d Extern ", ed);
6867 } else {
6868 grcc_fprintf(GRCC_Stdout, " %2d Intern ", ed);
6869 }
6870 edges[ed]->print();
6871 }
6872 if (bicount > 0) {
6873 grcc_fprintf(GRCC_Stdout, " Biconn: nopicomp=%d, nopi2p=%d, opi2plp=%d, nadj2ptv=%d\n",
6874 nopicomp, nopi2p, opi2plp, nadj2ptv);
6875 }
6876 grcc_fprintf(GRCC_Stdout, "\n");
6877
6878 if (nFlines > 0) {
6879 prFLines();
6880 }
6881}
6882
6883//--------------------------------------------------------------
6884void EGraph::printPy(FILE *fp, long mId)
6885{
6886 if (!assigned) {
6887 mgraph->printPy(fp, mId);
6888 return;
6889 }
6890
6891 fprintf(fp, "#AGraph : (gseq, {spid, gid, ...}, nodes, node-group)\n");
6892 fprintf(fp, "(%ld,\n", mId);
6893
6894 // {'proc':0, 'subproc':0, 'tgraph':1, ... }
6895 fprintf(fp, " {'proc':%d, 'subproc':%d, ", proc->id, sproc->id);
6896 fprintf(fp, "'tgraph':%ld, ", mId);
6897 fprintf(fp, "'OPI':%s, ", BOOLSTR(opt->values[GRCC_OPT_1PI]));
6898 fprintf(fp, "'agraph':%ld, \n", aId);
6899 fprintf(fp, " 'nnodes':%d, 'nnsym':%ld, 'nesym':%ld, },\n",
6900 nNodes, nsym, esym);
6901 // #nodes
6902 fprintf(fp, " [ #nodes\n");
6903 for (int nd = 0; nd < nNodes; nd++) {
6904 ENode *end = nodes[nd];
6905
6906 // #node 0: external=phi
6907 // #node 4: phi3=0
6908 fprintf(fp, " [ #node %d: ", nd);
6909 fprintf(fp, "\n");
6910
6911 // {'deg':1, 'cid':-3, ..., }
6912 fprintf(fp, " {'deg':%d, 'cid':%d, 'extern':%s, ",
6913 end->deg, 0, BOOLSTR(isExternal(nd)));
6914 fprintf(fp, "'intr':%d, 'loop':%d, },\n",
6915 end->intrct, end->extloop);
6916
6917 // legs : (edge, leg, particle)
6918 // [ (0, 1, 0), ... ],
6919 fprintf(fp, " [ ");
6920 for (int lg = 0; lg < end->deg; lg++) {
6921 int ed = V2Iedge(end->edges[lg]);
6922 int ptcl = edges[ed]->ptcl;
6923 int edlg = (edges[ed]->nodes[0] == nd) ? 1 : 0;
6924 int nnd = edges[ed]->nodes[edlg];
6925 int nlg = edges[ed]->nlegs[edlg];
6926 fprintf(fp, "(%d, %d, %d), ", nnd, ptcl, nlg);
6927 }
6928 fprintf(fp, "],\n");
6929 fprintf(fp, " ],\n"); // end #node
6930 }
6931 fprintf(fp, " ], #node\n");
6932 fprintf(fp, " [ # group of 1 elements\n");
6933 fprintf(fp, " [], #\n");
6934 fprintf(fp, " ], # group\n");
6935 fprintf(fp, ")\n");
6936}
6937
6938//--------------------------------------------------------------
6939void EGraph::prFLines(void)
6940{
6941 int j;
6942
6943 grcc_fprintf(GRCC_Stdout, " Fermion lines %d, sign=%d (mId=%ld, aId=%ld)\n",
6944 nFlines, fsign, mId, aId);
6945 for (j = 0; j < nFlines; j++) {
6946 grcc_fprintf(GRCC_Stdout, "%4d ", j);
6947 flines[j]->print("\n");
6948 }
6949}
6950
6951//--------------------------------------------------------------
6952int EGraph::dirEdge(int n, int e)
6953{
6954 if (nodes[n]->edges[e] > 0) {
6955 return 1;
6956 } else {
6957 return -1;
6958 }
6959}
6960
6961//--------------------------------------------------------------
6962int EGraph::cmpMom(int *lm0, int *em0, int *lm1, int *em1)
6963{
6964 int lp, ed, cmp, sgn = 0;
6965
6966 for (lp = 0; lp < nLoops; lp++) {
6967 if (lm0[lp] != 0) {
6968 if (lm1[lp] == 0) {
6969 return 1;
6970 } else if (sgn == 0) {
6971 sgn = lm0[lp]*lm1[lp]; // cancel first non-zero elements
6972#ifdef CHECK
6973 if (Abs(sgn) != 1) {
6974 erEnd("cmpMom : illegal element of lmom");
6975 }
6976#endif
6977 } else {
6978 cmp = lm0[lp] - sgn*lm1[lp];
6979 if (cmp != 0) {
6980 return cmp;
6981 }
6982 }
6983 } else if (lm1[lp] != 0) { // lm0[lp] == 0
6984 return -1;
6985 }
6986 }
6987 for (ed = 0; ed < nEdges; ed++) {
6988 if (em0[ed] != 0) {
6989 if (em1[ed] == 0) {
6990 return 1;
6991 } else if (sgn == 0) {
6992 sgn = em0[ed]*em1[ed]; // cancel first non-zero elements
6993#ifdef CHECK
6994 if (Abs(sgn) != 1) {
6995 erEnd("cmpMom : illegal element of emom");
6996 }
6997#endif
6998 } else {
6999 cmp = em0[ed] - sgn*em1[ed];
7000 if (cmp != 0) {
7001 return cmp;
7002 }
7003 }
7004 } else if (em1[ed] != 0) { // em0[ed] == 0
7005 return -1;
7006 }
7007 }
7008 return 0;
7009}
7010
7011//--------------------------------------------------------------
7012int EGraph::groupLMom(int *grp, int *ed2gr)
7013{
7014 // grp[g] : the number of elements in the group g (in [0,...,(ngrp-1)])
7015 // ed2gr[ed] : group number of edge ed.
7016
7017 int ed0, ed1, cmp, ngrp = -1;
7018
7019 for (ed0 = 0; ed0 < nEdges; ed0++) {
7020 ed2gr[ed0] = -1;
7021 grp[ed0] = 0;
7022 }
7023
7024 for (ed0 = 0; ed0 < nEdges; ed0++) {
7025 if (ed2gr[ed0] < 0) {
7026 ngrp++;
7027 ed2gr[ed0] = ngrp;
7028 grp[ngrp]++;
7029 for (ed1 = ed0+1; ed1 < nEdges; ed1++) {
7030 cmp = cmpMom(edges[ed0]->lmom, edges[ed0]->emom,
7031 edges[ed1]->lmom, edges[ed1]->emom);
7032 if (cmp == 0) {
7033 ed2gr[ed1] = ngrp;
7034 grp[ngrp]++;
7035 }
7036 }
7037 }
7038 }
7039 ngrp++;
7040
7041 return ngrp;
7042}
7043
7044//--------------------------------------------------------------
7045Bool EGraph::optQGrafM(Options *opt)
7046{
7047 int *qgopt = opt->qgopt;
7048 int nopis[GRCC_MAXEDGES];
7049 ULong mext = 0;
7050 mext = (~ mext) << nExtern;
7051
7052#ifdef PRINT
7053 grcc_fprintf(GRCC_Stdout, "optQGrafM:");
7054 print();
7055#endif
7056
7057#ifdef PRINT
7058 grcc_fprintf(GRCC_Stdout, "optQGrafM: %8ld\n", mId);
7059 econn->print();
7060#endif
7061
7062 // count the number of self-energy 1PI components.
7063 int maxlegs = 0;
7064 for (int j = 0; j < econn->nopic; j++) {
7065 maxlegs = Max(maxlegs, econn->opics[j].nlegs);
7066 }
7067 if (maxlegs >= GRCC_MAXEDGES) {
7068 grcc_fprintf(GRCC_Stdout, "*** table overflow\n");
7069 GRCC_ABORT();
7070 }
7071 for (int k = 0; k < GRCC_MAXEDGES; k++) {
7072 nopis[k] = 0;
7073 }
7074 for (int j = 0; j < econn->nopic; j++) {
7075 nopis[econn->opics[j].nlegs]++;
7076 }
7077
7078 //
7079 if (qgopt[GRCC_QGRAF_OPT_ONEPI] > 0) {
7080 if (econn->nopic != 1) {
7081 return False;
7082 }
7083 } else if (qgopt[GRCC_QGRAF_OPT_ONEPI] < 0) {
7084 if (econn->nopic < 2) {
7085 return False;
7086 }
7087 }
7088
7089 if (qgopt[GRCC_QGRAF_OPT_ONSHELL] != 0) {
7090 if (nExtern == 1) {
7091 if (qgopt[GRCC_QGRAF_OPT_ONSHELL] > 0) {
7092 if (econn->nopic != 1) {
7093 return False;
7094 }
7095 } else if (qgopt[GRCC_QGRAF_OPT_ONSHELL] < 0) {
7096 if (econn->nopic == 1) {
7097 return False;
7098 }
7099 }
7100 } else {
7101 if (qgopt[GRCC_QGRAF_OPT_ONSHELL] > 0) {
7102 if (econn->ne1bridges > 0) {
7103 return False;
7104 }
7105 } else if (qgopt[GRCC_QGRAF_OPT_ONSHELL] < 0) {
7106 if (econn->ne1bridges <= 0) {
7107 return False;
7108 }
7109 }
7110 }
7111 }
7112
7113 if (qgopt[GRCC_QGRAF_OPT_NOSNAIL] != 0) {
7114 if (qgopt[GRCC_QGRAF_OPT_NOSNAIL] > 0) {
7115 if (nExtern == 1) {
7116 if (econn->nblocks != 1) {
7117 return False;
7118 }
7119 } else {
7120 if (mgraph->mconn->ne0bridges >= 1 ||
7121 mgraph->mconn->na1blocks >= 1) {
7122 return False;
7123 }
7124 }
7125 } else if (qgopt[GRCC_QGRAF_OPT_NOSNAIL] < 0) {
7126 if (nExtern == 1) {
7127 if (econn->nblocks == 1) {
7128 return False;
7129 }
7130 } else {
7131 if (mgraph->mconn->ne0bridges < 1 &&
7132 mgraph->mconn->na1blocks < 1) {
7133 return False;
7134 }
7135 }
7136 }
7137 }
7138
7139 if (qgopt[GRCC_QGRAF_OPT_NOTADPOLE] != 0) {
7140 if (nExtern == 1) {
7141 if (qgopt[GRCC_QGRAF_OPT_NOTADPOLE] > 0) {
7142 if (econn->nopic != 1) {
7143 return False;
7144 }
7145 } else if (qgopt[GRCC_QGRAF_OPT_NOTADPOLE] < 0) {
7146 if (econn->nopic == 1) {
7147 return False;
7148 }
7149 }
7150 } else {
7151 if (qgopt[GRCC_QGRAF_OPT_NOTADPOLE] > 0) {
7152 if (mgraph->mconn->ne0bridges != 0) {
7153 return False;
7154 }
7155 } else if (qgopt[GRCC_QGRAF_OPT_NOTADPOLE] < 0) {
7156 if (mgraph->mconn->ne0bridges == 0) {
7157 return False;
7158 }
7159 }
7160 }
7161 }
7162
7163 if (qgopt[GRCC_QGRAF_OPT_NOSIGMA] != 0) {
7164 bool ok = True;
7165 if (nExtern != 2) {
7166 if (nopis[2] > 1) {
7167 ok = False;
7168 }
7169 }
7170 for (int j = 0; j < econn->nopic; j++) {
7171 if (econn->opics[j].nlegs >= 2 &&
7172 econn->opics[j].nlegs == econn->opics[j].mom0lg) {
7173 ok = False;
7174 }
7175 }
7176
7177 // loop momenta
7178 for (int j = 0; j < econn->sedges - 1; j++) {
7179 ULong momj = econn->cedges[j].momset;
7180 if (momj == 0) {
7181 continue;
7182 }
7183 int extj = 0;
7184 if (econn->cedges[j].nodes[0] < nExtern) {
7185 extj = 1;
7186 } else if (econn->cedges[j].nodes[1] < nExtern) {
7187 extj = 1;
7188 }
7189 for (int k = j+1; k < econn->sedges; k++) {
7190 ULong momk = econn->cedges[k].momset;
7191 if (momk == 0) {
7192 continue;
7193 }
7194 int extk = 0;
7195 if (econn->cedges[k].nodes[0] < nExtern) {
7196 extk = 1;
7197 } else if (econn->cedges[k].nodes[1] < nExtern) {
7198 extk = 1;
7199 }
7200 if ( momj == momk) {
7201 if (nExtern == 2) {
7202 if (extj + extk != 2) {
7203 ok = False;
7204 }
7205 } else {
7206 ok = False;
7207 }
7208 }
7209 }
7210 }
7211 if (qgopt[GRCC_QGRAF_OPT_NOSIGMA] > 0) {
7212 if (! ok) {
7213 return False;
7214 }
7215 } else if (qgopt[GRCC_QGRAF_OPT_NOSIGMA] < 0) {
7216 if (ok) {
7217 return False;
7218 }
7219 }
7220 }
7221
7222 if (qgopt[GRCC_QGRAF_OPT_SIMPLE] > 0) {
7223 if (mgraph->selfloop || mgraph->multiedge) {
7224 return False;
7225 }
7226 } else if (qgopt[GRCC_QGRAF_OPT_SIMPLE] < 0) {
7227 if (!mgraph->selfloop && !mgraph->multiedge) {
7228 return False;
7229 }
7230 }
7231
7232 if (qgopt[GRCC_QGRAF_OPT_BIPART] > 0) {
7233 if (! mgraph->bipart) {
7234 return False;
7235 }
7236 } else if (qgopt[GRCC_QGRAF_OPT_BIPART] < 0) {
7237 if (mgraph->bipart) {
7238 return False;
7239 }
7240 }
7241 // GRCC_QGRAF_OPT_CYCLI
7242 if (qgopt[GRCC_QGRAF_OPT_CYCLI] != 0) {
7243 int nb = 0;
7244 for (int k = 0; k < econn->nblocks; k++) {
7245 if (econn->blocks[k].loop > 0) {
7246 nb++;
7247 }
7248 }
7249 if (qgopt[GRCC_QGRAF_OPT_CYCLI] > 0) {
7250 if (nb > 1) {
7251 return False;
7252 }
7253 } else if (qgopt[GRCC_QGRAF_OPT_CYCLI] < 0) {
7254 if (nb <= 1) {
7255 return False;
7256 }
7257 }
7258 }
7259
7260 return True;
7261}
7262
7263//--------------------------------------------------------------
7264Bool EGraph::optQGrafA(Options *opt)
7265{
7266#ifdef PRINT
7267 grcc_fprintf(GRCC_Stdout, "optQGrafA: %8ld\n", mId);
7268 econn->print();
7269#endif
7270 Bool retval = True;
7271 if (opt->qgopt[GRCC_QGRAF_OPT_FLOOP] != 0) {
7272 for (int fl=0; fl < nFlines; fl++) {
7273 if (flines[fl]->ftype == FL_Closed) {
7274 if (flines[fl]->nlist % 2 != 0) {
7275 retval = False;
7276 break;
7277 }
7278 }
7279 }
7280 // `notfloop_' is the dual of `floop_', so flip the decision:
7281 if (opt->qgopt[GRCC_QGRAF_OPT_FLOOP] == -1) {
7282 retval = (retval == True ? False : True);
7283 }
7284 }
7285 return retval;
7286}
7287
7288//--------------------------------------------------------------
7289Bool EGraph::isOptE(void)
7290{
7291 EGraph edupv = EGraph(sNodes, sEdges, sMaxdeg);
7292 EGraph *edup = &edupv;
7293 int grp[GRCC_MAXEDGES], ed2gr[GRCC_MAXEDGES];
7294 int g, ed, ngrp;
7295 Bool ok;
7296 int minopi2p;
7297
7298
7299 // if (opt->values[GRCC_OPT_No2PtL1PI] == 0
7300 // && opt->values[GRCC_OPT_NoAdj2PtV] == 0) {
7301 // return True;
7302 // }
7303
7304 for (ed = 0; ed < nEdges; ed++) {
7305 edges[ed]->cut = False;
7306 }
7307
7308 biconnE();
7309
7310 // QGraf options
7311 if (! optQGrafM(opt)) {
7312 return False;
7313 }
7314
7315 if (opt->values[GRCC_OPT_NoAdj2PtV] > 0) {
7316 if (nadj2ptv > 0) {
7317 return False;
7318 }
7319 } else if (opt->values[GRCC_OPT_NoAdj2PtV] < 0) {
7320 if (nadj2ptv < 1) {
7321 return False;
7322 }
7323 }
7324 if (opt->values[GRCC_OPT_No2PtL1PI] == 0) {
7325 return True;
7326 }
7327
7328 if (nExtern == 2 && nopicomp == 1) {
7329 minopi2p = 2;
7330 } else {
7331 minopi2p = 1;
7332 }
7333
7334 if (opi2plp > 0 && nopi2p >= minopi2p) {
7335 if (opt->values[GRCC_OPT_No2PtL1PI] > 0) {
7336 return False;
7337 } else if (opt->values[GRCC_OPT_No2PtL1PI] < 0) {
7338 return True;
7339 }
7340 }
7341
7342 edup->copy(this);
7343 ngrp = groupLMom(grp, ed2gr);
7344
7345 for (g = 0; g < ngrp; g++) {
7346 ok = True;
7347 if (grp[g] < 2) {
7348 continue;
7349 }
7350 for (ed = 0; ed < nEdges; ed++) {
7351 if (ed2gr[ed] == g) {
7352 if (edges[ed]->ext) {
7353 ok = False;
7354 break;
7355 }
7356 edup->edges[ed]->cut = True;
7357 } else {
7358 edup->edges[ed]->cut = False;
7359 }
7360 }
7361 if (ok) {
7362 edup->gSubId++;
7363 edup->biconnE();
7364
7365 if (edup->nExtern == 2 && edup->nopicomp == 1) {
7366 minopi2p = 2;
7367 } else {
7368 minopi2p = 1;
7369 }
7370
7371 if (edup->opi2plp > 0 && edup->nopi2p >= minopi2p) {
7372 if (opt->values[GRCC_OPT_No2PtL1PI] > 0) {
7373 return False;
7374 } else if (opt->values[GRCC_OPT_No2PtL1PI] < 0) {
7375 return True;
7376 }
7377 }
7378 }
7379 }
7380
7381 if (opt->values[GRCC_OPT_No2PtL1PI] > 0) {
7382 return True;
7383 } else if (opt->values[GRCC_OPT_No2PtL1PI] < 0) {
7384 return False;
7385 } else {
7386 erEnd("isOptE: illegal control");
7387 return False;
7388 }
7389}
7390
7391//--------------------------------------------------------------
7392int EGraph::findRoot(void)
7393{
7394 int root, vr, er, e, nd0, nd1;
7395
7396 root = -1;
7397 vr = -1;
7398 er = -1;
7399 for (e = 0; e < nEdges; e++) {
7400 if (edges[e]->cut || edges[e]->edtype == GRCC_ED_Deleted) {
7401 continue;
7402 }
7403 if (edges[e]->visited) {
7404 continue;
7405 }
7406 if (root < 0) {
7407 if (edges[e]->ext) {
7408 nd0 = edges[e]->nodes[0];
7409 nd1 = edges[e]->nodes[1];
7410 if (isExternal(nd0) && !isExternal(nd1)) {
7411 root = nd1;
7412 break;
7413 } else if (!isExternal(nd0) && isExternal(nd1)) {
7414 root = nd0;
7415 break;
7416 }
7417 }
7418 }
7419 if (er < 0) {
7420 er = edges[e]->nodes[0];
7421 }
7422 if (vr < 0) {
7423 vr = edges[e]->nodes[0];
7424 }
7425 }
7426 // if root >= 0 : vertex adjacent to an external node
7427 if (root < 0) {
7428 // if vr >= 0 : a vertex
7429 if (vr >= 0) {
7430 root = vr;
7431
7432 // no vertex, only external nodes;
7433 } else {
7434 root = er;
7435 }
7436 }
7437 return root;
7438}
7439
7440//---------------------------------------------------------------
7441int EGraph::connComp(void)
7442{
7443 // Count the number of connected component
7444 // If a connected component without free leg is not the whole graph then
7445 // return False, otherwise return True.
7446
7447 int j, ncc, nelem;
7448
7449 for (j = 0; j < nNodes; j++) {
7450 nodes[j]->visited = -1;
7451 }
7452 ncc = 0; // # connected components
7453 nelem = 0; // # visited nodes
7454 while (nelem < nNodes) {
7455 for (j = 0; j < nNodes; j++) {
7456 if (nodes[j]->visited < 0) {
7457 break;
7458 }
7459 }
7460 if (j >= nNodes) {
7461 break;
7462 }
7463 nelem += connVisit(j, ncc);
7464 ncc++;
7465 }
7466 if (nelem != nNodes) {
7467 erEnd("EGraph::connComp: illegal control");
7468 }
7469 return ncc;
7470}
7471
7472//---------------------------------------------------------------
7473int EGraph::connVisit(int nd, int ncc)
7474{
7475 // Visiting connected node used for 'connComp'
7476
7477 int e, en, nn, j, nelem;
7478
7479 nelem = 1;
7480 nodes[nd]->visited = ncc;
7481 for (e = 0; e < nodes[nd]->deg; e++) {
7482 en = V2Iedge(nodes[nd]->edges[e]);
7483 for (j = 0; j < 2; j++) {
7484 nn = edges[en]->nodes[j];
7485 if (nodes[nn]->visited < 0) {
7486 nelem += connVisit(nn, ncc);
7487 }
7488 }
7489 }
7490 return nelem;
7491}
7492
7493//--------------------------------------------------------------
7494void EGraph::biconnE(void)
7495{
7496 int e, ie, root;
7497 int extlst[GRCC_MAXEDGES], intlst[GRCC_MAXEDGES];
7498 int opiext, opiloop;
7499
7500 nadj2ptv = 0;
7501 for (e = 0; e < nEdges; e++) {
7502 if (nodes[edges[e]->nodes[0]]->deg == 2 &&
7503 nodes[edges[e]->nodes[1]]->deg == 2 &&
7504 edges[e]->nodes[0] != edges[e]->nodes[1]) {
7505 nadj2ptv++;
7506 }
7507 }
7508
7509 biinitE(); // initialization
7510 bconn = 0; // the number of connected components
7511
7512 opiext = 0;
7513 opiloop = 0;
7514
7515 for (e = 0; e < nEdges; e++) {
7516 // root of a spanning tree to be searched.
7517 root = findRoot();
7518 if (root < 0) {
7519 // no root : end of search
7520 break;
7521 }
7522
7523 // recursive search
7524 bisearchE(root, extlst, intlst, &opiext, &opiloop);
7525
7526 // opi2plp = Max(opi2plp, opiloop); // ???
7527
7528 // adjust the #external for the root
7529 if (isExternal(root)) {
7530 opiext++;
7531 }
7532
7533 // 2 point function
7534 if (opiext == 2) {
7535 opi2plp = Max(opi2plp, opiloop);
7536 nopi2p++;
7537 }
7538 for (ie = 0; ie < nEdges; ie++) {
7539 if (intlst[ie]) {
7540 edges[ie]->opicomp = nopicomp;
7541 }
7542 }
7543 nopicomp++;
7544
7545 bconn++; // the number of connected component
7546 }
7547
7548 // momentum conservation of external particles
7549 extMomConsv();
7550
7551#ifdef CHECK
7552 chkMomConsv();
7553#endif
7554 return;
7555}
7556
7557//--------------------------------------------------------------
7558void EGraph::biinitE(void)
7559{
7560 int n, j, e;
7561
7562 bicount = 0; // counter of visiting node
7563 loopm = 0; // # of independent loop momentum
7564
7565 nopicomp = 0;
7566 opi2plp = 0;
7567 nopi2p = 0;
7568
7569 for (n = 0; n < nNodes; n++) {
7570 bidef[n] = -1;
7571 bilow[n] = -1;
7572 nodes[n]->ndtype = GRCC_ND_Undef;
7573 for (j = 0; j < nLoops; j++) {
7574 nodes[n]->klow[j] = -1;
7575 }
7576 }
7577
7578 for (e = 0; e < nEdges; e++) {
7579 // edges[e]->cut is defined before
7580 edges[e]->visited = False;
7581 edges[e]->conid = -1; // connected component
7582 edges[e]->edtype = GRCC_ED_Undef;
7583 edges[e]->opicomp = -1;
7584 for (j = 0; j < nEdges; j++) {
7585 edges[e]->emom[j] = 0; // coefficients of ext. mom.
7586 }
7587 for (j = 0; j < nLoops; j++) {
7588 edges[e]->lmom[j] = 0; // coefficients of loop mom.
7589 }
7590 }
7591}
7592
7593//--------------------------------------------------------------
7594void EGraph::bisearchE(int nd, int *extlst, int *intlst, int *opiext, int *opiloop)
7595{
7596 // Search in the spanning tree below 'nd'.
7597 // Arguments:
7598 // nd : input : node to be visited
7599 // extlst : output : set of external lines in the current 1PI comp.
7600 // intlst : output : set of internal lines in the current 1PI comp.
7601 // opiext : output : no. external lines of the current 1PI component
7602 // opiloop : output : no. loops of the current 1PI component
7603 //
7604 // EGraph variables
7605 // bicount : counter of visiting node
7606 // loopm : no. of independent loop momentum
7607 // nopicomp : no. of OPI components
7608 // opi2plp : maximum number loops among 2-point looped OPI components
7609 // nopi2p : no. of 2-point OPI components
7610 // edges[ie]->opicomp : OPI component no. of the edge
7611 //
7612
7613 int k, e, ie, ed, td, dir, j;
7614 int opiext1, opiloop1;
7615 int extlst1[GRCC_MAXEDGES]; // set of external nodes below
7616 int intlst1[GRCC_MAXEDGES]; // set of vertices in the 1PI component
7617
7618 (*opiext) = 0;
7619 (*opiloop) = 0;
7620
7621 // visit node 'nd'
7622 bidef[nd] = bicount;
7623 bilow[nd] = bicount;
7624 for (k = 0; k < nLoops; k++) {
7625 nodes[nd]->klow[k] = bicount;
7626 }
7627 bicount++;
7628 for (j = 0; j < nEdges; j++) {
7629 extlst[j] = False;
7630 intlst[j] = False;
7631 }
7632
7633 // go to children : nd --> ed --> td
7634 for (e = 0; e < nodes[nd]->deg; e++) {
7635 ed = V2Iedge(nodes[nd]->edges[e]);
7636
7637 // check this edge is already visited
7638 if (edges[ed]->edtype == GRCC_ED_Deleted) {
7639 // permanently deleted edge
7640 continue;
7641 } else if (edges[ed]->visited) {
7642 // already visited (backword visit)
7643 continue;
7644 } else if (edges[ed]->cut) {
7645 // cut edge : treat as nd is an external
7646 (*opiext)++;
7647 nodes[nd]->setType(GRCC_ND_CPoint);
7648 continue;
7649 } else if (!isExternal(nd) && edges[ed]->ext) {
7650 // external
7651 edges[ed]->setType(GRCC_ED_Extern);
7652 edges[ed]->visited = True;
7653 edges[ed]->emom[ed] = 1;
7654 extlst[ed] = True;
7655 (*opiext)++;
7656 nodes[nd]->setType(GRCC_ND_CPoint);
7657 continue;
7658 }
7659
7660 // mark visited
7661 edges[ed]->visited = True;
7662
7663 // momentum is assigned on the backward move. (nd) 1 --> 0 (td)
7664 td = edges[ed]->nodes[0];
7665 dir = 1;
7666 if (td == nd) {
7667 td = edges[ed]->nodes[1];
7668 dir = -1;
7669 }
7670
7671 // biconnected component
7672 if (bidef[td] >= 0) {
7673 // a back edge is found. Already visited. Don't go further
7674 bilow[nd] = Min(bilow[nd], bilow[td]);
7675 edges[ed]->setType(GRCC_ED_Back);
7676 intlst[ed] = True;
7677 (*opiloop)++;
7678
7679 // create new loop momentum
7680 k = loopm++;
7681 nodes[nd]->klow[k] = Min(nodes[nd]->klow[k], nodes[td]->klow[k]);
7682 edges[ed]->setLMom(k, dir);
7683
7684 // self-loop
7685 if (td == nd) {
7686 nodes[nd]->setType(GRCC_ND_CPoint);
7687 }
7688
7689 } else {
7690 // not a back edge
7691 // go down further
7692 bisearchE(td, extlst1, intlst1, &opiext1, &opiloop1);
7693
7694 // the set of external particles
7695 for (j = 0; j < nEdges; j++) {
7696 extlst[j] = extlst[j] || extlst1[j];
7697 }
7698
7699 // loop momenta
7700 for (k = 0; k < nLoops; k++) {
7701 if (nodes[td]->klow[k] <= nodes[nd]->klow[k]) {
7702 // inside loop 'k'
7703 edges[ed]->setLMom(k, dir);
7704 }
7705 nodes[nd]->klow[k] = Min(nodes[nd]->klow[k], nodes[td]->klow[k]);
7706 }
7707
7708 // cut point ?
7709 if (bilow[td] >= bidef[nd]) {
7710 // a cut point is found
7711 if (nodes[nd]->ndtype == GRCC_ND_Undef) {
7712 nodes[nd]->setType(GRCC_ND_CPoint);
7713#ifdef CHECK
7714 } else if (nodes[nd]->ndtype != GRCC_ND_CPoint) {
7715 if (prlevel > 0) {
7716 grcc_fprintf(GRCC_Stderr, "bisearch: node %d is a cut point ",
7717 nd);
7718 grcc_fprintf(GRCC_Stderr, "(not undef %d)\n",
7719 nodes[nd]->ndtype);
7720 }
7721#endif
7722 }
7723 } // cut point
7724
7725 // bridge ?
7726 if (bilow[td] > bidef[nd]) {
7727 // a bridge is found
7728 if (edges[ed]->edtype == GRCC_ED_Undef) {
7729 edges[ed]->setType(GRCC_ED_Bridge);
7730 nodes[td]->setType(GRCC_ND_CPoint);
7731#ifdef CHECK
7732 } else if (edges[ed]->edtype != GRCC_ED_Bridge) {
7733 if (prlevel > 0) {
7734 grcc_fprintf(GRCC_Stderr, "bisearch: edges %d is a bridge ", ed);
7735 grcc_fprintf(GRCC_Stderr, "(not undef %d)\n", edges[ed]->edtype);
7736 }
7737#endif
7738 }
7739
7740 if (!edges[ed]->ext) {
7741 // internal bridge
7742 opiext1++; // from bridge
7743 for (ie = 0; ie < nEdges; ie++) {
7744 if (intlst1[ie]) {
7745 // OPI component No.
7746 edges[ie]->opicomp = nopicomp;
7747 intlst1[ie] = False;
7748 }
7749 }
7750 // 2pt OPI component
7751 if (opiext1 == 2) {
7752 opi2plp = Max(opi2plp, opiloop1);
7753
7754 // the number of 2pt looped OPI components
7755 nopi2p++;
7756 }
7757 // the number of OPI components
7758 nopicomp++;
7759 }
7760 opiext1 = 1; // from bridge
7761 opiloop1 = 0;
7762
7763 } else {
7764 // not a bridge
7765
7766 bilow[nd] = Min(bilow[nd], bilow[td]);
7767
7768 if (edges[ed]->edtype == GRCC_ED_Undef) {
7769 edges[ed]->setType(GRCC_ED_Inloop);
7770#ifdef CHECK
7771 } else if (edges[ed]->edtype != GRCC_ED_Inloop) {
7772 if (prlevel > 0) {
7773 grcc_fprintf(GRCC_Stderr, "bisearch: ");
7774 grcc_fprintf(GRCC_Stderr, "edges %d is not undef (%d)\n",
7775 ed, edges[ed]->edtype);
7776 }
7777#endif
7778 }
7779 intlst1[ed] = True;
7780 }
7781
7782 // merge to the current variables
7783 for (ie = 0; ie < nEdges; ie++) {
7784 intlst[ie] = intlst[ie] || intlst1[ie];
7785 }
7786 (*opiext) += opiext1;
7787 (*opiloop) += opiloop1;
7788
7789 // linear combination of external momenta
7790 edges[ed]->setEMom(nEdges, extlst1, dir);
7791
7792 } // end of a child
7793 } // for (ed)
7794
7795 return;
7796}
7797
7798//--------------------------------------------------------------
7799void EGraph::extMomConsv(void)
7800{
7801 int e, ex, lex, rs;
7802
7803 lex = -1;
7804 for (e = 0; e < nEdges; e++) {
7805 if (edges[e]->ext) {
7806 lex = e;
7807 extMom[e] = edges[e]->emom[e];
7808 } else {
7809 extMom[e] = 0;
7810 }
7811 }
7812 // eliminate momentum of the last external particle
7813 if (lex < 0) {
7814 return;
7815 }
7816 for (e = 0; e < nEdges; e++) {
7817 rs = edges[e]->emom[lex];
7818 if (rs != 0) {
7819 for (ex = 0; ex < nEdges; ex++) {
7820 edges[e]->emom[ex] -= rs*extMom[ex];
7821 }
7822 }
7823 }
7824}
7825
7826//--------------------------------------------------------------
7827void EGraph::chkMomConsv(void)
7828{
7829 // check momentum conservation
7830
7831 int esum[GRCC_MAXEDGES];
7832 int lsum[GRCC_MAXNODES];
7833 Bool ok, okn;
7834 int n, ex, lk, ej, e, dir;
7835
7836 if (bicount < 1) {
7837 return;
7838 }
7839 ok = True;
7840 for (n = 0; n < nNodes; n++) {
7841 if (isExternal(n)) {
7842 continue;
7843 }
7844 for (ex = 0; ex < nEdges; ex++) {
7845 esum[ex] = 0;
7846 }
7847 for (lk = 0; lk < nLoops; lk++) {
7848 lsum[lk] = 0;
7849 }
7850 for (ej = 0; ej < nodes[n]->deg; ej++) {
7851 e = V2Iedge(nodes[n]->edges[ej]);
7852 if (edges[e]->nodes[0] == edges[e]->nodes[0]) {
7853 continue;
7854 }
7855 dir = dirEdge(n, ej);
7856 for (ex = 0; ex < nEdges; ex++) {
7857 if (edges[e]->ext) {
7858 esum[ex] += dir*edges[e]->emom[ex];
7859 }
7860 }
7861 for (lk = 0; lk < nLoops; lk++) {
7862 lsum[lk] += dir*edges[e]->lmom[lk];
7863 }
7864 }
7865
7866 okn = True;
7867 for (ex = 0; ex < nEdges; ex++) {
7868 if (esum[ex] != 0) {
7869 okn = False;
7870 grcc_fprintf(GRCC_Stderr, "chkMomConsv:n=%d, esum[%d]=%d\n",
7871 n, ex, esum[ex]);
7872 }
7873 }
7874
7875 for (lk = 0; lk < nLoops; lk++) {
7876 if (lsum[lk] != 0) {
7877 okn = False;
7878 grcc_fprintf(GRCC_Stderr, "chkMomConsv:n=%d, lsum[%d]=%d\n",
7879 n, lk, lsum[lk]);
7880
7881 }
7882 }
7883
7884 if (!okn) {
7885 ok = False;
7886 grcc_fprintf(GRCC_Stderr, "*** Violation of momentum conservation ");
7887 grcc_fprintf(GRCC_Stderr, "at node =%d\n",n);
7888 }
7889 }
7890
7891 if (!ok) {
7892 print();
7893 erEnd("inconsistent momentum");
7894 }
7895}
7896
7897//--------------------------------------------------------------
7898int EGraph::legParticle(int ed, int el)
7899{
7900 // outgoing particle from (edge, leg) = (ed, el)
7901
7902 return model->normalParticle((2*el-1)*edges[ed]->ptcl);
7903}
7904
7905//--------------------------------------------------------------
7906int EGraph::isFermion(int ed)
7907{
7908 // return if particle on the edge ed follows Fermi statistics or not.
7909
7910 int ptcl, ptype;
7911
7912 ptcl = edges[ed]->ptcl;
7913 ptype = model->particles[Abs(ptcl)]->ptype;
7914
7915 return (ptype == GRCC_PT_Dirac || ptype == GRCC_PT_Majorana
7916 || ptype == GRCC_PT_Ghost);
7917}
7918
7919//--------------------------------------------------------------
7920int EGraph::fltrace(int fk, int nd0, int *fl)
7921{
7922 // fk : kind of fermion
7923 // = (GRCC_PT_Dirac, GRCC_PT_Majorana or GRCC_PT_Ghost)
7924 // nd0 : the last node visited
7925 // fl : list of signed edge on the fermion line.
7926 // fl[j] :
7927 // (V2Iedge(fl[j]), V2Ileg(fl[j])) is the next node
7928 // fl[0] should be already defined
7929
7930 int nfl, k, i, nd, nl, e, ed, el, fgcnt, fkind, lk;
7931
7932 nfl = 1;
7933 // maximal possible length of a fline is nEdges
7934 for (k = 0; k < nEdges; k++) {
7935 if (k >= nfl) {
7936 grcc_fprintf(GRCC_Stdout, "*** fltrace:illegal contorl: k=%d, nEdges=%d\n", k, nEdges);
7937 break;
7938 }
7939
7940 // get next node : nd0 ---- nd (nl)
7941 e = fl[k];
7942 ed = V2Iedge(e);
7943 el = V2Ileg(e);
7944#ifdef CHECK
7945 if (ed > nEdges) {
7946 grcc_fprintf(GRCC_Stderr, "*** fltrace: ed=%d > nEdges=%d, fl=",
7947 ed, nEdges);
7948 prIntArray(nNodes, fl, "\n");
7949 erEnd("fltrace: illegal fl");
7950 }
7951#endif
7952 nd = edges[ed]->nodes[el];
7953 nl = edges[ed]->nlegs[el];
7954
7955 // end of the fline
7956 if (isExternal(nd) || nd == nd0) {
7957 fgcnt = 1;
7958 break;
7959 }
7960
7961 // find leg of nd for going next
7962 fgcnt = 0;
7963 ed = 0;
7964 lk = 0;
7965 for (i = 0; i < nodes[nd]->deg; i++) {
7966 e = nodes[nd]->edges[i];
7967 ed = V2Iedge(e);
7968 fkind = model->particles[Abs(edges[ed]->ptcl)]->ptype;
7969 // lk = 1 : (# of fkind particle) is even
7970 // lk = -1 : (# of fkind particle) is odd
7971 if (fkind == fk) {
7972 if (lk == 1) {
7973 lk = -1;
7974 } else {
7975 lk = 1;
7976 }
7977 } else {
7978 lk = 0;
7979 }
7980 if (!edges[ed]->visited) {
7981 if (!isFermion(ed)) {
7982 edges[ed]->visited = True;
7983 } else {
7984 if (fkind == fk) {
7985 // i should be the neighbor of nl
7986 // (nl, i) or (i, nl) should be a pair of fkind
7987 // (nl, i) : lk = -1
7988 // (i, nl) : lk = 1
7989 if ((lk == 1 && nl == i+1) || (lk == -1 && nl == i-1)) {
7990 edges[ed]->visited = True;
7991 fgcnt++;
7992 if (fgcnt == 1) {
7993 // -e = (signed edge points the next node)
7994 fl[nfl++] = - e;
7995 break;
7996 }
7997 }
7998 }
7999 }
8000 } // not visited
8001 } // end of for k
8002 if (fgcnt == 0) {
8003 grcc_fprintf(GRCC_Stdout, "*** fline: Fermion number is not conserved\n");
8004 grcc_fprintf(GRCC_Stdout, " nd=%d, e=%d, ed=%d, fgcnt=%d\n",
8005 nd, e, ed, fgcnt);
8006 // erEnd("fline: Fermion number is not conserved");
8007 } else if (fgcnt > 1) {
8008 grcc_fprintf(GRCC_Stdout, "+++ fline: more than two fermions: check fsign\n");
8009 grcc_fprintf(GRCC_Stdout, " nd=%d, e=%d, ed=%d, fgcnt=%d\n",
8010 nd, e, ed, fgcnt);
8011 }
8012 }
8013 if (k >= nEdges || k >= nfl) {
8014 grcc_fprintf(GRCC_Stdout, "*** fline: illegal control\n");
8015 grcc_fprintf(GRCC_Stdout, " nEdges=%d, nfl=%d, k=%d, ", nEdges, nfl, k);
8016 prIntArray(nfl, fl, "\n");
8017 erEnd("fline: illegal control");
8018 }
8019 return nfl;
8020}
8021
8022//--------------------------------------------------------------
8023void EGraph::getFLines(void)
8024{
8025 int fl[GRCC_MAXNODES];
8026 int nextn, exto[GRCC_MAXNODES];
8027 int e, ed, nd, floop, nswap, nfl, fkind, el, ptcl;
8028
8029 nFlines = 0;
8030 for (ed = 0; ed < nEdges; ed++) {
8031 edges[ed]->visited = False;
8032 }
8033
8034 nextn = 0;
8035 for (ed = 0; ed < nEdges; ed++) {
8036 if (edges[ed]->visited) {
8037 continue;
8038 }
8039 if (!edges[ed]->ext) {
8040 continue;
8041 }
8042 el = 0;
8043 nd = edges[ed]->nodes[el];
8044 if (!isExternal(nd)) {
8045 el = 1;
8046 nd = edges[ed]->nodes[el];
8047 if (!isExternal(nd)) {
8048 erEnd("*** illegal control");
8049 }
8050 }
8051 if (!isFermion(ed)) {
8052 continue;
8053 }
8054 ptcl = legParticle(ed, 1-el);
8055 if (ptcl < 0) {
8056 continue;
8057 }
8058
8059 // el ed el1
8060 // x----<----x e = (signed edge of (ed, el1))
8061 // nd ptcl(>= 0)
8062 // external
8063
8064 fl[0] = - I2Vedge(ed, el);
8065 nfl = 1;
8066 fkind = model->particles[Abs(edges[ed]->ptcl)]->ptype;
8067 edges[ed]->visited = True;
8068
8069 nfl = fltrace(fkind, nd, fl);
8070 addFLine(FL_Open, fkind, nfl, fl);
8071 e = fl[nfl-1];
8072 exto[nextn++] = edges[V2Iedge(e)]->nodes[V2Ileg(e)];
8073 }
8074
8075 // closed Fermion line
8076 floop = 0;
8077 for (ed = 0; ed < nEdges; ed++) {
8078 if (edges[ed]->visited) {
8079 continue;
8080 }
8081 if (!isFermion(ed)) {
8082 continue;
8083 }
8084 el = 0;
8085 ptcl = legParticle(ed, 1-el);
8086 if (ptcl < 0) {
8087 el = 1;
8088 }
8089 nd = edges[ed]->nodes[el];
8090
8091 // el ed el1
8092 // x----<----x e = (signed edge of (ed, el1))
8093 // nd ptcl
8094
8095 fl[0] = - I2Vedge(ed, el);
8096 nfl = 1;
8097 edges[ed]->visited = True;
8098
8099 fkind = model->particles[Abs(edges[ed]->ptcl)]->ptype;
8100 nfl = fltrace(fkind, nd, fl);
8101 addFLine(FL_Closed, fkind, nfl, fl);
8102 floop++;
8103 }
8104 if (nextn > 0) {
8105 nswap = sortb(nextn, exto);
8106 } else {
8107 nswap = 0;
8108 }
8109 if ((floop+nswap) % 2 == 0) {
8110 fsign = 1;
8111 } else {
8112 fsign = -1;
8113 }
8114}
8115
8116//--------------------------------------------------------------
8117void EGraph::addFLine(const FLType ft, int fk, int nfl, int *fl)
8118{
8119 int j;
8120
8121 if (nFlines >= GRCC_MAXFLINES) {
8122 erEnd("too many Fermion lines (GRCC_MAXEDGES)");
8123 }
8124 if (flines[nFlines] == NULL) {
8125 flines[nFlines] = new EFLine();
8126 }
8127 flines[nFlines]->ftype = ft;
8128 flines[nFlines]->fkind = fk;
8129 flines[nFlines]->nlist = nfl;
8130 for (j = 0; j < nfl; j++) {
8131 flines[nFlines]->elist[j] = fl[j];
8132 }
8133 nFlines++;
8134}
8135
8136
8137//**************************************************************
8138// assign.cc
8139//==============================================================
8140// Assign particles to the edges and interactions to nodes.
8141// Completed graph data is saved in the form of EGraph.
8142
8143// method : selection of assignable node
8144
8145//===============================================================
8146// class NCand
8147NCand::NCand(const NCandSt sta, const int dega, const int nilst, int *ilst)
8148{
8149 // candidate list of interactions attached to a vertex.
8150
8151 int j;
8152
8153 deg = dega;
8154 st = sta;
8155 nilist = nilst;
8156 for (j = 0; j < nilist; j++) {
8157 ilist[j] = ilst[j];
8158 }
8159
8160#ifdef CHECK
8161 if (st == AS_Assigned) {
8162 if (nilist != 1) {
8163 erEnd("illegal assignment");
8164 }
8165 } else if (st == AS_AssExt) {
8166 if (nilist != 1) {
8167 erEnd("illegal assignment");
8168 }
8169 }
8170#endif
8171}
8172
8173//---------------------------------------------------------------
8174NCand::~NCand(void)
8175{
8176}
8177
8178//---------------------------------------------------------------
8179void NCand::prNCand(const char* msg)
8180{
8181 grcc_fprintf(GRCC_Stdout, "%d %d ", st, deg);
8182 prIntArray(nilist, ilist, msg);
8183}
8184
8185//===============================================================
8186// class ECand
8187ECand::ECand(int dt, int nplst, int *plst)
8188{
8189 int j;
8190
8191 det = dt;
8192 nplist = nplst;
8193 for (j = 0; j < nplist; j++) {
8194 plist[j] = plst[j];
8195 }
8196
8197 if (det && nplist != 1) {
8198 if (prlevel > 0) {
8199 grcc_fprintf(GRCC_Stderr, "*** ECand : len(plist) != 1 : det=%d ", det);
8200 prIntArrayErr(nplist, plist, "\n");
8201 }
8202 erEnd("ECand : len(plist) != 1");
8203 }
8204}
8205
8206//---------------------------------------------------------------
8207ECand::~ECand(void)
8208{
8209}
8210
8211//---------------------------------------------------------------
8212void ECand::prECand(const char *msg)
8213{
8214 prIntArray(nplist, plist, "");
8215 grcc_fprintf(GRCC_Stdout, " (det=%d)%s", det, msg);
8216}
8217
8218//===============================================================
8219// class ANode
8220ANode::ANode(int dg)
8221{
8222 int j;
8223
8224 deg = dg;
8225 nlegs = 0;
8226 anodes = new int[deg];
8227 aedges = new int[deg];
8228 aelegs = new int[deg];
8229 cand = NULL;
8230 for (j = 0; j < deg; j++) {
8231 anodes[j] = -1;
8232 aedges[j] = -1;
8233 aelegs[j] = -1;
8234 }
8235}
8236
8237//---------------------------------------------------------------
8238ANode::~ANode(void)
8239{
8240 if (cand != NULL) {
8241 delete cand;
8242 cand = NULL;
8243 }
8244 if (aelegs != NULL) {
8245 delete[] aelegs;
8246 delete[] aedges;
8247 delete[] anodes;
8248 aelegs = NULL;
8249 aedges = NULL;
8250 anodes = NULL;
8251 }
8252}
8253
8254//---------------------------------------------------------------
8255int ANode::newleg(void)
8256{
8257 // add a slot for a leg
8258
8259 int lg = nlegs;
8260
8261 nlegs++;
8262#ifdef CHECK
8263 if (nlegs > deg) {
8264 grcc_fprintf(GRCC_Stderr, "*** ANode::newleg : nlegs = %d > deg = %d\n",
8265 nlegs, deg);
8266 erEnd("ANode::newleg : nlegs > deg");
8267 }
8268#endif
8269
8270 return lg;
8271}
8272
8273//===============================================================
8274// class AEdge
8275AEdge::AEdge(int n0, int l0, int n1, int l1)
8276{
8277 nodes[0] = n0; // node of 0 side of the edge
8278 nodes[1] = n1; // node of 1 side of the edge
8279 nlegs[0] = l0; // leg ot the node of 0 side of the edge
8280 nlegs[1] = l1; // leg ot the node of 1 side of the edge
8281 ptcl = GRCC_PT_Undef; // particle defined in the model
8282 cand = NULL; // candidate
8283}
8284
8285//---------------------------------------------------------------
8286AEdge::~AEdge(void)
8287{
8288 if (cand != NULL) {
8289 delete cand;
8290 }
8291}
8292
8293//===============================================================
8294// class Assign
8295Assign::Assign(SProcess *sprc, MGraph *mgr, PNodeClass *pnc)
8296{
8297 Bool ok;
8298 int j;
8299
8300 if (sprc == NULL) {
8301 erEnd("Assign: sproc == NULL");
8302 }
8303
8304 // pointers to related objects
8305 sproc = sprc;
8306 model = sproc->model;
8307 opt = sproc->opt;
8308 mgraph = mgr;
8309 pnclass = pnc;
8310
8311 egraph = mgraph->egraph;
8312 if (egraph == NULL) {
8313 erEnd("Assign: egraph == NULL");
8314 }
8315
8316 astack = sproc->astack;
8317 if (astack == NULL) {
8318 erEnd("Assign: astack == NULL");
8319 }
8320
8321 nNodes = mgraph->nNodes;
8322 nEdges = mgraph->nEdges;
8323 nExtern = sproc->nExtern;
8324 nETotal = 0; // total number of edges
8325
8326 // counters of graphs
8327 nAGraphs = 0;
8328 wAGraphs = Fraction(0,1);
8329 nAOPI = 0;
8330 wAOPI = Fraction(0,1);
8331
8332 nodes = new ANode*[nNodes];
8333 edges = new AEdge*[nEdges];
8334
8335 for (j = 0; j < nNodes; j++) {
8336 nodes[j] = NULL;
8337 }
8338 for (j = 0; j < nEdges; j++) {
8339 edges[j] = NULL;
8340 }
8341 for (j = 0; j < model->ncouple; j++) {
8342 cplleft[j] = sproc->clist[j];
8343 }
8344
8345 // initialize astack
8346 astack->setAGraph(this);
8347 astack->checkPoint(checkpoint0);
8348
8349 // import from mgraph
8350 ok = fromMGraph();
8351#ifdef CHECK
8352 checkAG("Assign::Assign");
8353#endif
8354
8355 if (ok) {
8356 // start assignment
8357 assignAllVertices();
8358 } else {
8359 // cannot assign
8360 }
8361
8362 // restore from the stack
8363#ifdef CHECK
8364 astack->restoreMsg(checkpoint0, "Assign");
8365#else
8366 astack->restore(checkpoint0);
8367#endif
8368}
8369
8370//===============================================================
8371Assign::~Assign(void)
8372{
8373 int j;
8374
8375 for (j = 0; j < nEdges; j++) {
8376 delete edges[j];
8377 edges[j] = NULL;
8378 }
8379 delete[] edges;
8380 edges = NULL;
8381
8382 for (j = 0; j < nNodes; j++) {
8383 delete nodes[j];
8384 nodes[j] = NULL;
8385 }
8386 delete[] nodes;
8387 nodes = NULL;
8388}
8389
8390//---------------------------------------------------------------
8391void Assign::prCand(const char *msg)
8392{
8393 // Print candidate table
8394 int n, e, ne;
8395 AEdge *ed;
8396
8397 grcc_fprintf(GRCC_Stdout, "\n");
8398 grcc_fprintf(GRCC_Stdout, "+++ Candidate list: %s\n", msg);
8399 grcc_fprintf(GRCC_Stdout, " Nodes %d\n", nNodes);
8400 for (n = 0; n < nNodes; n++) {
8401 grcc_fprintf(GRCC_Stdout, "%d: edges=", n);
8402 prIntArray(nodes[n]->deg, nodes[n]->aedges, ": cand=");
8403 if (nodes[n]->cand == NULL) {
8404 grcc_fprintf(GRCC_Stdout, "NULL\n");
8405 } else {
8406 nodes[n]->cand->prNCand("\n");
8407 }
8408 }
8409 ne = Min(nEdges, nETotal);
8410 grcc_fprintf(GRCC_Stdout, " Edges %d\n", ne);
8411 for (e = 0; e < ne; e++) {
8412 ed = edges[e];
8413 if (ed == NULL) {
8414 grcc_fprintf(GRCC_Stdout, "NULL_Edge\n");
8415 } else {
8416 grcc_fprintf(GRCC_Stdout, "%d: %d->%d: cand=", e, ed->nodes[0], ed->nodes[1]);
8417 if (edges[e]->cand == NULL) {
8418 grcc_fprintf(GRCC_Stdout, "NULL\n");
8419 } else {
8420 edges[e]->cand->prECand("\n");
8421 }
8422 }
8423 }
8424}
8425
8426//===============================================================
8427void Assign::checkAG(const char *msg)
8428{
8429 int n, lg;
8430 Bool ok = True;
8431
8432 for (n = 0; n < nNodes; n++) {
8433 for (lg = 0; lg < nodes[n]->deg; lg++) {
8434 if (nodes[n]->aedges[lg] < 0) {
8435 grcc_fprintf(GRCC_Stdout, "*** checkAG:%s: n=%d, lg=%d, aedges=%d\n",
8436 msg, n, lg, nodes[n]->aedges[lg]);
8437 ok = False;
8438 }
8439 }
8440 }
8441 if (!ok) {
8442 prCand("checkAG");
8443 erEnd("checkAG: failed");
8444 }
8445}
8446
8447//===============================================================
8448// control of the process of particle/interaction assignment
8449
8450//---------------------------------------------------------------
8451Bool Assign::assignAllVertices(void)
8452{
8453 // Entry point of the assignment procedure
8454 Bool ok;
8455
8456#ifdef CHECK
8457 checkCand("assignAllVertices:1");
8458#endif
8459
8460 // start main part
8461#ifdef SIMPSEL
8462 ok = selectVertexSimp(-1);
8463#else
8464 ok = selectVertex();
8465#endif
8466
8467#ifdef CHECK
8468 checkCand("assignAllVertices:2");
8469#endif
8470
8471 return ok;
8472}
8473
8474//---------------------------------------------------------------
8475Bool Assign::selectVertexSimp(int lastv)
8476{
8477 // Select a vertex for assignment of particles to legs
8478 //
8479 // Argument
8480 // lastv : previously assigned vertex; Nothing when lastv<0.
8481
8482 Bool ok;
8483 int v;
8484
8485#ifdef CHECK
8486 checkCand("selectVertexSimp");
8487#endif
8488
8489 // find a vertex to which interaction is assigned
8490 v = selUnAssVertexSimp(lastv);
8491
8492 // no more vertex
8493 if (v < 0) {
8494
8495 ok = allAssigned();
8496 if (ok) {
8497 if (!egraph->optQGrafA(opt)) {
8498 return False;
8499 }
8500 // egraph->biconnE(); // necessary ???
8501 opt->newAGraph(egraph);
8502 }
8503
8504 return ok;
8505 }
8506
8507 // select a leg and assign a particle to it
8508 ok = selectLeg(v, -1);
8509
8510 return ok;
8511}
8512
8513//---------------------------------------------------------------
8514Bool Assign::selectVertex(void)
8515{
8516 // Select a vertex for assignment of particles to legs
8517 //
8518 // Argument
8519 // lastv : previously assigned vertex; Nothing when lastv<0.
8520
8521 Bool ok;
8522 int v;
8523
8524#ifdef CHECK
8525 checkCand("selectVertex");
8526#endif
8527
8528 // find a vertex to which interaction is assigned
8529 v = selUnAssVertex();
8530
8531 // no more vertex
8532 if (v < 0) {
8533
8534 ok = allAssigned();
8535 if (ok) {
8536 if (!egraph->optQGrafA(opt)) {
8537 return False;
8538 }
8539 egraph->biconnE();
8540 opt->newAGraph(egraph);
8541 }
8542
8543 return ok;
8544 }
8545
8546 // select a leg and assign a particle to it
8547 ok = selectLeg(v, -1);
8548
8549 return ok;
8550}
8551
8552//---------------------------------------------------------------
8553Bool Assign::selectLeg(int v, int lastlg)
8554{
8555 // Select a leg of vertex 'v' for assignment of particle,
8556 // where the last assigned leg was 'lastlg'.
8557
8558 int pt, ln, j;
8559 Bool ok;
8560 CheckPt sav, sav0;
8561 int nplist, plist[GRCC_MAXMPARTICLES2];
8562
8563#ifdef CHECK
8564 checkNode(v, "selectLeg:0");
8565 checkCand("selectLeg");
8566#endif
8567
8568 // find a leg to be assigned
8569 ln = selUnAssLeg(v, lastlg);
8570
8571 // no more assignable leg for the current node
8572 if (ln < 0) {
8573 // move to next vertex
8574 ok = assignVertex(v);
8575
8576 return ok;
8577 }
8578
8579 // make the list of possible particles, incoming to the vertex
8580 astack->checkPoint(sav0);
8581 nplist = candPart(v, ln, plist, GRCC_MAXMPARTICLES2);
8582
8583 // no candidate
8584 if (nplist < 1) {
8585 return False;
8586 }
8587
8588 // assign each of possible particle to the leg 'lg'.
8589 astack->checkPoint(sav);
8590 for (j = 0; j < nplist; j++) {
8591 pt = plist[j];
8592
8593 // try to assign 'pt' to (v, ln)
8594 if(assignPLeg(v, ln, pt)) {
8595 // move to next leg
8596 selectLeg(v, ln);
8597 }
8598
8599#ifdef CHECK
8600 astack->restoreMsg(sav, "selectLeg2");
8601#else
8602 astack->restore(sav);
8603#endif
8604 }
8605
8606#ifdef CHECK
8607 astack->restoreMsg(sav0, "selectLeg2");
8608#else
8609 astack->restore(sav0);
8610#endif
8611 return True;
8612}
8613
8614//---------------------------------------------------------------
8615void Assign::saveCouple(int *sav)
8616{
8617 int j;
8618
8619 if (model->ncouple > 1) {
8620 for (j = 0; j < model->ncouple; j++) {
8621 sav[j] = cplleft[j];
8622 }
8623 }
8624}
8625
8626//---------------------------------------------------------------
8627void Assign::restoreCouple(int *sav)
8628{
8629 int j;
8630
8631 if (model->ncouple > 1) {
8632 for (j = 0; j < model->ncouple; j++) {
8633 cplleft[j] = sav[j];
8634 }
8635 }
8636}
8637
8638//---------------------------------------------------------------
8639Bool Assign::subCouple(int *cpl)
8640{
8641 int j;
8642
8643 if (model->ncouple > 1) {
8644 for (j = 0; j < model->ncouple; j++) {
8645 cplleft[j] -= cpl[j];
8646 if (cplleft[j] < 0) {
8647 return False;
8648 }
8649 }
8650 }
8651 return True;
8652}
8653
8654//---------------------------------------------------------------
8655Bool Assign::assignVertex(int v)
8656{
8657 // Assign interactions to vertex 'v'
8658
8659 Bool done, ok;
8660 CheckPt sav, sav1;
8661 NCand *nc;
8662 int ia, n, j, cl;
8663 NCandSt vst;
8664 Bool ok1;
8665 int savc0[GRCC_MAXNCPLG], savc1[GRCC_MAXNCPLG];
8666
8667#ifdef CHECK
8668 checkCand("assignVertex");
8669#endif
8670
8671 // save the configuration
8672 astack->checkPoint(sav);
8673 saveCouple(savc0);
8674
8675 // assign to all vertices with only one candidate
8676 done = False;
8677 for (n = 0; n < nNodes; n++) {
8678
8679 // check if vertex
8680 cl = pnclass->nd2cl[n];
8681 if (!isATExternal(pnclass->type[cl])) {
8682
8683 nc = nodes[n]->cand;
8684 if (nc->st == AS_UnAssLegs && nc->nilist == 1) {
8685
8686 // bind interaction to the vertex
8687 ia = nc->ilist[0];
8688 vst = assignIVertex(n, ia);
8689 if (vst == AS_Impossible) {
8690 // discard the current configuration
8691#ifdef CHECK
8692 astack->restoreMsg(sav, "assignVertex");
8693#else
8694 astack->restore(sav);
8695#endif
8696 restoreCouple(savc0);
8697 return False;
8698
8699 } else if (vst == AS_Assigned) {
8700 if (!subCouple(model->interacts[ia]->clist)) {
8701#ifdef CHECK
8702 astack->restoreMsg(sav, "assignVertex");
8703#else
8704 astack->restore(sav);
8705#endif
8706 restoreCouple(savc0);
8707 return False;
8708 }
8709 }
8710 if (n == v) {
8711 done = (vst == AS_Assigned);
8712 }
8713 }
8714 }
8715 }
8716
8717 // uniquely determined
8718 ok = True;
8719 if (done) {
8720 // move to the next vertex
8721#ifdef SIMPSEL
8722 ok = selectVertexSimp(v);
8723#else
8724 ok = selectVertex();
8725#endif
8726
8727#ifdef CHECK
8728 astack->restoreMsg(sav, "assignVertex");
8729#else
8730 astack->restore(sav);
8731#endif
8732 restoreCouple(savc0);
8733
8734 return ok;
8735 }
8736
8737 // there are still several possibilities.
8738
8739 astack->checkPoint(sav1);
8740 saveCouple(savc1);
8741 for (j = 0; j < nodes[v]->cand->nilist; j++) {
8742 ia = nodes[v]->cand->ilist[j];
8743
8744 // bind interaction to the vertex
8745 ok1 = True;
8746 vst = assignIVertex(v, ia);
8747 if (vst == AS_Assigned) {
8748 ok1 = subCouple(model->interacts[ia]->clist);
8749 }
8750 if (ok1 && (vst == AS_Assigned || vst == AS_Assigned0)) {
8751 // move to the next vertex
8752#ifdef SIMPSEL
8753 ok = selectVertexSimp(v);
8754#else
8755 ok = selectVertex();
8756#endif
8757 }
8758
8759#ifdef CHECK
8760 astack->restoreMsg(sav1, "assignVertex");
8761#else
8762 astack->restore(sav1);
8763#endif
8764 restoreCouple(savc1);
8765 }
8766
8767#ifdef CHECK
8768 astack->restoreMsg(sav, "assignVertex");
8769#else
8770 astack->restore(sav);
8771#endif
8772 restoreCouple(savc0);
8773
8774 return ok;
8775}
8776
8777//---------------------------------------------------------------
8778Bool Assign::allAssigned(void)
8779{
8780 // Assignment of particles and interactions is finished.
8781 // Check isomorphism etc. and count symmetry factor
8782 // The sign from Fermi statistics is calculated inf fillEGraph
8783
8784 BigInt nsym, esym, nsym1;
8785 MNodeClass *cl;
8786 Bool ok = True;
8787#ifdef OPTEXTONLY
8788#else
8789 Bool ext;
8790 int e, p;
8791#endif
8792
8793#ifdef CHECK
8794 checkCand("allAssigned");
8795#endif
8796
8797 // check order of coupling constants
8798#ifdef CHECK
8799 if (!checkOrderCpl()) {
8800 erEnd("allAssigned: checkOrderCpl = False");
8801 }
8802#endif
8803
8804 // check duplication by violating ordering condition
8805 if (!isOrdLegs()) {
8806 return False;
8807 }
8808
8809 // classification of nodes
8810 cl = mgraph->curcl;
8811
8812 // check isomorphism and calculate sfactor
8813 nsym = 0;
8814 esym = 0;
8815
8816 ok = isIsomorphic(cl, &nsym, &esym, &nsym1);
8817 if (!ok || nsym < 1 || esym < 1) {
8818 return False;
8819 }
8820
8821 //--------------------------
8822 // Now we got a new agraph.
8823
8824 // Update counters
8825 nAGraphs++;
8826 wAGraphs.add(1,nsym*esym);
8827 if (mgraph->opi) {
8828 nAOPI++;
8829 wAOPI.add(1,nsym*esym);
8830 }
8831
8832#ifdef CHECK
8833 checkAG("allAssigned");
8834#endif
8835 // fill information to resulting Egraph
8836 fillEGraph(nAGraphs, nsym, esym, nsym1);
8837
8838#ifdef OPTEXTONLY
8839#else
8840 // check extonly particles
8841 for (e = 0; e < nEdges; e++) {
8842 p = Abs(egraph->edges[e]->ptcl);
8843 ext = egraph->edges[e]->ext;
8844 if (!ext) {
8845 if (model->particles[p]->extonly) {
8846 return False;
8847 }
8848 }
8849 }
8850#endif
8851
8852 return True;
8853}
8854
8855//===============================================================
8856// Interface to MGraph and EGraph
8857//---------------------------------------------------------------
8858Bool Assign::fromMGraph(void)
8859{
8860 // Import from MGraph
8861
8862 int npall, *pall;
8863 int np[1];
8864 Bool ok;
8865 int j, k, n, nn, n1, deg, nc, ptcl, cl, typ, mcl, cl1, typ1;
8866 int lcn, ia;
8867 int nilist, ilist[GRCC_MAXMINTERACT];
8868 NCandSt st;
8869
8870 // create ANodes
8871 for (j = 0; j < nNodes; j++) {
8872 nodes[j] = new ANode(mgraph->nodes[j]->deg);
8873 }
8874
8875 // initialization of edge table
8876 nETotal = 0;
8877
8878 // List of all particles
8879 pall = model->allParticles(&npall);
8880
8881 // add nodes
8882 for (n = 0; n < mgraph->nNodes; n++) {
8883 cl = pnclass->nd2cl[n];
8884 typ = pnclass->type[cl];
8885
8886 // external particle
8887 if (isATExternal(typ)) {
8888
8889#ifdef CHECK
8890 if (mgraph->nodes[n]->deg != 1) {
8891 grcc_fprintf(GRCC_Stdout, "*** assign:fromMGraph : "
8892 "external but deg[%d] = %d != 1, type=%d\n",
8893 n, mgraph->nodes[n]->deg, typ);
8894 mgraph->print();
8895 erEnd("assign:fromMGraph : illegal external particle");
8896 }
8897#endif
8898 np[0] = pnclass->particle[cl];
8899 nodes[n]->cand = new NCand(AS_AssExt, 1, 1, np);
8900 for (n1 = 0; n1 < mgraph->nNodes; n1++) {
8901 nc = mgraph->adjMat[n][n1];
8902 for (k = 0; k < nc; k++) {
8903 addEdge(n, n1, 1, np);
8904 }
8905 }
8906
8907 // vertex
8908 } else {
8909
8910 // candidates of vertices
8911 deg = mgraph->nodes[n]->deg;
8912 st = AS_UnAssLegs;
8913 cl = sproc->pnclass->nd2cl[n]; // class in the process
8914 mcl = sproc->pnclass->cl2mcl[cl]; // class in the model
8915
8916 if (nodes[n]->cand != NULL) {
8917 delete nodes[n]->cand;
8918 }
8919 lcn = model->ncouple;
8920
8921 // multiple coupling constants are defined in the model.
8922 if (lcn > 1) {
8923 nilist = 0;
8924 for (j = 0; j < model->cplgnvl[mcl]; j++) {
8925 ia = model->cplgvl[mcl][j];
8926
8927 // select by coupling constants
8928 if (leqArray(lcn, model->interacts[ia]->clist, cplleft)) {
8929 ilist[nilist++] = ia;
8930 }
8931 }
8932 nodes[n]->cand = new NCand(st, deg, nilist, ilist);
8933
8934 // there is only one coupling constant
8935 } else {
8936 nodes[n]->cand =
8937 new NCand(st, deg, model->cplgnvl[mcl], model->cplgvl[mcl]);
8938 }
8939
8940 // vertices
8941 for (n1 = n; n1 < mgraph->nNodes; n1++) {
8942 cl1 = pnclass->nd2cl[n1];
8943 typ1 = pnclass->type[cl1];
8944 if (!isATExternal(typ1)) {
8945 nc = mgraph->adjMat[n][n1];
8946 if (n == n1) {
8947 nc = nc/2;
8948 }
8949 for (k = 0; k < nc; k++) {
8950 addEdge(n, n1, npall, pall);
8951 }
8952 }
8953 }
8954 }
8955 }
8956#ifdef CHECK
8957 if (nETotal != nEdges) {
8958 grcc_fprintf(GRCC_Stdout, "*** Assign::fromMGraph nETotal=%d != nEdges=%d\n",
8959 nETotal, nEdges);
8960 erEnd("Assign::fromMGraph nETotal= != nEdges");
8961 }
8962#endif
8963
8964 // assign particle of an edge next to an external particle
8965 for (n = 0; n < mgraph->nNodes; n++) {
8966 cl = pnclass->nd2cl[n];
8967 typ = pnclass->type[cl];
8968 if (isATExternal(typ)) {
8969
8970 cl = pnclass->nd2cl[n];
8971 ptcl = pnclass->particle[cl];
8972
8973 // particle ptcl flows in to the node and
8974 // particle (- ptcl) flows in from the edge.
8975
8976#ifdef CHECK
8977 if (ptcl == 0) {
8978 erEnd("fromMGraph: ptcl=0");
8979 }
8980#endif
8981 ok = assignPLeg(n, 0, -ptcl);
8982 if (!ok) {
8983 // impossible config
8984 return False;
8985 }
8986 nn = nodes[n]->anodes[0];
8987 ok = updateCandNode(nn);
8988 if (!ok) {
8989 // impossible config
8990 return False;
8991 }
8992 }
8993 }
8994
8995#ifdef CHECK
8996 checkCand("fromMGraph");
8997 checkAG("fromMGraph");
8998#endif
8999
9000 return True;
9001}
9002
9003//---------------------------------------------------------------
9004void Assign::addEdge(int n0, int n1, int nplist, int *plist)
9005{
9006 // add an edge and set connection information
9007 // n0 -- (new edge) -- n1, with candidates 'plist'
9008
9009 int lg0, lg1, eid;
9010 AEdge *aed;
9011
9012#ifdef CHECK
9013 if (n0 >= nNodes || n1 >= nNodes) {
9014 grcc_fprintf(GRCC_Stdout, "*** Assign::addEdge : undefined nodes %d: [%d, %d]",
9015 nETotal, n0, n1);
9016 erEnd("Assign::addEdge : undefined nodes");
9017 }
9018#endif
9019
9020 // legs to be connected
9021 lg0 = nodes[n0]->newleg();
9022 lg1 = nodes[n1]->newleg();
9023
9024 // create edge
9025#ifdef CHECK
9026 if (nETotal >= nEdges) {
9027 erEnd("too many edges");
9028 }
9029#endif
9030
9031 aed = new AEdge(n0, lg0, n1, lg1);
9032 aed->cand = new ECand(False, nplist, plist);
9033
9034#ifdef CHECK
9035 if (edges[nETotal] != NULL) {
9036 erEnd("edges[nETotal] != NULL");
9037 }
9038#endif
9039
9040 // registor to the edge table
9041 eid = nETotal;
9042 edges[nETotal++] = aed;
9043
9044 // connect edge and nodes
9045 connect(n0, lg0, eid, 0, n1, lg1);
9046}
9047
9048//---------------------------------------------------------------
9049void Assign::connect(int n0, int l0, int eg, int el, int n1, int l1)
9050{
9051 // Connect (n0, l0) -- (eg, el) -- (nl)
9052
9053 ANode *nd0, *nd1;
9054 AEdge *ed;
9055 int eo;
9056
9057 nd0 = nodes[n0];
9058 nd1 = nodes[n1];
9059 ed = edges[eg];
9060 eo = 1 - el;
9061
9062 nd0->anodes[l0] = n1;
9063 nd0->aedges[l0] = eg;
9064 nd0->aelegs[l0] = el;
9065
9066 nd1->anodes[l1] = n0;
9067 nd1->aedges[l1] = eg;
9068 nd1->aelegs[l1] = eo;
9069
9070 ed->nodes[el] = n0;
9071 ed->nlegs[el] = l0;
9072
9073 ed->nodes[eo] = n1;
9074 ed->nlegs[eo] = l1;
9075}
9076
9077//---------------------------------------------------------------
9078Bool Assign::fillEGraph(int aid, BigInt nsym, BigInt esym, BigInt nsym1)
9079{
9080 // Set variables of egraph with the result of particle assignment
9081 // Adjust the ordering of legs of vertices in a consistent way
9082 // with the interaction defined in the model.
9083
9084 ANode *an;
9085 ENode *en;
9086 int work[3][GRCC_MAXLEGS];
9087 int n, lr, e;
9088 int *elist;
9089 int lg, ed, eg;
9090#ifdef CHECK
9091 int cl, ok = True;
9092#endif
9093
9094 egraph->assigned = True;
9095
9096 egraph->aId = aid;
9097 egraph->nsym = nsym;
9098 egraph->esym = esym;
9099 egraph->bicount = -1;
9100 if (sproc != NULL) {
9101 egraph->extperm = sproc->extperm;
9102 } else {
9103 egraph->extperm = 1;
9104 }
9105 egraph->nsym1 = nsym1;
9106 egraph->multp = (egraph->extperm * egraph->nsym1) / egraph->nsym;
9107
9108#ifdef CHECK
9109 checkAG("fillEGraph:0");
9110#endif
9111 // external node
9112 for (n = 0; n < nNodes; n++) {
9113 // vertices
9114#ifdef CHECK
9115 cl = pnclass->nd2cl[n];
9116 if (isATExternal(pnclass->type[cl])) {
9117 ;
9118 } else if (nodes[n]->cand->st != AS_Assigned) {
9119 grcc_fprintf(GRCC_Stdout, "*** fillEGraph : node %d is not assigned", n);
9120 prCand("fillEGraph: node");
9121 erEnd("fillEGraph : node is not assigned");
9122 }
9123#endif
9124
9125 an = nodes[n];
9126 en = egraph->nodes[n];
9127
9128 en->initAss(egraph, n, an->deg);
9129
9130 en->intrct = an->cand->ilist[0];
9131 elist = reordLeg(n, work[0], work[1], work[2]);
9132 for (lr = 0; lr < nodes[n]->deg; lr++) {
9133 if (elist == NULL) {
9134 lg = lr;
9135 } else {
9136 lg = elist[lr];
9137 }
9138#ifdef CHECK
9139 if (lg < 0 || lg >= nodes[n]->deg) {
9140 grcc_fprintf(GRCC_Stdout, "*** fillEGraph: n=%d, lr=%d: 0 <= lg=%d < %d\n",
9141 n, lr, lg, nodes[n]->deg);
9142 erEnd("fillEGraph: illegal reordering");
9143 }
9144#endif
9145 ed = an->aedges[lg];
9146 eg = an->aelegs[lg];
9147
9148 en->edges[lr] = I2Vedge(ed, 2*eg-1);
9149
9150 egraph->edges[ed]->nodes[eg] = n;
9151 egraph->edges[ed]->nlegs[eg] = lr;
9152 }
9153 }
9154 // edges
9155 for (e = 0; e < nEdges; e++) {
9156#ifdef CHECK
9157 if (edges[e]->cand->nplist != 1) {
9158 grcc_fprintf(GRCC_Stdout, "*** fillEGraph : edge %d is not assigned", e);
9159 prCand("fillEGraph: edge");
9160 erEnd("fillEGraph : edge is not assigned");
9161 }
9162#endif
9163 egraph->edges[e]->ptcl = edges[e]->cand->plist[0];
9164 }
9165#ifdef EDGEPORDER
9166 for (e = 0; e < nEdges; e++) {
9167 if (egraph->edges[e]->ptcl < 0) {
9168 egraph->edges[e]->ptcl = - edges[e]->cand->plist[0];
9169 n = egraph->edges[e]->nodes[0];
9170 lr = egraph->edges[e]->nlegs[0];
9171 egraph->edges[e]->nodes[0] = egraph->edges[e]->nodes[1];
9172 egraph->edges[e]->nlegs[0] = egraph->edges[e]->nlegs[1];
9173 egraph->edges[e]->nodes[1] = n;
9174 egraph->edges[e]->nlegs[1] = lr;
9175
9176 egraph->nodes[n]->edges[lr] = - egraph->nodes[n]->edges[lr];
9177 n = egraph->edges[e]->nodes[0];
9178 lr = egraph->edges[e]->nlegs[0];
9179 egraph->nodes[n]->edges[lr] = - egraph->nodes[n]->edges[lr];
9180 }
9181 }
9182#endif
9183#ifdef CHECK
9184 for (ed = 0; ed < nEdges; ed++) {
9185 n = egraph->edges[ed]->nodes[0];
9186 lr = egraph->edges[ed]->nlegs[0];
9187 if (egraph->nodes[n]->edges[lr] != -ed-1) {
9188 grcc_fprintf(GRCC_Stderr, "+++ node[%d][%d]=%d != - (edge[%d][0] + 1) = %d\n",
9189 n, lr, egraph->nodes[n]->edges[lr], e, -ed-1);
9190 ok = False;
9191 }
9192 n = egraph->edges[ed]->nodes[1];
9193 lr = egraph->edges[ed]->nlegs[1];
9194 if (egraph->nodes[n]->edges[lr] != ed+1) {
9195 grcc_fprintf(GRCC_Stderr, "+++ node[%d][%d]=%d != + (edge[%d][0] + 1) = %d\n",
9196 n, lr, egraph->nodes[n]->edges[lr], e, ed+1);
9197 ok = False;
9198 }
9199 }
9200 if (!ok) {
9201 egraph->print();
9202 erEnd("fillEGraph: illegal connection");
9203 }
9204#endif
9205
9206
9207 // analyse fermion line and determine Fermi statistical sign factor
9208 egraph->getFLines();
9209
9210#ifdef CHECK
9211 checkAG("fillEGraph:0");
9212#endif
9213 return True;
9214
9215}
9216
9217//---------------------------------------------------------------
9218int *Assign::reordLeg(int n, int *reord, int *plist, int *used)
9219{
9220 // Reorder legs of node 'n' in accordance with the definition
9221 // of the interaction in the model
9222 //
9223 // plist[record[j]] = model->interacts[ia]->plist[j]
9224
9225 int lg, ia, lr, deg, pt, ed;
9226 int *ilegs;
9227#ifdef CHECK
9228 Bool found;
9229#endif
9230
9231 // external node
9232 if (nodes[n]->cand->st == AS_AssExt) {
9233 reord[0] = 0;
9234 return 0;
9235 }
9236
9237 // degree of the node
9238 deg = nodes[n]->deg;
9239
9240 if (deg <= 1) {
9241 reord[0] = 0;
9242 return 0;
9243 }
9244
9245 // list of particles at the legs of the node 'n'
9246 for (lg = 0; lg < deg; lg++) {
9247 ed = nodes[n]->aedges[lg];
9248 pt = edges[ed]->cand->plist[0];
9249 plist[lg] = legEdgeParticle(n, lg, pt);
9250 used[lg] = 0;
9251 }
9252
9253 // list of legs in the interaction
9254 ia = nodes[n]->cand->ilist[0];
9255 ilegs = model->interacts[ia]->plist;
9256
9257 // reorder
9258#ifdef CHECK
9259 found = False;
9260#endif
9261 for (lr = 0; lr < deg; lr++) {
9262 for (lg = 0; lg < deg; lg++) {
9263 if (used[lg] == 0 && plist[lg] == ilegs[lr]) {
9264 reord[lr] = lg;
9265 used[lg] = 1;
9266#ifdef CHECK
9267 found = True;
9268#endif
9269 break;
9270 }
9271 }
9272
9273#ifdef CHECK
9274 if (!found) {
9275 grcc_fprintf(GRCC_Stdout, "*** reordLeg: illegal list of particles:"
9276 "interaction %d ", ia);
9277 prIntArray(deg, ilegs, "; ");
9278 grcc_fprintf(GRCC_Stdout, "vertex %d ", n);
9279 prIntArray(deg, plist, "\n");
9280 prCand("reordLeg");
9281 erEnd("reordLeg: illegal list of particles");
9282 }
9283#endif
9284 }
9285
9286 return reord;
9287}
9288
9289//==============================================================
9290// Adjust the direction of a particle on an edge and on a leg of
9291// node.
9292//---------------------------------------------------------------
9293int Assign::getLegParticle(int n, int ln)
9294{
9295 // Get particle code of (n, ln) when particle 'pt' runs
9296 // in the direction of the edge at (n, ln).
9297 //
9298 // Get particle code in the direction the edge at (n, ln)
9299 // when particle 'pt' is at leg (n, ln).
9300 //
9301 // These two cases are realized by the same function
9302
9303 ANode *nd;
9304 int elg, ed, pt;
9305
9306 nd = nodes[n];
9307 elg = nd->aelegs[ln];
9308 ed = nd->aedges[ln];
9309 pt = edges[ed]->cand->plist[0];
9310
9311 // normalization of sign for neutral particle
9312 if (elg == 0) {
9313 return model->normalParticle(-pt);
9314 } else {
9315 return model->normalParticle(pt);
9316 }
9317}
9318
9319//---------------------------------------------------------------
9320int Assign::legEdgeParticle(int n, int ln, int pt)
9321{
9322 // Get particle code of (n, ln) when particle 'pt' runs
9323 // in the direction of the edge at (n, ln).
9324 //
9325 // Get particle code in the direction the edge at (n, nl)
9326 // when particle 'pt' is at leg (n, ln).
9327 //
9328 // These two cases are realized by the same function
9329
9330 // normalization of sign for neutral particle
9331
9332 if (nodes[n]->aelegs[ln] == 0) {
9333 return model->normalParticle(-pt);
9334 } else {
9335 return model->normalParticle(pt);
9336 }
9337}
9338
9339//---------------------------------------------------------------
9340int Assign::legPart(int v, int lg, int nplist, int *plist, int *rlist, const int size)
9341{
9342 // Convert list of candidate particles in 'plist' at (v, lg) ==> edge
9343 // or edge ==> (v, lg)
9344
9345 int j, nrlist;
9346
9347 nrlist = 0;
9348 for (j = 0; j < nplist; j++) {
9349 nrlist = intSetAdd(nrlist, rlist,
9350 legEdgeParticle(v, lg, plist[j]), size);
9351 }
9352 return nrlist;
9353}
9354
9355//---------------------------------------------------------------
9356int Assign::candPart(int v, int ln, int *plist, const int size)
9357{
9358 // update candidate particles incoming to (v, ln)
9359
9360 int en;
9361 int ntplist;
9362 ECand *ec;
9363
9364 en = nodes[v]->aedges[ln];
9365
9366#ifdef CHECK
9367 if (edges[en]->cand->det) {
9368 grcc_fprintf(GRCC_Stdout, "*** candPart : particle of leg (%d, %d) "
9369 "is assigned to %d\n",
9370 v, ln, edges[en]->cand->plist[0]);
9371 checkCand("candPart");
9372 mgraph->printAdjMat(mgraph->curcl);
9373 prCand("candPart");
9374 erEnd("candPart : particle of leg is assigned");
9375 }
9376#endif
9377
9378 ec = edges[en]->cand;
9379
9380 ntplist = legPart(v, ln, ec->nplist, ec->plist, plist, size);
9381
9382 return ntplist;
9383}
9384
9385//==============================================================
9386// tools for assignment
9387
9388//---------------------------------------------------------------
9389int Assign::selUnAssVertexSimp(int lastv)
9390{
9391 // Select a vertex for assignment to its leg.
9392 // We take one with minimum number of candidates
9393 //
9394 // There may be better method.
9395
9396 int v0, v;
9397
9398 // select vertex one by one in the sequential order of node number
9399 v0 = Max(lastv+1, nExtern);
9400 for (v = v0; v < nNodes; v++) {
9401 if (nodes[v]->cand->st == AS_UnAssLegs) {
9402 return v;
9403 }
9404 }
9405 return -1;
9406}
9407
9408//---------------------------------------------------------------
9409int Assign::selUnAssVertex(void)
9410{
9411 // Select a vertex for assignment to its leg.
9412 // We take one with minimum number of candidates
9413 //
9414 // There may be better method.
9415
9416 int v0, v, nl;
9417
9418 // select vertex one by one in the sequential order of node number
9419 v0 = -1;
9420 nl = 0;
9421 for (v = 0; v < nNodes; v++) {
9422 if (nodes[v]->cand->st == AS_UnAssLegs) {
9423 if (nodes[v]->cand->nilist == 1) {
9424 return v;
9425 } else if (nodes[v]->cand->nilist > 1) {
9426 // select node with fewer candidates
9427 if (v0 < 0 || nodes[v]->cand->nilist < nl) {
9428 v0 = v;
9429 nl = nodes[v]->cand->nilist;
9430 }
9431 }
9432 }
9433 }
9434 return v0;
9435}
9436
9437//---------------------------------------------------------------
9438int Assign::selUnAssLeg(int v, int lastlg)
9439{
9440 // Select a leg of vertex 'v' for the assignment.
9441 // The lastly selected leg was 'lastlg'.
9442
9443 int lg0, lg, e;
9444#ifdef CHECK
9445 int n0, n1;
9446#endif
9447
9448 // lg0 = Max(lastlg, lastlg + 1);
9449 lg0 = lastlg + 1;
9450
9451 for (lg = lg0; lg < nodes[v]->deg; lg++) {
9452
9453#ifdef CHECK
9454 if (lastlg >= 0) {
9455 n0 = nodes[v]->anodes[lastlg];
9456 } else {
9457 n0 = -1;
9458 }
9459 n1 = nodes[v]->anodes[lg];
9460 if (n0 > n1) {
9461 grcc_fprintf(GRCC_Stdout, "*** selUnAssLeg: n0=%d > n1=%d\n", n0, n1);
9462 grcc_fprintf(GRCC_Stdout, "*** illegal connection\n");
9463 erEnd("selUnAssLeg: n0 > n1");
9464 }
9465#endif
9466
9467 e = nodes[v]->aedges[lg];
9468 if (!edges[e]->cand->det) {
9469 return lg;
9470 }
9471
9472 }
9473 return -1;
9474}
9475
9476//---------------------------------------------------------------
9477NCandSt Assign::assignIVertex(int v, int ia)
9478{
9479 // Try to assign interaction 'ia' to 'v'
9480
9481 int lplist[GRCC_MAXLEGS], iplist[GRCC_MAXLEGS];
9482 int lg, e, pt, deg;
9483
9484
9485 if (nodes[v]->cand->st == AS_Assigned || nodes[v]->cand->st == AS_AssExt) {
9486 return AS_Assigned0;
9487 }
9488
9489 deg = nodes[v]->deg;
9490 if (deg != model->interacts[ia]->nlegs) {
9491 return AS_Impossible;
9492 }
9493
9494 // list of particles at the legs of the vertex
9495 for (lg = 0; lg < deg; lg++) {
9496 e = nodes[v]->aedges[lg];
9497 if (edges[e]->cand->nplist != 1) {
9498 return AS_UnAssLegs;
9499 } else {
9500 pt = edges[e]->cand->plist[0];
9501 lplist[lg] = legEdgeParticle(v, lg, pt);
9502 }
9503 iplist[lg] = model->interacts[ia]->plist[lg];
9504 }
9505
9506 sorti(deg, lplist);
9507 sorti(deg, iplist);
9508
9509 // from interaction
9510 if (cmpArray(deg, lplist, deg, iplist) == 0) {
9511 // orders of coupling constants should be checked ???
9512 astack->pushNode(v);
9513 nodes[v]->cand->st = AS_Assigned;
9514 nodes[v]->cand->nilist = 1;
9515 nodes[v]->cand->ilist[0] = ia;
9516 return AS_Assigned;
9517 }
9518
9519 return AS_Impossible;
9520}
9521
9522//---------------------------------------------------------------
9523Bool Assign::assignPLeg(int n, int ln, int pt)
9524{
9525 // A particle 'pt' is assigned to leg 'ln' of node 'n'
9526
9527 ANode *nd;
9528 int e, ept;
9529 Bool ok;
9530
9531#ifdef CHECK
9532 checkNode(n, "assignPLeg0");
9533 checkCand("assignPLeg");
9534#endif
9535
9536 // nodes and the edge
9537 nd = nodes[n];
9538 e = nd->aedges[ln];
9539
9540 // already determined
9541 if (edges[e]->cand->det) {
9542 return True;
9543 }
9544
9545 if (!isOrdPLeg(n, ln, pt)) {
9546 return False;
9547 }
9548
9549 // particle on the edge
9550 ept = legEdgeParticle(n, ln, pt);
9551
9552#ifdef CHECK
9553 if (!isIn(edges[e]->cand->nplist, edges[e]->cand->plist, ept)) {
9554 grcc_fprintf(GRCC_Stdout, "*** assignPLeg: particle %d is not in the cand. of e=%d",
9555 ept, e);
9556 edges[e]->cand->prECand("\n");
9557 prCand("assignPLeg");
9558 erEnd("assignPLeg: particle is not in the cand.");
9559 }
9560#endif
9561
9562 // save the current configuration
9563 astack->pushEdge(e);
9564
9565 // determine the particle on the edge
9566 edges[e]->cand->nplist = 1;
9567 edges[e]->cand->plist[0] = ept;
9568
9569 ok = detEdge(e);
9570
9571 return ok;
9572}
9573
9574//---------------------------------------------------------------
9575Bool Assign::detEdge(int e)
9576{
9577 Bool ok0, ok1;
9578
9579 if (edges[e]->cand->nplist != 1) {
9580 return False;
9581 }
9582 edges[e]->cand->det = True;
9583
9584 // update candidate list
9585 ok0 = updateCandNode(edges[e]->nodes[0]);
9586 if (ok0) {
9587 ok1 = updateCandNode(edges[e]->nodes[1]);
9588 } else {
9589 ok1 = False;
9590 }
9591
9592 return (ok0 && ok1);
9593}
9594
9595//---------------------------------------------------------------
9596Bool Assign::isOrdPLeg(int n, int ln, int pt)
9597{
9598 int e0, el, ln0, ep0, pt0, nn, n0, n1, ln1, pt1, e1, ep1;
9599
9600 if (nodes[n]->deg < 2) {
9601 return True;
9602 }
9603 nn = nodes[n]->anodes[ln];
9604 if (n <= nn) {
9605 n0 = n;
9606 n1 = nn;
9607 ln0 = ln;
9608 pt0 = pt;
9609 } else {
9610 n0 = nn;
9611 n1 = n;
9612 e0 = nodes[n]->aedges[ln];
9613 el = nodes[n]->aelegs[ln];
9614 ln0 = edges[e0]->nlegs[1-el];
9615 ep0 = legEdgeParticle(n, ln, pt);
9616 pt0 = legEdgeParticle(n0, ln0, ep0);
9617 }
9618
9619 for (ln1 = 0; ln1 < nodes[n0]->deg; ln1++) {
9620 if (ln1 == ln0 || n1 != nodes[n0]->anodes[ln1]) {
9621 continue;
9622 }
9623 e1 = nodes[n0]->aedges[ln1];
9624 if (!edges[e1]->cand->det) {
9625 continue;
9626 }
9627 ep1 = edges[e1]->cand->plist[0];
9628 pt1 = legEdgeParticle(n0, ln1, ep1);
9629 if ((ln0 < ln1 && pt0 > pt1) ||
9630 (ln0 > ln1 && pt0 < pt1)) {
9631 return False;
9632 }
9633 }
9634 return True;
9635}
9636
9637//==============================================================
9638// Operations of candidate
9639//---------------------------------------------------------------
9640Bool Assign::candPartClassify(int v, int *npdass, int *pdass, int *npuass, int *puass, const int size)
9641{
9642 // Construct the classified lists of particles possible to assign to
9643 // the legs of node v
9644 //
9645 // pdass = (duplicated set of particles where edges has a unique
9646 // candidate)
9647 // puass = (duplicated set of other candidate particles)
9648
9649 int lg, e, npl, ass, jd, ju, j, pt, pts;
9650
9651 jd = 0;
9652 ju = 0;
9653 for (lg = 0; lg < nodes[v]->deg; lg++) {
9654 e = nodes[v]->aedges[lg];
9655 npl = edges[e]->cand->nplist;
9656 if (npl < 1) {
9657 return False;
9658 }
9659 ass = (npl == 1);
9660 for (j = 0; j < edges[e]->cand->nplist; j++) {
9661 pt = edges[e]->cand->plist[j];
9662 pts = legEdgeParticle(v, lg, pt);
9663 if (ass) {
9664 jd = intSListAdd(jd, pdass, pts, size);
9665 } else {
9666 ju = intSListAdd(ju, puass, pts, size);
9667 }
9668 }
9669 }
9670 *npdass = jd;
9671 *npuass = ju;
9672
9673 return True;
9674}
9675
9676//---------------------------------------------------------------
9677Bool Assign::updateCandNode(int v)
9678{
9679 // Update the configuration
9680 // - nodes[v]->cand->ilist
9681 // - edges[e]->cand->plist for the adjacent edge
9682 // - nodes[n]->cand->unass for the adjacent node 'n' of 'e'
9683
9684 int npdass, pdass[GRCC_MAXPSLIST];
9685 int npuass, puass[GRCC_MAXPSLIST];
9686 int nsub0, sub0[GRCC_MAXPSLIST];
9687 int niplist, iplist[GRCC_MAXPSLIST];
9688 int nd0, d0[GRCC_MAXMPARTICLES2];
9689 int nd1, d1[GRCC_MAXMPARTICLES2];
9690 int ns0, s0[GRCC_MAXMPARTICLES2];
9691 int neplist, eplist[GRCC_MAXMPARTICLES2];
9692 int nitlist, itlist[GRCC_MAXMINTERACT];
9693 int e, it, j, k, i, lg;
9694
9695 // external node
9696 if (nodes[v]->cand->st == AS_AssExt) {
9697#ifdef CHECK
9698 e = nodes[v]->aedges[0];
9699 if (e < 0 || edges[e]->cand->nplist != 1) {
9700 grcc_fprintf(GRCC_Stdout, "*** illegal external node: v=%d e=%d :", v, e);
9701 prCand("updateCandNode");
9702 erEnd("illegal external node");
9703 }
9704#endif
9705
9706 return True;
9707 }
9708
9709 // impossible configuration.
9710 if (nodes[v]->cand->nilist < 1) {
9711 return False;
9712 }
9713
9714 // list of possible particles on the edges of the vertex.
9715 // pdass = (set of assigned particles)
9716 // puass = (list of particles of edges with two of more candidates)
9717
9718 niplist = 0;
9719 nitlist = 0;
9720 if (!candPartClassify(v, &npdass, pdass, &npuass, puass, GRCC_MAXPSLIST)) {
9721 return False;
9722 }
9723
9724 if (npdass < 1) {
9725 return False;
9726 }
9727
9728 // from interaction : slist
9729 // Conditions :
9730 // 1. pdass \subset slist
9731 // 2. slist-pdass \subset puass
9732 // from interaction : slist
9733 // conditions : pdass \subset slist \subset (pdass + puass)
9734 // sub0 = slist - pdass,
9735 nitlist = 0;
9736 for (j = 0; j < nodes[v]->cand->nilist; j++) {
9737 it = nodes[v]->cand->ilist[j];
9738 // conditions:
9739 // 1. pdass \subset slist <==> pdass-slist = \emptyset
9740 // 2. slist-pdass \subset puass <==> (slist-pdass)-puass = \emptyset
9741 if (isSubSList(npdass, pdass,
9742 model->interacts[it]->nslist,
9743 model->interacts[it]->slist) ) {
9744 nsub0 = subtrSet(model->interacts[it]->nslist,
9745 model->interacts[it]->slist,
9746 npdass, pdass, sub0, GRCC_MAXPSLIST);
9747 if (nsub0 < 1) {
9748 // slist == pdass : no additional candidate particle
9749 nitlist = intSetAdd(nitlist, itlist, it, GRCC_MAXMINTERACT);
9750
9751 } else {
9752 if (isSubSList(nsub0, sub0, npuass, puass)) {
9753 nitlist = intSetAdd(nitlist, itlist, it, GRCC_MAXMINTERACT);
9754 for (k = 0; k < nsub0; k++) {
9755 niplist = intSetAdd(niplist,iplist,sub0[k],GRCC_MAXPSLIST);
9756 }
9757 }
9758 }
9759 }
9760 }
9761
9762 if (nitlist < 1) {
9763 return False;
9764 }
9765
9766 if (nitlist != nodes[v]->cand->nilist) {
9767 astack->pushNode(v);
9768 nodes[v]->cand->nilist = nitlist;
9769 for (i = 0; i < nitlist; i++) {
9770 nodes[v]->cand->ilist[i] = itlist[i];
9771 }
9772#ifdef CHECK
9773 } else if (nitlist > nodes[v]->cand->nilist) {
9774 erEnd("larger ncand");
9775#endif
9776 }
9777
9778 // edge
9779 for (lg = 0; lg < nodes[v]->deg; lg++) {
9780 e = nodes[v]->aedges[lg];
9781 if (edges[e]->cand->nplist > 1) {
9782 // elist = {candidate particles in the direction of the edge}
9783 // s0 = plist \cap elist
9784 neplist = legPart(v, lg, niplist, iplist, eplist, GRCC_MAXMPARTICLES2);
9785 listDiff(edges[e]->cand->nplist, edges[e]->cand->plist,
9786 neplist, eplist,
9787 &nd0, d0, &ns0, s0, &nd1, d1);
9788
9789 if (ns0 < 1) {
9790 return False;
9791 }
9792 if (ns0 < edges[e]->cand->nplist) {
9793 astack->pushEdge(e);
9794 edges[e]->cand->nplist = ns0;
9795 for (i = 0; i < ns0; i++) {
9796 edges[e]->cand->plist[i] = s0[i];
9797 }
9798 }
9799 }
9800 }
9801 for (lg = 0; lg < nodes[v]->deg; lg++) {
9802 e = nodes[v]->aedges[lg];
9803 if (edges[e]->cand->nplist == 1 && !edges[e]->cand->det) {
9804 if(!detEdge(e)) {
9805 return False;
9806 }
9807 }
9808 }
9809
9810 return True;
9811}
9812
9813//==============================================================
9814// Check order of coupling constants, duplication and isomorphism
9815//--------------------------------------------------------------
9816Bool Assign::checkOrderCpl(void)
9817{
9818 // Check order of coupling constants
9819
9820 int ord[GRCC_MAXNCPLG];
9821 int lcn, n, ia, j, cl;
9822
9823 // list of coupling constants
9824 lcn = model->ncouple;
9825
9826 if (lcn == 1) {
9827 return True;
9828 }
9829
9830 // sum up for each coupling constants
9831 for (j = 0; j < GRCC_MAXNCPLG; j++) {
9832 ord[j] = 0;
9833 }
9834 for (n = 0; n < nNodes; n++) {
9835 cl = pnclass->nd2cl[n];
9836 if (!isATExternal(pnclass->type[cl])) {
9837 ia = nodes[n]->cand->ilist[0];
9838 for (j = 0; j < lcn; j++) {
9839 ord[j] += model->interacts[ia]->clist[j];
9840 }
9841 }
9842 }
9843
9844 // comparison
9845 for (j = 0; j < lcn; j++) {
9846 if (sproc->clist[j] != ord[j]) {
9847 return False;
9848 }
9849 }
9850 return True;
9851}
9852
9853//--------------------------------------------------------------
9854Bool Assign::isOrdLegs(void)
9855{
9856 // Whether graph is duplicated because of the violation
9857 // of ordering in the case of multiple connections
9858 // v0 <-- v --> v1
9859
9860 int v, l0, v0, l1, v1, e0, e1, q0, q1, p0, p1, cl;
9861
9862 for (v = 0; v < nNodes; v++) {
9863 cl = pnclass->nd2cl[v];
9864 if (!isATExternal(pnclass->type[cl])) {
9865 for (l0 = 0; l0 < nodes[v]->deg; l0++) {
9866 v0 = nodes[v]->anodes[l0];
9867 for (l1 = l0+1; l1 < nodes[v]->deg; l1++) {
9868 v1 = nodes[v]->anodes[l1];
9869
9870 if (v0 == v1 && v <= v0) {
9871 // multiple connections (v, l0) and (v, l1)
9872 e0 = nodes[v]->aedges[l0];
9873 e1 = nodes[v]->aedges[l1];
9874 q0 = edges[e0]->cand->plist[0];
9875 q1 = edges[e1]->cand->plist[0];
9876 p0 = legEdgeParticle(v, l0, q0);
9877 p1 = legEdgeParticle(v, l1, q1);
9878 if (p0 > p1) {
9879 // violation of ordering
9880 return False;
9881 }
9882 }
9883 }
9884 }
9885 }
9886 }
9887
9888 return True;
9889}
9890
9891//--------------------------------------------------------------
9892Bool Assign::isIsomorphic(MNodeClass *cl, BigInt *nsym, BigInt *esym, BigInt *nsym1)
9893{
9894 // Check whether the current graph is the representive of
9895 // a isomorphic class.
9896 // Returns (nsym, esym)
9897 // nsym = symmetry factor by the permutation of nodes.
9898 // esym = symmetry factor by the permutation of edge.
9899 // If this graph is not a representative, then returns (0,0).
9900
9901 int j, cmp, n, cln;
9902 BigInt ngelem;
9903 int *p;
9904 Bool invext;
9905
9906 ngelem = mgraph->group->nElem();
9907#ifdef CHECK
9908 if (mgraph->nsym > 1 && ngelem <= 1) {
9909 grcc_fprintf(GRCC_Stdout, "*** isIsomorphic: illegal group: "
9910 "ngelem=%ld, mgraph->sym=(%ld, %ld)\n",
9911 ngelem, mgraph->nsym, mgraph->esym);
9912 erEnd("Assign::isIsomorphic: illegal group");
9913 }
9914#endif
9915 if (ngelem == 0) {
9916 *nsym = 1;
9917 *nsym1 = 1;
9918 } else {
9919 *nsym = 0;
9920 *nsym1 = 0;
9921 for (j = 0; j < ngelem; j++) {
9922 // check the graph is the representative and count 'nsym'.
9923
9924 //p = mgraph->group->nextElem();
9925 p = mgraph->group->elem[j];
9926
9927 cmp = cmpPermGraph(p, cl);
9928
9929 if (cmp < 0) { // duplicated graph
9930 return False;
9931 } else if(cmp == 0) { // not duplicated
9932 (*nsym)++;
9933
9934 if (opt->values[GRCC_OPT_SymmInitial] || opt->values[GRCC_OPT_SymmFinal]) {
9935 invext = True;
9936 for (n = 0; n < nNodes; n++) {
9937 cln = pnclass->nd2cl[n];
9938 if (!isATExternal(pnclass->type[cln])) {
9939 continue;
9940 }
9941 if (p[n] != n) {
9942 invext = False;
9943 }
9944 }
9945 if (invext) {
9946 (*nsym1)++;
9947 }
9948 } else {
9949 (*nsym1)++;
9950 }
9951 }
9952 }
9953 }
9954 if (*nsym1 == 0) {
9955 *nsym1 = *nsym;
9956 }
9957
9958 // calculate permutations of edges
9959 *esym = edgeSym();
9960 if (*esym < 1) {
9961 return False;
9962 }
9963
9964 return True;
9965}
9966
9967//--------------------------------------------------------------
9968int Assign::cmpPermGraph(int *p, MNodeClass *cl)
9969{
9970 // compare the graph with one permutated by 'p'.
9971
9972 int n, cmp, n1, n2, p1, p2, j;
9973 ANode *nd1, *np1;
9974 // ANode *nd2, *np2;
9975 int njn, jn[GRCC_MAXLEGS];
9976 int njp, jp[GRCC_MAXLEGS];
9977
9978#ifdef CHECK
9979 if (p == NULL) {
9980 erEnd("Assign::cmpPermGraph: p==NULL");
9981 }
9982#endif
9983 for (n = 0; n < nNodes; n++) {
9984 if (!isATExternal(pnclass->type[pnclass->nd2cl[n]])) {
9985 cmp = cmpNodes(n, p[n], cl);
9986 if (cmp != 0) {
9987 return cmp;
9988 }
9989 }
9990 }
9991
9992 njn = 0;
9993 njp = 0;
9994 for (n1 = 0; n1 < nNodes; n1++) {
9995 p1 = p[n1];
9996 nd1 = nodes[n1];
9997 np1 = nodes[p1];
9998 for (n2 = n1; n2 < nNodes; n2++) {
9999 if (mgraph->adjMat[n1][n2] == 0) {
10000 continue;
10001 }
10002
10003 p2 = p[n2];
10004 if (p1 == n1 && p2 == n2) {
10005 continue;
10006 }
10007 cmp = mgraph->adjMat[n1][n2] - mgraph->adjMat[p1][p2];
10008 if (cmp != 0) {
10009 return cmp;
10010 }
10011
10012 njn = 0;
10013 njp = 0;
10014 for (j = 0; j < nd1->deg; j++) {
10015 if (nd1->anodes[j] == n2) {
10016 jn[njn++] = getLegParticle(n1, j);
10017 }
10018 }
10019
10020 for (j = 0; j < np1->deg; j++) {
10021 if (np1->anodes[j] == p2) {
10022 jp[njp++] = getLegParticle(p1, j);
10023 }
10024 }
10025
10026 cmp = njn - njp;
10027 if (cmp != 0) {
10028 return cmp;
10029 }
10030
10031 // ignore ordering for multiple connections
10032 if (mgraph->adjMat[n1][n2] >= 2) {
10033 sorti(njn, jn);
10034 sorti(njn, jp);
10035 }
10036
10037 for (j = 0; j < njn; j++) {
10038 cmp = jn[j] - jp[j];
10039 if (cmp != 0) {
10040 return cmp;
10041 }
10042 }
10043 }
10044 }
10045
10046 return 0;
10047}
10048
10049//--------------------------------------------------------------
10050int Assign::cmpNodes(int nd0, int nd1, MNodeClass *cn)
10051{
10052 // Comparison of two nodes 'nd0' and 'nd1'
10053 // Ordering is lexicographical (class, connection configuration)
10054 //
10055
10056 int cmp;
10057
10058 // Wether two nodes are in a same class or not.
10059 cmp = cn->ndcl[nd0] - cn->ndcl[nd1];
10060 if (cmp != 0) {
10061 return cmp;
10062 }
10063
10064 // interaction
10065 cmp = nodes[nd0]->cand->ilist[0] - nodes[nd1]->cand->ilist[0];
10066 return cmp;
10067}
10068
10069//--------------------------------------------------------------
10070BigInt Assign::edgeSym(void)
10071{
10072 // calculate permutations of edges
10073
10074 int lg[GRCC_MAXLEGS], lt[GRCC_MAXLEGS], lc;
10075 ANode *nd1;
10076 int n1, n2, j, k, mult;
10077 BigInt esym;
10078
10079 esym = 1;
10080 for (n1 = 0; n1 < nNodes; n1++) {
10081 nd1 = nodes[n1];
10082 for (n2 = n1; n2 < nNodes; n2++) {
10083 if (mgraph->adjMat[n1][n2] > 1) {
10084 lc = 0;
10085 for (j = 0; j < nd1->deg; j++) {
10086 if (nd1->anodes[j] == n2) {
10087 lg[lc] = 1;
10088 lt[lc] = getLegParticle(n1, j);
10089 lc++;
10090 }
10091 }
10092 for (j = 0; j < lc-1; j++) {
10093 if (lg[j] > 0) {
10094 for (k = lc-1; k > j; k--) {
10095 if (lt[j] == lt[k]) {
10096 lg[j] += lg[k];
10097 lg[k] = 0;
10098 }
10099 }
10100 }
10101 }
10102
10103 // calculate symmetry factor
10104 for (j = 0; j < lc; j++) {
10105 if (lg[j] < 1) {
10106 continue;
10107 }
10108 mult = lg[j];
10109 if (mult > 1) {
10110 if (n1 == n2) {
10111 // self-loop
10112 esym *= ipow(2,mult/2)*factorial(mult/2);
10113 } else {
10114 esym *= factorial(mult);
10115 }
10116 }
10117 }
10118 }
10119 }
10120 }
10121
10122 return esym;
10123}
10124
10125#ifdef CHECK
10126//==============================================================
10127// check
10128//--------------------------------------------------------------
10129Bool Assign::checkCand(const char *msg)
10130{
10131 // Check the consistency of Candidate data
10132
10133 Bool ok;
10134 ANode *na;
10135 NCand *nc;
10136 ECand *ec;
10137 int n, lg, e;
10138
10139 // check 'nodes->cand'
10140 ok = True;
10141 for (n = 0; n < nNodes; n++) {
10142 na = nodes[n];
10143 nc = na->cand;
10144
10145 // check unassigned vertex
10146 if (nc->st == AS_UnAssLegs) {
10147
10148 // check assigned vertex
10149 } else if (nc->st == AS_Assigned) {
10150 if (nc->nilist < 1) {
10151 grcc_fprintf(GRCC_Stdout, "*** checkCand:7:%s:status (%d) of node %d says"
10152 " interaction is assigned to %d but ilist=",
10153 msg, nc->st, n, nc->st);
10154 prIntArray(nc->nilist, nc->ilist, "\n");
10155 ok = False;
10156 }
10157
10158 for (lg = 0; lg < nc->deg; lg++) {
10159 e = na->aedges[lg];
10160 ec = edges[e]->cand;
10161 if (ec->nplist != 1) {
10162 grcc_fprintf(GRCC_Stdout, "*** checkCand:8:%s:status (%d) of node %d says"
10163 " interaction is assigned "
10164 " but unassigned edge %d is found\n",
10165 msg, nc->st, n, e);
10166 ok = False;
10167 }
10168 }
10169
10170 // external particle
10171 } else if (nc->st == AS_AssExt) {
10172 // pt = nc->ilist[0];
10173 // *** pte = legEdgeParticle(n, 0, - pt);
10174 } else {
10175 grcc_fprintf(GRCC_Stdout, "*** checkCand:10:%s:illegal status of node %d : %d",
10176 msg, n, nc->st);
10177 ok = False;
10178 }
10179 }
10180
10181 // check edges
10182
10183 for (e = 0; e < nEdges; e++) {
10184 ec = edges[e]->cand;
10185 if (ec != NULL && ec->nplist < 1) {
10186 grcc_fprintf(GRCC_Stdout, "*** checkCand:12:%s:illegal edge %d\n", msg, e);
10187 ok = False;
10188 }
10189 }
10190
10191 if (!ok) {
10192 grcc_fprintf(GRCC_Stdout, "*** checkCand:15:%s:illegal configuration\n", msg);
10193 prCand("checkCand");
10194 grcc_fprintf(GRCC_Stdout, "*** checkCand:16:illegal configuration\n");
10195 erEnd("checkCand:16:illegal configuration");
10196 }
10197 return ok;
10198}
10199
10200//--------------------------------------------------------------
10201void Assign::checkNode(int n, const char *msg)
10202{
10203 int j, it;
10204
10205 for (j = 0; j < nodes[n]->cand->nilist; j++) {
10206 it = nodes[n]->cand->ilist[j];
10207 if (Abs(it) >= GRCC_MAXMINTERACT) {
10208 grcc_fprintf(GRCC_Stdout, "*** %s: n=%d, j=%d, it=%d\n", msg, n, j, it);
10209 nodes[n]->cand->prNCand(msg);
10210 grcc_fprintf(GRCC_Stdout, "\n");
10211 erEnd("checkNode:illegal it");
10212 }
10213 }
10214}
10215#endif // CHECK
10216
10217//**************************************************************
10218// astack.cc
10219//==============================================================
10220// Assign particles to the edges and interactions to nodes.
10221// Completed graph data is saved in the form of EGraph.
10222
10223//=============================================================
10224// stack operations
10225//--------------------------------------------------------------
10226void NStack::print(const char *msg)
10227{
10228 grcc_fprintf(GRCC_Stdout, " node=%d, deg=%d, st=%d, ilist=", noden, deg, st);
10229 prilist(nilist, ilist, msg);
10230}
10231
10232//--------------------------------------------------------------
10233void EStack::print(const char *msg)
10234{
10235 grcc_fprintf(GRCC_Stdout, " edge=%d, det=%d, plist=", edgen, det);
10236 prilist(nplist, plist, msg);
10237}
10238
10239//--------------------------------------------------------------
10240AStack::AStack(int nsize, int esize)
10241{
10242 int j;
10243
10244 agraph = NULL;
10245
10246 nSize = nsize;
10247 eSize = esize;
10248 if (nSize > 0) {
10249 nStack = new NStack*[nSize];
10250 } else {
10251 nStack = NULL;
10252 }
10253 if (eSize > 0) {
10254 eStack = new EStack*[eSize];
10255 } else {
10256 eStack = NULL;
10257 }
10258
10259 nStackP = 0;
10260 eStackP = 0;
10261
10262 for (j = 0; j < nSize; j++) {
10263 nStack[j] = new NStack();
10264 }
10265
10266 for (j = 0; j < eSize; j++) {
10267 eStack[j] = new EStack();
10268 }
10269}
10270
10271//--------------------------------------------------------------
10272AStack::~AStack(void)
10273{
10274 int j;
10275
10276 if (eStack != NULL) {
10277 for (j = eSize-1; j >= 0; j--) {
10278 if (eStack[j] != NULL) {
10279 delete eStack[j];
10280 eStack[j] = NULL;
10281 }
10282 }
10283 delete[] eStack;
10284 eStack = NULL;
10285 }
10286
10287 if (nStack != NULL) {
10288 for (j = nSize-1; j >= 0; j--) {
10289 if (nStack[j] != NULL) {
10290 delete nStack[j];
10291 nStack[j] = NULL;
10292 }
10293 }
10294 delete[] nStack;
10295 nStack = NULL;
10296 }
10297}
10298
10299//--------------------------------------------------------------
10300void AStack::setAGraph(Assign *ag)
10301{
10302 agraph = ag;
10303}
10304
10305//--------------------------------------------------------------
10306void AStack::pushNode(int n)
10307{
10308 NCand *nc;
10309 NStack *ns;
10310 int j;
10311
10312#ifdef CHECK
10313 if (agraph == NULL) {
10314 erEnd("pushNode: agraph is not defined");
10315 }
10316#endif
10317 if (nStackP >= GRCC_MAXNSTACK) {
10318 erEnd("N-stack overflow (GRCC_MAXNSTACK)");
10319 }
10320 nc = agraph->nodes[n]->cand;
10321 if (nc->nilist >= GRCC_MAXMINTERACT) {
10322 erEnd("N-stack: too long list (GRCC_MAXMINTERACT)");
10323 }
10324 ns = nStack[nStackP];
10325 ns->noden = n;
10326 ns->deg = nc->deg;
10327 ns->st = nc->st;
10328 ns->nilist = nc->nilist;
10329 for (j = 0; j < nc->nilist; j++) {
10330 ns->ilist[j] = nc->ilist[j];
10331 }
10332 nStackP++;
10333}
10334
10335//--------------------------------------------------------------
10336void AStack::pushEdge(int e)
10337{
10338 ECand *ec;
10339 EStack *es;
10340 int j;
10341
10342#ifdef CHECK
10343 if (agraph == NULL) {
10344 erEnd("pushEdge: agraph is not defined");
10345 }
10346#endif
10347 if (eStackP >= GRCC_MAXESTACK) {
10348 erEnd("E-stack overflow (GRCC_MAXESTACK)");
10349 }
10350 ec = agraph->edges[e]->cand;
10351 if (ec->nplist >= GRCC_MAXMPARTICLES2) {
10352 erEnd("E-stack: Too long list (GRCC_MAXMPARTICLES)");
10353 }
10354 es = eStack[eStackP];
10355 es->edgen = e;
10356 es->det = ec->det;
10357 es->nplist = ec->nplist;
10358 for (j = 0; j < ec->nplist; j++) {
10359 es->plist[j] = ec->plist[j];
10360 }
10361 eStackP++;
10362}
10363
10364//--------------------------------------------------------------
10365void AStack::checkPoint(CheckPt sav)
10366{
10367 sav[0] = nStackP;
10368 sav[1] = eStackP;
10369}
10370
10371//--------------------------------------------------------------
10372void AStack::restoreNode(int spr)
10373{
10374 NStack *stc;
10375 int sp, n, j;
10376
10377 for (sp = nStackP-1; sp >= spr; sp--) {
10378 stc = nStack[sp];
10379 n = stc->noden;
10380 agraph->nodes[n]->cand->deg = stc->deg;
10381 agraph->nodes[n]->cand->st = stc->st;
10382 agraph->nodes[n]->cand->nilist = stc->nilist;
10383 for (j = 0; j < stc->nilist; j++) {
10384 agraph->nodes[stc->noden]->cand->ilist[j] = stc->ilist[j];
10385 }
10386 }
10387 nStackP = spr;
10388}
10389
10390//--------------------------------------------------------------
10391void AStack::restoreEdge(int spr)
10392{
10393 EStack *stc;
10394 int sp, e, j;
10395
10396 for (sp = eStackP-1; sp >= spr; sp--) {
10397 stc = eStack[sp];
10398 e = eStack[sp]->edgen;
10399 agraph->edges[e]->cand->det = stc->det;
10400 agraph->edges[e]->cand->nplist = stc->nplist;
10401 for (j = 0; j < stc->nplist; j++) {
10402 agraph->edges[e]->cand->plist[j] = stc->plist[j];
10403 }
10404 }
10405 eStackP = spr;
10406}
10407
10408//--------------------------------------------------------------
10409void AStack::restore(CheckPt sav)
10410{
10411 restoreNode(sav[0]);
10412 restoreEdge(sav[1]);
10413}
10414
10415#ifdef CHECK
10416//--------------------------------------------------------------
10417void AStack::restoreMsg(CheckPt sav, const char *msg)
10418{
10419 if (agraph == NULL) {
10420 erEnd("restore: agraph is not defined");
10421 }
10422
10423 restore(sav);
10424
10425 if (!agraph->checkCand("restore")) {
10426 grcc_fprintf(GRCC_Stdout, "restore is called from %s\n", msg);
10427 }
10428}
10429#endif
10430
10431//--------------------------------------------------------------
10432void AStack::prStack(void)
10433{
10434 int j;
10435
10436 grcc_fprintf(GRCC_Stdout, "+++ prStack : (%d, %d)", nStackP, eStackP);
10437 for (j = 0; j < nStackP; j++) {
10438 grcc_fprintf(GRCC_Stdout, "N:%4d ", j);
10439 nStack[j]->print("\n");
10440 }
10441 for (j = 0; j < eStackP; j++) {
10442 grcc_fprintf(GRCC_Stdout, "E:%4d ", j);
10443 eStack[j]->print("\n");
10444 }
10445}
10446
10447//**************************************************************
10448// class Fraction
10449//==============================================================
10450Fraction::Fraction(BigInt n, BigInt d)
10451{
10452 BigInt g;
10453
10454 g = gcd(n, d);
10455 num = n/g;
10456 den = d/g;
10457 ratio = Real(n)/Real(d);
10458}
10459
10460//--------------------------------------------------------------
10461void Fraction::print(const char *msg)
10462{
10463 double err = Abs(Real(num)/Real(den) - ratio);
10464
10465 if (err > GRCC_FRACERROR) {
10466 grcc_fprintf(GRCC_Stdout, "%ld/%ld(%g)(overflow)%s", num, den, ratio, msg);
10467 } else {
10468 grcc_fprintf(GRCC_Stdout, "%ld/%ld(%g)%s", num, den, ratio, msg);
10469 }
10470}
10471
10472//--------------------------------------------------------------
10473void Fraction::setValue(BigInt n, BigInt d)
10474{
10475 num = n;
10476 den = d;
10477 ratio = Real(n)/Real(d);
10478}
10479
10480//--------------------------------------------------------------
10481void Fraction::setValue(Fraction &f)
10482{
10483 num = f.num;
10484 den = f.den;
10485 ratio = f.ratio;
10486}
10487
10488//--------------------------------------------------------------
10489BigInt Fraction::gcd(BigInt n0, BigInt n1)
10490{
10491 BigInt nn[2], r;
10492 int nc;
10493
10494 nn[0] = Abs(n0);
10495 nn[1] = Abs(n1);
10496 nc = 0;
10497
10498 while (1) {
10499 r = nn[nc] % nn[1-nc];
10500 if (r == 0) {
10501 return nn[1-nc];
10502 }
10503 nn[nc] = r;
10504 nc = 1 - nc;
10505 }
10506}
10507
10508//--------------------------------------------------------------
10509void Fraction::normal(void)
10510{
10511 BigInt g;
10512
10513 if (den == 0) {
10514 erEnd("Fraction: den==0");
10515 }
10516 g = gcd(num, den);
10517 num /= g;
10518 den /= g;
10519 if (den < 0) {
10520 num = - num;
10521 den = - den;
10522 }
10523}
10524
10525//--------------------------------------------------------------
10526void Fraction::add(BigInt n, BigInt d)
10527{
10528 BigInt g, d1;
10529
10530 if (d < 0) {
10531 n = -n;
10532 d = -d;
10533 }
10534 if (den < 0) {
10535 num = - num;
10536 den = - den;
10537 }
10538 g = gcd(den, d);
10539 d1 = d/g;
10540 num = num * d1 + n * (den/g);
10541 den = d1*den;
10542 g = gcd(num, den);
10543 num /= g;
10544 den /= g;
10545 ratio += Real(n)/Real(d);
10546}
10547
10548//--------------------------------------------------------------
10549void Fraction::add(Fraction f)
10550{
10551 double r = ratio + f.ratio;
10552
10553 add(f.num, f.den);
10554 ratio = r;
10555}
10556
10557//--------------------------------------------------------------
10558void Fraction::sub(Fraction f)
10559{
10560 double r = ratio - f.ratio;
10561
10562 add(-f.num, f.den);
10563 ratio = r;
10564}
10565
10566//--------------------------------------------------------------
10567Bool Fraction::isEq(Fraction f)
10568{
10569 return (num == f.num && den == f.den);
10570}
10571
10572//**************************************************************
10573// common.cc
10574//==============================================================
10575
10576// Wrapper function for printing messages. This allows the use
10577// of FORM MesPrint when compiled as part of FORM, and the
10578// usual fprintf to GRCC_Stdout or GRCC_Stderr otherwise.
10579static void grcc_fprintf(FILE* out, const char* fmt, ...)
10580{
10581 va_list args;
10582 va_start(args, fmt);
10583
10584#ifndef NOFORM
10585 DUMMYUSE(out);
10586 // the second call of vsnprintf requires a copy of args
10587 va_list args_copy;
10588 va_copy(args_copy, args);
10589 // determine the required buffer size for the formatted string:
10590 const int len = vsnprintf(NULL, 0, fmt, args);
10591 char *buffer = new char[len+1];
10592 vsnprintf(buffer, len+1, fmt, args_copy);
10593 MLOCK(ErrorMessageLock);
10594 MesPrint("%s%", buffer);
10595 MUNLOCK(ErrorMessageLock);
10596 delete[] buffer;
10597 va_end(args_copy);
10598#else
10599 vfprintf(out, fmt, args);
10600#endif
10601
10602 va_end(args);
10603 return;
10604}
10605
10606static void erEnd(const char *msg)
10607{
10608 if (erExit != NULL) {
10609 (*erExit)(msg, erExitArg);
10610 }
10611 grcc_fprintf(GRCC_Stderr, "*** Error : %s\n\n", msg);
10612 GRCC_ABORT();
10613}
10614
10615#define MAXPART 100
10616//------------------------------------------------------------
10617static Bool nextPart(int nelem, int nclist, int *clist, int *nl, int *r)
10618{
10619 // Generate configuration nl[] sequentially such that
10620 // sum_j^{nclist} nl[j]*clist[j] = nelem
10621 // 0 <= nl[j] (j = 0, ..., nclis-1)
10622 // For control
10623 // for the first call : *r < 0
10624 // otherwise : *r >= 0, nl is the last configuration
10625 // Returns
10626 // True : succeeded
10627 // False : no more configuration
10628
10629 int rem, pn, j, c;
10630
10631 if (*r < 0) {
10632 *r = 0;
10633 rem = nelem;
10634 for (j = 0; j < nclist; j++) {
10635 nl[j] = rem/clist[j];
10636 rem -= nl[j]*clist[j];
10637 }
10638 if (rem == 0) {
10639 return True;
10640 }
10641 } else {
10642 rem = 0;
10643 }
10644 for (c = 0; c < MAXPART; c++) {
10645 rem += nl[nclist-1]*clist[nclist-1];
10646 for (pn = nclist-2; pn >= 0 && nl[pn] == 0; pn--) {
10647 ;
10648 }
10649 if (pn < 0) {
10650 return False;
10651 }
10652 rem += clist[pn];
10653 nl[pn]--;
10654 for (j = pn+1; j < nclist; j++) {
10655 nl[j] = rem/clist[j];
10656 rem -= nl[j]*clist[j];
10657 }
10658 if (rem == 0) {
10659 return True;
10660 }
10661 }
10662 erEnd("*** nextPart : illegal control : too many repetition");
10663 return False;
10664}
10665
10666//------------------------------------------------------------
10667static int *intdup(int n, int *a)
10668{
10669 int *r, j;
10670
10671 r = new int[n];
10672 for (j = 0; j < n; j++) {
10673 r[j] = a[j];
10674 }
10675 return r;
10676}
10677
10678//------------------------------------------------------------
10679static int *delintdup(int *a)
10680{
10681 if (a != NULL) {
10682 delete[] a;
10683 }
10684 return NULL;
10685}
10686
10687//------------------------------------------------------------
10688static void prilist(int n, const int *a, const char *msg)
10689{
10690 grcc_fprintf(GRCC_Stdout, "[");
10691 for (int j = 0; j < n; j++) {
10692 if (j!=0) grcc_fprintf(GRCC_Stdout, ", ");
10693 grcc_fprintf(GRCC_Stdout, "%d", a[j]);
10694 }
10695 grcc_fprintf(GRCC_Stdout, "]%s", msg);
10696}
10697
10698//------------------------------------------------------------
10699static int nextPerm(int nelem, int nclass, int *cl, int *r, int *q, int *p, int count)
10700{
10701 // Sequential generation of all permutations.
10702
10703 int j, k, n, e, t;
10704 Bool b;
10705
10706 for (j = 0; j < nelem; j++) {
10707 p[j] = j;
10708 }
10709 if (count < 1) {
10710 for (j = 0; j < nelem; j++) {
10711 q[j] = 0;
10712 r[j] = 0;
10713 }
10714 j = 0;
10715 for (k = 0; k < nclass; k++) {
10716 n = cl[k];
10717 for (e = 0; e < n; e++) {
10718 r[j] = n - e - 1;
10719 j++;
10720 }
10721 }
10722#ifdef CHECK
10723 if (j != nelem) {
10724 erEnd("inconsistent # elements");
10725 }
10726#endif
10727 return 1;
10728 }
10729 b = False;
10730 for (j = nelem-1; j >= 0; j--) {
10731 if (q[j] < r[j]) {
10732 for (k = j+1; k < nelem; k++) {
10733 q[k] = 0;
10734 }
10735 q[j]++;
10736 b = True;
10737 break;
10738 }
10739 }
10740 if (!b) {
10741 return (-count);
10742 }
10743
10744 for (j = 0; j < nelem; j++) {
10745 k = j + q[j];
10746 t = p[j];
10747 p[j] = p[k];
10748 p[k] = t;
10749 }
10750 return count + 1;
10751}
10752
10753//------------------------------------------------------------
10754static BigInt factorial(int n)
10755{
10756 // returns 1 for n < 1
10757
10758 int r, j;
10759
10760 r = 1;
10761 for (j = 2; j <= n; j++) {
10762 r *= j;
10763 }
10764 return r;
10765}
10766
10767//------------------------------------------------------------
10768static BigInt ipow(int n, int p)
10769{
10770 int r, j;
10771
10772 r = 1;
10773 for (j = 0; j < p; j++) {
10774 r *= n;
10775 }
10776 return r;
10777}
10778
10779//------------------------------------------------------------
10780static int *newArray(int size, int val)
10781{
10782 // memory allocation of an array
10783
10784 int *a, j;
10785
10786 a = new int[size];
10787 for (j = 0; j < size; j++) {
10788 a[j] = val;
10789 }
10790 return a;
10791}
10792
10793//------------------------------------------------------------
10794static int *deleteArray(int *a)
10795{
10796 // memory allocation of an array
10797
10798 delete[] a;
10799 return NULL;
10800}
10801
10802//------------------------------------------------------------
10803static int **newMat(int n0, int n1, int val)
10804{
10805 int **m, j, k;
10806
10807 m = new int*[n0];
10808 for (j = 0; j < n0; j++) {
10809 m[j] = new int[n1];
10810 for (k = 0; k < n1; k++) {
10811 m[j][k] = val;
10812 }
10813 }
10814 return m;
10815}
10816
10817//------------------------------------------------------------
10818static int **deleteMat(int **m, int n0)
10819{
10820 int j;
10821
10822 for (j = n0-1; j >= 0; j--) {
10823 delete[] m[j];
10824 }
10825 delete[] m;
10826
10827 return NULL;
10828}
10829
10830//------------------------------------------------------------
10831static void bsort(int n, int *ord, int *a)
10832{
10833 int i, j, t;
10834
10835 for (j = n-1; j > 0; j--) {
10836 for (i = 0; i < j; i++) {
10837 if(a[ord[i+1]] < a[ord[i]]) {
10838 t = ord[i];
10839 ord[i] = ord[i+1];
10840 ord[i+1] = t;
10841 }
10842 }
10843 }
10844}
10845
10846//--------------------------------------------------------------
10847static void prMomStr(int mom, const char *ms, int mn)
10848{
10849 if (mom == 0) {
10850 return;
10851 } else if (mom == 1) {
10852 grcc_fprintf(GRCC_Stdout, " + %s%d", ms, mn);
10853 } else if (mom > 0) {
10854 grcc_fprintf(GRCC_Stdout, " + %d*%s%d", mom, ms, mn);
10855 } else if (mom == -1) {
10856 grcc_fprintf(GRCC_Stdout, " - %s%d", ms, mn);
10857 } else {
10858 grcc_fprintf(GRCC_Stdout, " - %d*%s%d", -mom, ms, mn);
10859 }
10860}
10861
10862//--------------------------------------------------------------
10863static void prIntArray(int n, int *p, const char *msg)
10864{
10865
10866 int j;
10867
10868 grcc_fprintf(GRCC_Stdout, "[");
10869 for (j = 0; j < n; j++) {
10870 if (j!=0) grcc_fprintf(GRCC_Stdout, ", ");
10871 grcc_fprintf(GRCC_Stdout, "%2d", p[j]);
10872 }
10873 grcc_fprintf(GRCC_Stdout, "]%s", msg);
10874}
10875
10876//--------------------------------------------------------------
10877static void prIntArrayErr(int n, int *p, const char *msg)
10878{
10879
10880 int j;
10881
10882 grcc_fprintf(GRCC_Stderr, "[");
10883 for (j = 0; j < n; j++) {
10884 if (j!=0) grcc_fprintf(GRCC_Stderr, ", ");
10885 grcc_fprintf(GRCC_Stderr, "%2d", p[j]);
10886 }
10887 grcc_fprintf(GRCC_Stderr, "]%s", msg);
10888}
10889
10890//--------------------------------------------------------------
10891static void sortrec(int l, int r, int *a)
10892{
10893 // quick sort : taken from N. Wirth
10894 int i,j, x, w;
10895
10896 i = l;
10897 j = r;
10898 x = a[(l+r)/2];
10899 do {
10900 while(a[i] < x) i++;
10901 while(x < a[j]) j--;
10902 if (i <= j) {
10903 w = a[i]; a[i] = a[j]; a[j] = w;
10904 i++; j--;
10905 }
10906 } while (i < j);
10907 if (l < j) sortrec(l, j, a);
10908 if (i < r) sortrec(i, r, a);
10909}
10910
10911//--------------------------------------------------------------
10912static void sorti(int size, int *a)
10913{
10914 sortrec(0, size-1, a);
10915}
10916
10917//------------------------------------------------------------
10918static int sortb(int n, int *a)
10919{
10920 int i, j, t, nswap;
10921
10922 nswap = 0;
10923 for (j = n-1; j > 0; j--) {
10924 for (i = 0; i < j; i++) {
10925 if(a[i+1] < a[i]) {
10926 t = a[i];
10927 a[i] = a[i+1];
10928 a[i+1] = t;
10929 nswap++;
10930 }
10931 }
10932 }
10933
10934 // the sign of the permutation is (-1)^{nswap}
10935 return nswap;
10936}
10937
10938#ifdef CHECK
10939//--------------------------------------------------------------
10940static Bool isIn(int n, int *a, int v)
10941{
10942 int j;
10943
10944 for (j = 0; j < n; j++) {
10945 if (a[j] == v) {
10946 return True;
10947 }
10948 }
10949 return False;
10950}
10951#endif
10952
10953//--------------------------------------------------------------
10954static int intSetAdd(int n, int *a, int v, const int size)
10955{
10956 // Add 'v' into 'a'.
10957 // 'n' is the current # of element.
10958 // 'a' is assumed sorted without duplicated elements.
10959 // Size of 'a' should be large enough.
10960
10961 int j, k;
10962
10963 if (n >= size) {
10964 grcc_fprintf(GRCC_Stderr, "*** intSetAdd : array out of range (>%d)\n", size);
10965 erEnd("intSetAdd : array out of range (GRCC_MAXPSLIST)");
10966 }
10967 for (j = 0; j < n; j++) {
10968 if (a[j] > v) {
10969 break;
10970 } else if (a[j] == v) {
10971 return n;
10972 }
10973 }
10974
10975 // 'j' can be equal to 'n'
10976 for (k = n-1; k >= j; k--) {
10977 a[k+1] = a[k];
10978 }
10979 a[j] = v;
10980 return n+1;
10981}
10982
10983//--------------------------------------------------------------
10984static int intSListAdd(int n, int *a, int v, const int size)
10985{
10986 // Add 'v' into 'a'.
10987 // 'n' is the current # of element.
10988 // 'a' is assumed sorted without duplicated elements.
10989 // Size of 'a' should be large enough.
10990
10991 int j, k;
10992
10993 if (n >= size) {
10994 grcc_fprintf(GRCC_Stderr, "*** intSListAdd : array out of range (>%d)\n", size);
10995 erEnd("intSListAdd : array out of range");
10996 }
10997 for (j = 0; j < n; j++) {
10998 if (a[j] >= v) {
10999 break;
11000 }
11001 }
11002
11003 // 'j' can be equal to 'n'
11004 for (k = n-1; k >= j; k--) {
11005 a[k+1] = a[k];
11006 }
11007 a[j] = v;
11008 return n+1;
11009}
11010
11011//--------------------------------------------------------------
11012static int cmpArray(int na, int *a, int nb, int *b)
11013{
11014 int j, cmp;
11015
11016 cmp = na - nb;
11017 if (cmp != 0) {
11018 return cmp;
11019 }
11020 for (j = 0; j < na; j++) {
11021 cmp = a[j] - b[j];
11022 if (cmp != 0) {
11023 return cmp;
11024 }
11025 }
11026 return 0;
11027}
11028
11029//--------------------------------------------------------------
11030static Bool leqArray(int n, int *a, int *b)
11031{
11032 int j;
11033
11034 for (j = 0; j < n; j++) {
11035 if (a[j] > b[j]) {
11036 return False;
11037 }
11038 }
11039 return True;
11040}
11041
11042//--------------------------------------------------------------
11043// convert list to sorted list
11044static int toSList(int n, int *a)
11045{
11046 sorti(n, a);
11047 return n;
11048}
11049
11050//--------------------------------------------------------------
11051// as set operation assuming a and b are sorted with duplication
11052// p := a \ b; q := a \cap b; r := b \ a;
11053// p, q, r are sorted without duplication
11054static void listDiff(int na, int *a, int nb, int *b, int *np, int *p, int *nq, int *q, int *nr, int *r)
11055{
11056 int ja, jb;
11057
11058 *np = *nq = *nr = 0;
11059 ja = jb = 0;
11060 while (ja < na && jb < nb) {
11061 while (ja < na && a[ja] < b[jb]) {
11062 p[(*np)++] = a[ja++];
11063 }
11064 while (jb < nb && b[jb] < a[ja]) {
11065 r[(*nr)++] = b[jb++];
11066 }
11067 if (ja < na && jb < nb && a[ja] == b[jb]) {
11068 q[(*nq)++] = a[ja++];
11069 jb++;
11070 }
11071 }
11072 for (; ja < na; ja++) {
11073 p[(*np)++] = a[ja];
11074 }
11075 for (; jb < nb; jb++) {
11076 r[(*nr)++] = b[jb];
11077 }
11078}
11079
11080//--------------------------------------------------------------
11081static int isSubSList(int na, int *a, int nb, int *b)
11082{
11083 int ja, jb;
11084
11085 ja = jb = 0;
11086 while (ja < na && jb < nb) {
11087 for ( ; jb < nb && b[jb] < a[ja]; jb++) {
11088 ;
11089 }
11090 if (jb >= nb || b[jb] > a[ja]) {
11091 return False;
11092 }
11093 for ( ; jb < nb && ja < na && b[jb] == a[ja]; jb++, ja++) {
11094 ;
11095 }
11096 }
11097 return (ja >= na);
11098}
11099
11100//--------------------------------------------------------------
11101static int subtrSet(int na, int *a, int nb, int *b, int *c, int size)
11102{
11103 // set subtraction 'c' := 'a' - 'b'.
11104 // 'a' and 'b' are sorted lists (not always unique)
11105 // 'c' is the set (sorted and unique elements)
11106
11107 int ja, jb, jc;
11108
11109 jc = 0;
11110 ja = jb = 0;
11111 while (ja < na && jb < nb) {
11112 while (ja < na && a[ja] < b[jb]) {
11113 if (jc == 0 || c[jc-1] != a[ja]) {
11114 if (jc >= size) {
11115 erEnd("subsutSet: too small size of array (GRCC_MAXPSLIST)");
11116 }
11117 c[jc++] = a[ja];
11118 }
11119 ja++;
11120 }
11121 while (jb < nb && b[jb] < a[ja]) {
11122 ;
11123 }
11124 if (ja < na && jb < nb && a[ja] == b[jb]) {
11125 ja++;
11126 jb++;
11127 }
11128 }
11129 for (; ja < na; ja++) {
11130 if (jc == 0 || c[jc-1] != a[ja]) {
11131 c[jc++] = a[ja];
11132 }
11133 }
11134 return jc;
11135}
11136
11137// } ) ]
Definition grcc.h:1164
Definition grcc.h:1140
Definition grcc.h:1124
Definition grcc.h:562
Definition grcc.h:612
Definition grcc.h:624
Definition grcc.h:528
Definition grcc.h:936
Definition grcc.h:951
Definition grcc.h:1002
Definition grcc.h:793
Definition grcc.h:771
Definition grcc.h:284
Definition grcc.h:1106
Definition grcc.h:166
Definition grcc.h:732