• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

form-dev / form / 15701338753

17 Jun 2025 07:49AM UTC coverage: 50.382% (-0.004%) from 50.386%
15701338753

Pull #662

github

web-flow
Merge f1f68c050 into 207386593
Pull Request #662: Cleanup: change VOID into void

178 of 245 new or added lines in 34 files covered. (72.65%)

2 existing lines in 1 file now uncovered.

41784 of 82935 relevant lines covered (50.38%)

2640008.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

20.76
/sources/lus.c
1
/** @file lus.c
2
 * 
3
 *        Routines to find loops in index contractions.
4
 *        These routines allow for a category of topological statements.
5
 *        They were originally developed for the color library.
6
 */
7
/* #[ License : */
8
/*
9
 *   Copyright (C) 1984-2023 J.A.M. Vermaseren
10
 *   When using this file you are requested to refer to the publication
11
 *   J.A.M.Vermaseren "New features of FORM" math-ph/0010025
12
 *   This is considered a matter of courtesy as the development was paid
13
 *   for by FOM the Dutch physics granting agency and we would like to
14
 *   be able to track its scientific use to convince FOM of its value
15
 *   for the community.
16
 *
17
 *   This file is part of FORM.
18
 *
19
 *   FORM is free software: you can redistribute it and/or modify it under the
20
 *   terms of the GNU General Public License as published by the Free Software
21
 *   Foundation, either version 3 of the License, or (at your option) any later
22
 *   version.
23
 *
24
 *   FORM is distributed in the hope that it will be useful, but WITHOUT ANY
25
 *   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
26
 *   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
27
 *   details.
28
 *
29
 *   You should have received a copy of the GNU General Public License along
30
 *   with FORM.  If not, see <http://www.gnu.org/licenses/>.
31
 */
32
/* #] License : */ 
33
/*
34
          #[ Includes : lus.c
35
*/
36

37
#include "form3.h"
38

39
/*
40
          #] Includes : 
41
          #[ Lus :
42

43
        Routine to find loops.
44
        Mode: 0: Just tell whether there is such a loop.
45
              1: Take out the functions and replace by outfun with the
46
                 remaining arguments of the loop function
47
              > AM.OffsetIndex: This index must be included in the loop.
48
              < -AM.OffsetIndex: This index must be included in the loop. Replace.
49
        Return value: 0: no loop. 1: there is/was such a loop.
50
        funnum: the function(s) in which we look for a loop.
51
        numargs: the number of arguments admissible in the function.
52
        outfun: the output function in case of a substitution.
53
        loopsize: the size of the loop we are looking for.
54
                  if < 0 we look for all loops.
55
*/
56

57
int Lus(WORD *term, WORD funnum, WORD loopsize, WORD numargs, WORD outfun, WORD mode)
12✔
58
{
59
        GETIDENTITY
8✔
60
        WORD *w, *t, *tt, *m, *r, **loc, *tstop, minloopsize;
12✔
61
        int nfun, i, j, jj, k, n, sign = 0, action = 0, L, ten, ten2, totnum,
12✔
62
        sign2, *alist, *wi, mini, maxi, medi = 0;
12✔
63
        if ( numargs <= 1 ) return(0);
12✔
64
        GETSTOP(term,tstop);
12✔
65
/*
66
        First count the number of functions with the proper number of arguments.
67
*/
68
        t = term+1; nfun = 0;
12✔
69
        if ( ( ten = functions[funnum-FUNCTION].spec ) >= TENSORFUNCTION ) {
12✔
70
                while ( t < tstop ) {
×
71
                        if ( *t == funnum && t[1] == FUNHEAD+numargs ) { nfun++; }
×
72
                        t += t[1];
×
73
                }
74
        }
75
        else {
76
                while ( t < tstop ) {
66✔
77
                        if ( *t == funnum ) {
54✔
78
                                i = 0; m = t+FUNHEAD; t += t[1];
54✔
79
                                while ( m < t ) { i++; NEXTARG(m) }
216✔
80
                                if ( i == numargs ) nfun++;
54✔
81
                        }
82
                        else t += t[1];
×
83
                }
84
        }
85
        if ( loopsize < 0 ) minloopsize = 2;
12✔
86
        else                minloopsize = loopsize;
6✔
87
        if ( funnum < minloopsize ) return(0); /* quick abort */
12✔
88
        if ( ((functions[funnum-FUNCTION].symmetric) & ~REVERSEORDER) == ANTISYMMETRIC ) sign = 1;
12✔
89
        if ( mode == 1 || mode < 0 ) {
12✔
90
                ten2 = functions[outfun-FUNCTION].spec >= TENSORFUNCTION;
12✔
91
        }
92
        else ten2 = -1;
93
/*
94
        Allocations:
95
*/
96
        if ( AN.numflocs < funnum ) {
12✔
97
                if ( AN.funlocs ) M_free(AN.funlocs,"Lus: AN.funlocs");
12✔
98
                AN.numflocs = funnum;
12✔
99
                AN.funlocs = (WORD **)Malloc1(sizeof(WORD *)*AN.numflocs,"Lus: AN.funlocs");
12✔
100
        }
101
        if ( AN.numfargs < funnum*numargs ) {
12✔
102
                if ( AN.funargs ) M_free(AN.funargs,"Lus: AN.funargs");
12✔
103
                AN.numfargs = funnum*numargs;
12✔
104
                AN.funargs = (int *)Malloc1(sizeof(int *)*AN.numfargs,"Lus: AN.funargs");
12✔
105
        }
106
/*
107
        Make a list of relevant indices
108
*/
109
        alist = AN.funargs; loc = AN.funlocs;
12✔
110
        t = term+1;
12✔
111
        if ( ten >= TENSORFUNCTION ) {
12✔
112
                while ( t < tstop ) {
×
113
                        if ( *t == funnum && t[1] == FUNHEAD+numargs ) {
×
114
                                *loc++ = t;
×
115
                                t += FUNHEAD;
×
116
                                j = i = numargs; while ( --i >= 0 ) {
×
117
                                        if ( *t >= AM.OffsetIndex && 
×
118
                                                ( *t >= AM.OffsetIndex+WILDOFFSET ||
×
119
                                                indices[*t-AM.OffsetIndex].dimension != 0 ) ) {
×
120
                                                *alist++ = *t++; j--;
×
121
                                        }
122
                                        else t++;
×
123
                                }
124
                                while ( --j >= 0 ) *alist++ = -1;
×
125
                        }
126
                        else t += t[1];
×
127
                }
128
        }
129
        else {
130
                nfun = 0;
131
                while ( t < tstop ) {
66✔
132
                        if ( *t == funnum ) {
54✔
133
                                w = t;
54✔
134
                                i = 0; m = t+FUNHEAD; t += t[1];
54✔
135
                                while ( m < t ) { i++; NEXTARG(m) }
216✔
136
                                if ( i == numargs ) {
54✔
137
                                        m = w + FUNHEAD;
138
                                        while ( m < t ) {
216✔
139
                                                if ( *m == -INDEX && m[1] >= AM.OffsetIndex && 
162✔
140
                                                ( m[1] >= AM.OffsetIndex+WILDOFFSET ||
162✔
141
                                                indices[m[1]-AM.OffsetIndex].dimension != 0 ) ) {
162✔
142
                                                        *alist++ = m[1]; m += 2; i--;
162✔
143
                                                }
144
                                                else if ( ten2 >= TENSORFUNCTION && *m != -INDEX
×
145
                                                 && *m != -VECTOR && *m != -MINVECTOR &&
×
146
                                                ( *m != -SNUMBER || *m < 0 || *m >= AM.OffsetIndex ) ) {
147
                                                        i = numargs; break;
148
                                                }
149
                                                else { NEXTARG(m) }
×
150
                                        }
151
                                        if ( i < numargs ) {
54✔
152
                                                *loc++ = w;
54✔
153
                                                nfun++;
54✔
154
                                                while ( --i >= 0 ) *alist++ = -1;
54✔
155
                                        }
156
                                }
157
                        }
158
                        else t += t[1];
×
159
                }
160
                if ( nfun < minloopsize ) return(0);
12✔
161
        }
162
/*
163
        We have now nfun objects. Not all indices may be usable though.
164
        If the list is not long, we use a quadratic algorithm to remove
165
        indices and vertices that cannot be used. If it becomes large we
166
        sort the list of available indices (and their multiplicity) and
167
        work with binary searches.
168
*/
169
        alist = AN.funargs; totnum = numargs*nfun;
12✔
170
        if ( nfun > 7 ) {
12✔
171
                if ( AN.funisize < totnum ) {
×
172
                        if ( AN.funinds ) M_free(AN.funinds,"AN.funinds");
×
173
                        AN.funisize = (totnum*3)/2;
×
174
                        AN.funinds = (int *)Malloc1(AN.funisize*2*sizeof(int),"AN.funinds");
×
175
                }
176
                i = totnum; n = 0; wi = AN.funinds;
×
177
                while ( --i >= 0 ) {
×
178
                        if ( *alist >= 0 ) { n++; *wi++ = *alist; *wi++ = 1; }
×
179
                        alist++;
×
180
                }
181
                n = SortTheList(AN.funinds,n);
×
182
                do {
×
183
                        action = 0;
×
184
                        for ( i = 0; i < nfun; i++ ) {
×
185
                                alist = AN.funargs + i*numargs;
×
186
                                jj = numargs;
×
187
                                for ( j = 0; j < jj; j++ ) {
×
188
                                        if ( alist[j] < 0 ) break;
×
189
                                        mini = 0; maxi = n-1;
×
190
                                        while ( mini <= maxi ) {
×
191
                                                medi = (mini + maxi) / 2; k = AN.funinds[2*medi];
×
192
                                                if ( alist[j] > k ) mini = medi + 1;
×
193
                                                else if ( alist[j] < k ) maxi = medi - 1;
×
194
                                                else break;
195
                                        }
196
                                        if ( AN.funinds[2*medi+1] <= 1 ) {
×
197
                                                (AN.funinds[2*medi+1])--;
×
198
                                                jj--; k = j; while ( k < jj ) { alist[k] = alist[k+1]; k++; }
×
199
                                                alist[jj] = -1; j--;
×
200
                                        }
201
                                }
202
                                if ( jj < 2 ) {
×
203
                                        if ( jj == 1 ) {
×
204
                                                mini = 0; maxi = n-1;
×
205
                                                while ( mini <= maxi ) {
×
206
                                                        medi = (mini + maxi) / 2; k = AN.funinds[2*medi];
×
207
                                                        if ( alist[0] > k ) mini = medi + 1;
×
208
                                                        else if ( alist[0] < k ) maxi = medi - 1;
×
209
                                                        else break;
210
                                                }
211
                                                (AN.funinds[2*medi+1])--;
×
212
                                                if ( AN.funinds[2*medi+1] == 1 ) action++;
×
213
                                        }
214
                                        nfun--; totnum -= numargs; AN.funlocs[i] = AN.funlocs[nfun];
×
215
                                        wi = AN.funargs + nfun*numargs;
×
216
                                        for ( j = 0; j < numargs; j++ ) alist[j] = *wi++;
×
217
                                        i--;
×
218
                                }
219
                        }
220
                } while ( action );
×
221
        }
222
        else {
223
                for ( i = 0; i < totnum; i++ ) {
174✔
224
                        if ( alist[i] == -1 ) continue;
162✔
225
                        for ( j = 0; j < totnum; j++ ) {
1,332✔
226
                                if ( alist[j] == alist[i] && j != i ) break;
1,302✔
227
                        }
228
                        if ( j >= totnum ) alist[i] = -1;
162✔
229
                }
230
                do {
18✔
231
                        action = 0;
18✔
232
                        for ( i = 0; i < nfun; i++ ) {
90✔
233
                                alist = AN.funargs + i*numargs;
72✔
234
                                n = numargs;
72✔
235
                                for ( k = 0; k < n; k++ ) {
288✔
236
                                        if ( alist[k] < 0 ) { alist[k--] = alist[--n]; alist[n] = -1; }
216✔
237
                                }
238
                                if ( n <= 1 ) {
72✔
239
                                        if ( n == 1 ) { j = alist[0]; }
6✔
240
                                        else j = -1;
241
                                        nfun--; totnum -= numargs; AN.funlocs[i] = AN.funlocs[nfun];
6✔
242
                                        wi = AN.funargs + nfun * numargs;
6✔
243
                                        for ( k = 0; k < numargs; k++ ) alist[k] = wi[k];
24✔
244
                                        i--;
6✔
245
                                        if ( j >= 0 ) {
6✔
246
                                                for ( k = 0, jj = 0, wi = AN.funargs; k < totnum; k++, wi++ ) {
60✔
247
                                                        if ( *wi == j ) { jj++; if ( jj > 1 ) break; }
54✔
248
                                                }
249
                                                if ( jj <= 1 ) {
6✔
250
                                                        for ( k = 0, wi = AN.funargs; k < totnum; k++, wi++ ) {
60✔
251
                                                                if ( *wi == j ) { *wi = -1; action = 1; }
54✔
252
                                                        }
253
                                                }
254
                                        }
255
                                }
256
                        }
257
                } while ( action );
18✔
258
        }
259
        if ( nfun < minloopsize ) return(0);
12✔
260
/*
261
        Now we have nfun objects, each with at least 2 indices, each of which
262
        occurs at least twice in our list. There will be a loop!
263
*/
264
        if ( mode != 0 && mode != 1 ) {
12✔
265
                if ( mode > 0 ) AN.tohunt =  mode - 5;
×
266
                else            AN.tohunt = -mode - 5;
×
267
                AN.nargs = numargs; AN.numoffuns = nfun;
×
268
                i = 0;
×
269
                if ( loopsize < 0 ) {
×
270
                        if ( loopsize == -1 ) k = nfun;
×
271
                        else { k = -loopsize-1; if ( k > nfun ) k = nfun; }
×
272
                        for ( L = 2; L <= k; L++ ) {
×
273
                                if ( FindLus(0,L,AN.tohunt) ) goto Success;
×
274
                        }
275
                }
276
                else if ( FindLus(0,loopsize,AN.tohunt) ) { L = loopsize; goto Success; }
×
277
        }
278
        else {
279
                AN.nargs = numargs; AN.numoffuns = nfun;
12✔
280
                if ( loopsize < 0 ) {
12✔
281
                        jj = 2; k = nfun;
6✔
282
                        if ( loopsize < -1 ) { k = -loopsize-1; if ( k > nfun ) k = nfun; }
6✔
283
                }
284
                else { jj = k = loopsize; }
285
                for ( L = jj; L <= k; L++ ) {
12✔
286
                        for ( i = 0; i <= nfun-L; i++ ) {
30✔
287
                                alist = AN.funargs + i * numargs;
30✔
288
                                for ( jj = 0; jj < numargs; jj++ ) {
90✔
289
                                        if ( alist[jj] < 0 ) continue;
72✔
290
                                        AN.tohunt = alist[jj];
66✔
291
                                        for ( j = jj+1; j < numargs; j++ ) {
132✔
292
                                                if ( alist[j] < 0 ) continue;
78✔
293
                                                if ( FindLus(i+1,L-1,alist[j]) ) {
66✔
294
                                                        alist[0] = alist[jj];
12✔
295
                                                        alist[1] = alist[j];
12✔
296
                                                        goto Success;
12✔
297
                                                }
298
                                        }
299
                                }
300
                        }
301
                }
302
        }
303
        return(0);
304
Success:;
12✔
305
        if ( mode == 0 || mode > 1 ) return(1);
12✔
306
/*
307
        Now we have to make the replacement and fix the potential sign
308
*/
309
        sign2 = 1;
12✔
310
        wi = AN.funargs + i*numargs; loc = AN.funlocs + i;
12✔
311
        for ( k = 0; k < L; k++ ) *(loc[k]) = -1;
42✔
312
        if ( AT.WorkPointer < term + *term ) AT.WorkPointer = term + *term;
12✔
313
        w = AT.WorkPointer + 1;
12✔
314
        m = t = term + 1;
12✔
315
        while ( t < tstop ) {
30✔
316
                if ( *t == -1 ) break;
30✔
317
                t += t[1];
18✔
318
        }
319
        while ( m < t ) *w++ = *m++;
174✔
320
        r = w;
12✔
321
        *w++ = outfun;
12✔
322
        w++;
12✔
323
        *w++ = DIRTYFLAG;
12✔
324
        FILLFUN3(w)
325
        if ( functions[outfun-FUNCTION].spec >= TENSORFUNCTION ) {
12✔
326
                if ( ten >= TENSORFUNCTION ) {
×
327
                        for ( i = 0; i < L; i++ ) {
×
328
                                alist = wi + i*numargs;
×
329
                                m = loc[i] + FUNHEAD;
×
330
                                for ( k = 0; k < numargs; k++ ) {
×
331
                                        if ( m[k] == alist[0] ) {
×
332
                                                if ( k != 0 ) {
×
333
                                                        jj = m[k]; m[k] = m[0]; m[0] = jj;
×
334
                                                        sign = -sign;
×
335
                                                }
336
                                                break;
337
                                        }
338
                                }
339
                                for ( k = 1; k < numargs; k++ ) {
×
340
                                        if ( m[k] == alist[1] ) {
×
341
                                                if ( k != 1 ) {
×
342
                                                        jj = m[k]; m[k] = m[1]; m[1] = jj;
×
343
                                                        sign = -sign;
×
344
                                                }
345
                                                break;
346
                                        }
347
                                }
348
                                m += 2;
×
349
                                for ( k = 2; k < numargs; k++ ) *w++ = *m++;
×
350
                        }
351
                }
352
                else {
353
                        WORD *t1, *t2, *t3;
354
                        for ( i = 0; i < L; i++ ) {
×
355
                                alist = wi + i*numargs;
×
356
                                tt = loc[i];
×
357
                                m = tt + FUNHEAD;
×
358
                                for ( k = 0; k < numargs; k++ ) {
×
359
                                        if ( *m == -INDEX && m[1] == alist[0] ) {
×
360
                                                if ( k != 0 ) {
×
361
                                                        if ( ( k & 1 ) != 0 ) sign = -sign;
×
362
/*
363
                                                        now move to position 0
364
*/
365
                                                        t2 = m+2; t1 = m; t3 = tt+FUNHEAD;
×
366
                                                        while ( t1 > t3 ) { *--t2 = *--t1; }
×
367
                                                        t3[0] = -INDEX; t3[1] = alist[0];
×
368
                                                }
369
                                                break;
370
                                        }
371
                                        NEXTARG(m)
×
372
                                }
373
                                m = tt + FUNHEAD + 2;
×
374
                                for ( k = 1; k < numargs; k++ ) {
×
375
                                        if ( *m == -INDEX && m[1] == alist[1] ) {
×
376
                                                if ( k != 1 ) {
×
377
                                                        if ( ( k & 1 ) == 0 ) sign = -sign;
×
378
/*
379
                                                        now move to position 1
380
*/
381
                                                        t2 = m+2; t1 = m; t3 = tt+FUNHEAD+2;
×
382
                                                        while ( t1 > t3 ) { *--t2 = *--t1; }
×
383
                                                        t3[0] = -INDEX; t3[1] = alist[1];
×
384
                                                }
385
                                                break;
386
                                        }
387
                                        NEXTARG(m)
×
388
                                }
389
/*
390
                                now copy the remaining arguments to w
391
                                keep in mind that the output function is a tensor!
392
*/
393
                                t1 = tt + FUNHEAD + 4;
×
394
                                t2 = tt + tt[1];
×
395
                                while ( t1 < t2 ) {
×
396
                                        if ( *t1 == -INDEX || *t1 == -VECTOR ) {
×
397
                                                *w++ = t1[1]; t1 += 2;
×
398
                                        }
399
                                        else if ( *t1 == -MINVECTOR ) {
×
400
                                                *w++ = t1[1]; t1 += 2; sign2 = -sign2;
×
401
                                        }
402
                                        else if ( ( *t1 == -SNUMBER ) && ( t1[1] >= 0 ) && ( t1[1] < AM.OffsetIndex ) ) {
×
403
                                                *w++ = t1[1]; t1 += 2; sign2 = -sign2;
×
404
                                        }
405
                                        else {
406
                                                MLOCK(ErrorMessageLock);
×
407
                                                MesPrint("Illegal attempt to use a non-index-like argument in a tensor in ReplaceLoop statement");
×
408
                                                MUNLOCK(ErrorMessageLock);
×
409
                                                Terminate(-1);
×
410
                                        }
411
                                }
412
                        }
413
                }
414
        }
415
        else {
416
                if ( ten >= TENSORFUNCTION ) {
12✔
417
                        for ( i = 0; i < L; i++ ) {
×
418
                                alist = wi + i*numargs;
×
419
                                m = loc[i] + FUNHEAD;
×
420
                                for ( k = 0; k < numargs; k++ ) {
×
421
                                        if ( m[k] == alist[0] ) {
×
422
                                                if ( k != 0 ) {
×
423
                                                        jj = m[k]; m[k] = m[0]; m[0] = jj;
×
424
                                                        sign = -sign;
×
425
                                                        break;
×
426
                                                }
427
                                        }
428
                                }
429
                                for ( k = 1; k < numargs; k++ ) {
×
430
                                        if ( m[k] == alist[1] ) {
×
431
                                                if ( k != 1 ) {
×
432
                                                        jj = m[k]; m[k] = m[1]; m[1] = jj;
×
433
                                                        sign = -sign;
×
434
                                                        break;
×
435
                                                }
436
                                        }
437
                                }
438
                                m += 2;
×
439
                                for ( k = 2; k < numargs; k++ ) {
×
440
                                        if ( *m >= AM.OffsetIndex ) { *w++ = -INDEX; }
×
441
                                        else if ( *m < 0 ) { *w++ = -VECTOR; }
×
442
                                        else { *w = -SNUMBER; }
×
443
                                        *w++ = *m++;
×
444
                                }
445
                        }
446
                }
447
                else {
448
                        WORD *t1, *t2, *t3;
449
                        for ( i = 0; i < L; i++ ) {
42✔
450
                                alist = wi + i*numargs;
30✔
451
                                tt = loc[i];
30✔
452
                                m = tt + FUNHEAD;
30✔
453
                                for ( k = 0; k < numargs; k++ ) {
54✔
454
                                        if ( *m == -INDEX && m[1] == alist[0] ) {
54✔
455
                                                if ( k != 0 ) {
30✔
456
                                                        if ( ( k & 1 ) != 0 ) sign = -sign;
18✔
457
/*
458
                                                        now move to position 0
459
*/
460
                                                        t2 = m+2; t1 = m; t3 = tt+FUNHEAD;
18✔
461
                                                        while ( t1 > t3 ) { *--t2 = *--t1; }
66✔
462
                                                        t3[0] = -INDEX; t3[1] = alist[0];
18✔
463
                                                }
464
                                                break;
465
                                        }
466
                                        NEXTARG(m)
24✔
467
                                }
468
                                m = tt + FUNHEAD + 2;
30✔
469
                                for ( k = 1; k < numargs; k++ ) {
42✔
470
                                        if ( *m == -INDEX && m[1] == alist[1] ) {
42✔
471
                                                if ( k != 1 ) {
30✔
472
                                                        if ( ( k & 1 ) == 0 ) sign = -sign;
12✔
473
/*
474
                                                        now move to position 1
475
*/
476
                                                        t2 = m+2; t1 = m; t3 = tt+FUNHEAD+2;
12✔
477
                                                        while ( t1 > t3 ) { *--t2 = *--t1; }
36✔
478
                                                        t3[0] = -INDEX; t3[1] = alist[1];
12✔
479
                                                }
480
                                                break;
481
                                        }
482
                                        NEXTARG(m)
12✔
483
                                }
484
/*
485
                                now copy the remaining arguments to w
486
*/
487
                                t1 = tt + FUNHEAD + 4;
30✔
488
                                t2 = tt + tt[1];
30✔
489
                                while ( t1 < t2 ) *w++ = *t1++;
90✔
490
                        }
491
                }
492
        }
493
        r[1] = w-r;
12✔
494
        while ( t < tstop ) {
48✔
495
                if ( *t == -1 ) { t += t[1]; continue; }
36✔
496
                i = t[1];
6✔
497
                NCOPY(w,t,i)
60✔
498
        }
499
        tstop = term + *term;
12✔
500
        while ( t < tstop ) *w++ = *t++;
48✔
501
        if ( sign < 0 ) w[-1] = -w[-1];
12✔
502
        i = w - AT.WorkPointer;
12✔
503
        *AT.WorkPointer = i;
12✔
504
        t = term; w = AT.WorkPointer;
12✔
505
        NCOPY(t,w,i)
372✔
506
        *AN.RepPoint = 1;        /* For Repeat */
12✔
507
        return(1);
12✔
508
}
509

510
/*
511
          #] Lus : 
512
          #[ FindLus :
513
*/
514

515
int FindLus(int from, int level, int openindex)
72✔
516
{
517
        GETIDENTITY
48✔
518
        int i, j, k, jj, *alist, *blist, *w, *m, partner;
72✔
519
        WORD **loc = AN.funlocs, *wor;
72✔
520
        if ( level == 1 ) {
72✔
521
                for ( i = from; i < AN.numoffuns; i++ ) {
204✔
522
                        alist = AN.funargs + i*AN.nargs;
150✔
523
                        for ( j = 0; j < AN.nargs; j++ ) {
582✔
524
                                if ( alist[j] == openindex ) {
444✔
525
                                        for ( k = 0; k < AN.nargs; k++ ) {
210✔
526
                                                if ( k == j ) continue;
162✔
527
                                                if ( alist[k] == AN.tohunt ) {
114✔
528
                                                        loc[from] = loc[i];
12✔
529
                                                        alist = AN.funargs + from*AN.nargs;
12✔
530
                                                        alist[0] = openindex; alist[1] = AN.tohunt;
12✔
531
                                                        return(1);
12✔
532
                                                }
533
                                        }
534
                                }
535
                        }
536
                }
537
        }
538
        else {
539
                for ( i = from; i < AN.numoffuns; i++ ) {
6✔
540
                        alist = AN.funargs + i*AN.nargs;
6✔
541
                        for ( j = 0; j < AN.nargs; j++ ) {
6✔
542
                                if ( alist[j] == openindex ) {
6✔
543
                                        if ( from != i ) {
6✔
544
                                                wor = loc[i]; loc[i] = loc[from]; loc[from] = wor;
×
545
                                                blist = w = AN.funargs + from*AN.nargs;
×
546
                                                m = alist;
×
547
                                                k = AN.nargs;
×
548
                                                while ( --k >= 0 ) { jj = *m; *m++ = *w; *w++ = jj; }
×
549
                                        }
550
                                        else blist = alist;
551
                                        for ( k = 0; k < AN.nargs; k++ ) {
12✔
552
                                                if ( k == j || blist[k] < 0 ) continue;
12✔
553
                                                partner = blist[k];
6✔
554
                                                if ( FindLus(from+1,level-1,partner) ) {
6✔
555
                                                        blist[0] = openindex; blist[1] = partner;
6✔
556
                                                        return(1);
6✔
557
                                                }
558
                                        }
559
                                        if ( from != i ) {
×
560
                                                wor = loc[i]; loc[i] = loc[from]; loc[from] = wor;
×
561
                                                w = AN.funargs + from*AN.nargs;
×
562
                                                m = alist;
×
563
                                                k = AN.nargs;
×
564
                                                while ( --k >= 0 ) { jj = *m; *m++ = *w; *w++ = jj; }
×
565
                                        }
566
                                }
567
                        }
568
                }
569
        }
570
        return(0);
571
}
572

573
/*
574
          #] FindLus : 
575
          #[ SortTheList :
576
*/
577

578
int SortTheList(int *slist, int num)
×
579
{
580
        GETIDENTITY
581
        int i, nleft, nright, *t1, *t2, *t3, *rlist;
×
582
        if ( num <= 2 ) {
×
583
                if ( num <=  1 ) return(num);
×
584
                if ( slist[0] < slist[2] ) return(2);
×
585
                if ( slist[0] > slist[2] ) {
×
586
                        i = slist[0]; slist[0] = slist[2]; slist[2] = i;
×
587
                        i = slist[1]; slist[1] = slist[3]; slist[3] = i;
×
588
                        return(2);
×
589
                }
590
                slist[1] += slist[3];
×
591
                return(1);
×
592
        }
593
        else {
594
                nleft = num/2; rlist = slist + 2*nleft;
×
595
                nright = SortTheList(rlist,num-nleft);
×
596
                nleft = SortTheList(slist,nleft);
×
597
                if ( AN.tlistsize < nleft ) {
×
598
                        if ( AN.tlistbuf ) M_free(AN.tlistbuf,"AN.tlistbuf");
×
599
                        AN.tlistsize = (nleft*3)/2;
×
600
                        AN.tlistbuf = (int *)Malloc1(AN.tlistsize*2*sizeof(int),"AN.tlistbuf");
×
601
                }
602
                i = nleft; t1 = slist; t2 = AN.tlistbuf;
×
603
                while ( --i >= 0 ) { *t2++ = *t1++; *t2++ = *t1++; }
×
604
                i = nleft+nright; t1 = AN.tlistbuf; t2 = rlist; t3 = slist;
×
605
                while ( nleft > 0 && nright > 0 ) {
×
606
                        if ( *t1 < *t2 ) {
×
607
                                *t3++ = *t1++; *t3++ = *t1++; nleft--;
×
608
                        }
609
                        else if ( *t1 > *t2 ) {
×
610
                                *t3++ = *t2++; *t3++ = *t2++; nright--;
×
611
                        }
612
                        else {
613
                                *t3++ = *t1++; t2++; *t3++ = (*t1++) + (*t2++); i--;
×
614
                                nleft--; nright--;
×
615
                        }
616
                }
617
                while ( --nleft >= 0 ) { *t3++ = *t1++; *t3++ = *t1++; }
×
618
                while ( --nright >= 0 ) { *t3++ = *t2++; *t3++ = *t2++; }
×
619
                return(i);
620
        }
621
}
622

623
/*
624
          #] SortTheList : 
625
          #[ AllLoops :
626

627
        Routine finds all possible loops that can be made in the
628
        arguments of the symmetric commuting vertex function v and creates
629
        for each loop a new term which is the original term times the loop.
630
        The occurrences of v can have different numbers of arguments.
631
        Each argument that occurs twice (and in different instances of v)
632
        in total will be considered.
633

634
        The input parameters are in C->lhs[level] and are
635
                C->lhs[level][0]  TYPEALLLOOPS
636
                C->lhs[level][1]  6
637
                C->lhs[level][2]  Number of function v.
638
                C->lhs[level][3]  Number of the output function loop.
639
                C->lhs[level][4]  option1: the type of argument.
640
                C->lhs[level][5]  option2: 0,1: what to do if no loop.
641
        Eligible arguments must be of the type SYMBOL, VECTOR, INDEX or SNUMBER.
642
        They must all be of the same type, indicated by option1.
643
        Extra restriction: In a loop, each v can be visited at most once.
644
        If there is no loop at all, option2 determines whether the term
645
        remains unmodified, or is replaced by zero.
646
        Function v can be either a regular function or a tensor.
647
        To facilitate this we copy the relevant arguments into the workspace.
648
*/
649

650
WORD AllLoops(PHEAD WORD *term,WORD level)
×
651
{
652
        CBUF *C = cbuf+AM.rbufnum;
×
653
        WORD vcode = C->lhs[level][2];    /* The input function */
×
654
        WORD option1 = C->lhs[level][4];  /* type of argument */
×
655
        WORD option2 = C->lhs[level][5];  /* what to do when no loop */
×
656
        WORD *tstop, *t, *tend, *tstart, *tfrom;
×
657
        WORD i, j, jj;
×
658
        WORD *arglist, nargs, *loop, nloop;
×
659
        WORD *oldworkpointer = AT.WorkPointer;
×
660
        LONG oldpworkpointer = AT.pWorkPointer;
×
661
        LONG numgenerated = 0, vert;
×
662
        WORD *a, *a1, *a2, *a3, *v, *vv, nvert, *to, *from, *tos, action;
×
663
/*
664
        Search for the first occurrence of vcode.
665
*/
666
        tstop = term+*term; tstop -=  ABS(tstop[-1]);
×
667
        t = term + 1;
×
668
        while ( t < tstop && *t != vcode ) t += t[1];
×
669
        if ( t == tstop ) {
×
670
                if ( option2 == 0 ) return(0);
×
671
                else return(Generator(BHEAD term,level));
×
672
        }
673
        tstart = t;
674
        nvert = 0;
675
        do {
×
676
                t += t[1]; nvert++;
×
677
        } while ( t < tstop && *t == vcode );
×
678
        tend = t;
679
/*
680
        Make room for 2*nvert pointers
681
*/
682
        WantAddPointers(2*nvert);
×
683
        vert = AT.pWorkPointer;
×
684
        AT.pWorkPointer += 2*nvert;
×
685
        nvert = 0;
×
686
/*
687
        Next we copy these functions into the workspace, but only the arguments
688
        that agree with option1. Because of the difference between tensors and
689
        regular functions in the copy we strip the type of the argument.
690
*/
691
        to = AT.WorkPointer;
×
692
        from = tstart;
×
693
        if ( functions[vcode-FUNCTION].spec == TENSORFUNCTION ) {
×
694
                from = tstart;
695
                while ( from < tend ) {
×
696
                        tos = to++;
×
697
                        tfrom = from+from[1];
×
698
                        from += FUNHEAD;
×
699
                        while ( from < tfrom ) {
×
700
                                if ( option1 == -INDEX && *from >= 0 ) {
×
701
                                        *to++ = *from++;
×
702
                                }
703
                                else if ( option1 == -VECTOR && *from < 0 ) {
×
704
                                        *to++ = *from++ - AM.OffsetVector;
×
705
                                }
706
                                else {
707
                                        from++;
×
708
                                }
709
                        }
710
                        *tos = to-from;
×
711
                        if ( *tos < 3 ) to = tos;
×
712
                        else AT.pWorkSpace[vert+nvert++] = tos;
×
713
                }
714
        }
715
        else if ( functions[vcode-FUNCTION].spec == 0 ) {
×
716
                from = tstart;
717
                while ( from < tend ) {
×
718
                        tos = to++;
×
719
                        tfrom = from + from[1];
×
720
                        from += FUNHEAD;
×
721
                        while ( from < tfrom ) {
×
722
                                if ( option1 == -VECTOR
×
723
                                         && ( from[0] == -INDEX || from[0] == -VECTOR )
×
724
                                         && from[1] < 0 ) {
×
725
                                        from++;
×
726
                                        *to++ = *from++ - AM.OffsetVector;
×
727
                                }
728
                                else if ( option1 == *from ) {
×
729
                                        from++; *to++ = *from++;
×
730
                                }
731
                                else {
732
                                        NEXTARG(from);
×
733
                                }
734
                        }
735
                        *tos = to-tos;
×
736
                        if ( *tos < 3 ) to = tos;
×
737
                        else AT.pWorkSpace[vert+nvert++] = tos;
×
738
                }
739
        }
740
        else {
741
                AT.WorkPointer = oldworkpointer;
×
742
                AT.pWorkPointer = oldpworkpointer;
×
743
                if ( option2 == 0 ) return(0);
×
744
                return(Generator(BHEAD term,level));
×
745
        }
746
        AT.WorkPointer = to;
×
747
/*
748
        Now make a list of all relevant arguments.
749
*/
750
        a = arglist = AT.WorkPointer;
×
751
        for ( i = 0; i < nvert; i++ ) {
×
752
                v = AT.pWorkSpace[vert+i];
×
753
                j = *v-1; v++;
×
754
                NCOPY(a,v,j);
×
755
        }
756
        nargs = a-arglist;
×
757
        AT.WorkPointer = a;
×
758
/*
759
        Now sort the list. Bubble type sort.
760
*/
761
        a1 = arglist; a2 = a1+1;
×
762
        while ( a2 < a ) {
×
763
                a3 = a2;
764
                while ( a3 > a1 && a3[-1] > a3[0] ) {
×
765
                        EXCH(*a3,a3[-1]);
×
766
                        a3--;
×
767
                }
768
                a2++;
×
769
        }
770
/*
771
        Now remove the elements from the list that do not occur exactly twice.
772
*/
773
        a1 = arglist; a2 = a1; a3 = a1+nargs;
×
774
        while ( a2 < a3 ) {
×
775
                if ( a2+1 == a3 ) { break; }
×
776
                else if ( a2+2 == a3 ) {
×
777
                        if ( a2[0] == a2[1] ) { *a1++ = a2[0]; }
×
778
                        break;
779
                }
780
                else {
781
                        if ( a2[0] != a2[1] ) { a2++; }
×
782
                        else if ( a2[0] != a2[2] ) {
×
783
                                *a1++ = a2[0]; a2 += 2;
×
784
                        }
785
                        else {
786
                                a2++; while ( a2 < a3 && a2[-1] == a2[0] ) a2++;
×
787
                        }
788
                }
789
        }
790
        nargs = a1-arglist;
×
791
/*
792
        Now we need to redo the list of vertices and remove the elements
793
        that are not in our arglist.
794
*/
795
        do {
×
796
          action = 0;
×
797
          for ( i = 0; i < nvert; i++ ) {
×
798
                vv = v = AT.pWorkSpace[vert+i];
×
799
                v++;
×
800
                for ( j = 1; j < vv[0]; j++ ) {
×
801
                        for ( jj = 0; jj < nargs; jj++ ) {
×
802
                                if ( *v == arglist[jj] ) break;
×
803
                        }
804
                        if ( jj >= nargs ) {        /* was not in the list */
×
805
                                vv[0] = vv[0]-1;
×
806
                                for ( jj = j; jj < vv[0]; jj++ ) vv[jj] = vv[jj+1];
×
807
                        }
808
                        v++;
×
809
                }
810
          }
811
/*
812
          Next we need to remove vertices that have only one object remaining.
813
          Also, the object can be removed from arglist. After that we go back
814
          to clean up the list.
815
*/
816
          for ( i = 0; i < nvert; i++ ) {
×
817
                vv = AT.pWorkSpace[vert+i];
×
818
                if ( vv[0] == 1 ) {
×
819
                        AT.pWorkSpace[vert+i] = AT.pWorkSpace[vert+nvert-1];
×
820
                        nvert--; i--; continue;
×
821
                }
822
                else if ( vv[0] == 2 ) {
×
823
                        for ( j = 0; j < nargs; j++ ) {
×
824
                                if ( arglist[j] == vv[1] ) break;
×
825
                        }
826
                        while ( j < nargs-1 ) arglist[j] = arglist[j+1];
×
827
                        nargs--;
×
828
                        AT.pWorkSpace[vert+i] = AT.pWorkSpace[vert+nvert-1];
×
829
                        nvert--; i--; 
×
830
                        action = 1;
×
831
                }
832
          }
833
        } while ( action );
×
834
/*
835
        Because the user can remove tadpoles rather easily as in
836
                id v(?a,i?,?b,i?,?c) = v(?a,?b,?c)
837
        there is no need to avoid them as potential loops.
838

839
        At this point we are ready to look for loops.
840
        We have
841
                arglist,nargs   list of eligible objects.
842
                vert,nvert      position in pWorkSpace for vertices and their number.
843
                                The vertices themselves are in the WorkSpace.
844
                loop,nloop      The buildup of the loop.
845
*/
846
        loop = AT.WorkPointer;
×
847
        AT.WorkPointer += nargs;
×
848
        nloop = 0;
×
849
        numgenerated += StartLoops(BHEAD term,level,vert,nvert,arglist,nargs,loop,nloop);
×
850
        AT.WorkPointer = oldworkpointer;
×
851
        AT.pWorkPointer = oldpworkpointer;
×
852

853
        if ( numgenerated == 0 && option2 != 0 ) return(Generator(BHEAD term,level));
×
854
        return(0);
855
}
856

857
/*
858
          #] AllLoops : 
859
          #[ StartLoops :
860

861
        Algorithm.
862
        1: have a list of vertices and objects that can be part of the loops.
863
        2: starting with the first element of arglist, look for the two
864
           vertices that contain this object. The first is vstart.
865
        3: At the second, look at all possible objects to continue from here.
866
        4: For each, find the vertex with its partner.
867
        5: if the partner vertex is vstart, we have a loop. --> 9.
868
        6: The partner vertex is not allowed to be a vertex that we passed
869
           in the current build-up of the loop.
870
        7: Put the object in loop and increase nloop.
871
        8: Now sum over all allowed objects in the partner vertex. --> 4.
872

873
        9: Create the function loop with the arguments from loop,nloop.
874
   10: If a reverse cyclic permutation gives a smaller result, drop this
875
           solution and continue with the last summing over objects at a vertex.
876
   11: If not, output the result by adding the function loop
877
           to the term and call Generator(term,level)
878

879
   12: when all possibilities with the first element of arglist have been
880
           exhausted, raise arglist and lower nargs by one. --> 2
881
   13: when nargs == 1, we can stop.
882

883
        The inclusion of a new object when we sum over the possibilities at a
884
        vertex can best be done in a recursion, because we have no idea how
885
        many nested loops we would otherwise need. Of course the recursion can
886
        be emulated, but that makes the algorithm rather messy.
887

888
        We have two routines: StartLoops and GenLoops.
889
        StartLoops takes care of the first argument (and the summing over who
890
        is the first argument), while GenLoops treats an additional vertex until
891
        a loop is closed. GenLoops also sends completed loops off toe Generator.
892
*/
893

894
LONG StartLoops(PHEAD WORD *term,WORD level,LONG vert,WORD nvert,
×
895
                WORD *arglist,WORD nargs,WORD *loop,WORD nloop)
896
{
897
        LONG numgenerated = 0;
×
898
        WORD *v, *vv, *vstart, istart, *vpartner, ipartner, j;
×
899
        while ( nargs > 1 ) {
×
900
/*
901
                Look for a vertex with arglist[0]. This is our starting vertex.
902
                Next we look for its partner and we put arglist[0] in loop.
903
*/
904
                nloop = 0;
×
905
                loop[nloop++] = arglist[0];
×
906
                for ( istart = 0; istart < nvert; istart++ ) {
×
907
                        vstart = AT.pWorkSpace[vert+istart];
×
908
                        v = vstart+1; vv = vstart + *vstart;
×
909
                        do {
×
910
                                if ( *v == arglist[0] ) goto havestart;
×
911
                                v++;
×
912
                        } while ( v < vv );
×
913
                }
914
/*
915
                If we come here, we have a problem.
916
*/
917
                MesPrint("Internal error in StartLoops. Object not found.");
×
918
                Terminate(-1);
×
919
                return(-1);
×
920
havestart:
×
921
                AT.pWorkSpace[vert+nvert] = vstart;
×
922
/*
923
                Check for tadpole.
924
*/
925
                v++;
×
926
                while ( v < vv ) {
×
927
                        if ( *v == arglist[0] ) {        /* tadpole */
×
928
                                LoopOutput(BHEAD term,level,loop,nloop);
×
929
                                numgenerated++;
×
930
                                goto nextarg;
×
931
                        }
932
                        v++;
×
933
                }
934
/*
935
                Now the partner vertex.
936
*/
937
                for ( ipartner = istart+1; ipartner < nvert; ipartner++ ) {
×
938
                        vpartner = AT.pWorkSpace[vert+ipartner];
×
939
                        vv = vpartner+*vpartner; v = vpartner+1;
×
940
                        do {
×
941
                                if ( *v == arglist[0] ) goto havepartner;
×
942
                                v++;
×
943
                        } while ( v < vv );
×
944
                }
945
                return(numgenerated);
946
havepartner:
×
947
                AT.pWorkSpace[vert+nvert+1] = vpartner;
×
948
/*
949
                Now we run through all other possibilities at vpartner.
950
                vv is still OK.
951
*/
952
                v = vpartner+1;
×
953
                while ( v < vv ) {
×
954
                        if ( *v != arglist[0] ) {
×
955
                                for ( j = 1; j < nargs; j++ ) {
×
956
                                        if ( *v == arglist[j] ) {
×
957
                                                loop[nloop++] = *v;
×
958
                                                numgenerated += GenLoops(BHEAD term,level,vert,nvert,
×
959
                                                                                                arglist,nargs,loop,nloop);
960
                                                nloop--;
×
961
                                                break;
×
962
                                        }
963
                                }
964
                        }
965
                        v++;
×
966
                }
967
nextarg:
×
968
                arglist++; nargs--;
×
969
        }
970
        return(numgenerated);
971
}
972

973
/*
974
          #] StartLoops : 
975
          #[ GenLoops :
976

977
        We enter with an open line in loop[nloop-1]
978
*/
979

980
LONG GenLoops(PHEAD WORD *term,WORD level,LONG vert,WORD nvert,
×
981
                WORD *arglist,WORD nargs,WORD *loop,WORD nloop)
982
{
983
        LONG numgenerated = 0;
×
984
        WORD *vstart, *v, *vv, i, j, *vpartner;
×
985
/*
986
        Start with checking whether the partner is in vstart (=vert[nvert])
987
*/
988
        vstart = AT.pWorkSpace[nvert];
×
989
        vv = vstart + *vstart; v = vstart+1;
×
990
        while ( v < vv ) {
×
991
                if ( *v == loop[nloop-1] ) {
×
992
/*
993
                        This closes the loop.
994
                        Now we can output it.
995
*/
996
                        LoopOutput(BHEAD term,level,loop,nloop);
×
997
                        numgenerated++;
×
998
                        return(numgenerated);
×
999
                }
1000
                v++;
×
1001
        }
1002
/*
1003
        Start with finding the partner.
1004
*/
1005
        for ( i = 0; i < nvert; i++ ) {
×
1006
                vpartner = AT.pWorkSpace[vert+i];
×
1007
                if ( vpartner == vstart ) continue;
×
1008
                for ( j = 0; j < nloop; j++ ) {
×
1009
                        if ( vpartner == AT.pWorkSpace[vert+nvert+j] ) break;
×
1010
                }
1011
                if ( j < nloop ) continue;
×
1012
                v = vpartner+1; vv = vpartner + *vpartner;
×
1013
                while ( v < vv ) {
×
1014
                        if ( *v == loop[nloop-1] ) {
×
1015
/*
1016
                                Found the partner.
1017
                                Now we can sum over the remaining permitted arguments of this vertex.
1018
*/
1019
                                v = vpartner + 1;
1020
                                while ( v < vv ) {
×
1021
/*
1022
                                        *v should be in arglist.
1023
*/
1024
                                        for ( j = 0; j < nargs; j++ ) {
×
1025
                                                if ( *v == arglist[j] ) break;
×
1026
                                        }
1027
                                        if ( j >= nargs ) { v++; continue; }
×
1028
/*
1029
                                        *v should not be in loops.
1030
*/
1031
                                        for ( j = 0; j < nloop; j++ ) {
×
1032
                                                if ( *v == loop[j] ) break;
×
1033
                                        }
1034
                                        if ( j >= nloop ) {
×
1035
                                                AT.pWorkSpace[vert+nvert+nloop] = vpartner;
×
1036
                                                loop[nloop++] = *v;
×
1037
                                                numgenerated += GenLoops(BHEAD term,level,vert,nvert,
×
1038
                                                                arglist,nargs,loop,nloop);
1039
                                                nloop--;
×
1040
                                        }
1041
                                        v++;
×
1042
                                }
1043
                                return(numgenerated);
1044
                        }
1045
                        v++;
×
1046
                }
1047
        }
1048
/*
1049
        The partner is in a vertex we have finished before.
1050
*/
1051
        return(numgenerated);
1052
}
1053

1054
/*
1055
          #] GenLoops : 
1056
          #[ LoopOutput :
1057
*/
1058

1059
void LoopOutput(PHEAD WORD *term, WORD level, WORD *loop, WORD nloop)
×
1060
{
1061
        CBUF *C = cbuf+AM.rbufnum;
×
1062
        WORD loopfun = C->lhs[level][3];  /* The output function */
×
1063
        WORD option1 = C->lhs[level][4];  /* type of argument */
×
1064
        WORD *tstop, *tstop1, *t, *tt;
×
1065
        WORD *outterm, *loop1;
×
1066
        WORD i;
×
1067
        tstop1 = term+*term; tstop = tstop1 - ABS(tstop1[-1]);
×
1068
/*
1069
        Construct the rcycle symmetrized version of loop.
1070
*/
1071
        if ( nloop > 2 ) {
×
1072
                loop1 = AT.WorkPointer;
×
1073
                loop1[0] = loop[0];
×
1074
                for ( i = 1; i < nloop; i++ ) { loop1[i] = loop[nloop-i]; }
×
1075
                if ( loop1[1] < loop[1] ) {
×
1076
                        AT.WorkPointer += nloop;
×
1077
                        loop = loop1;
×
1078
                }
1079
        }
1080
        outterm = AT.WorkPointer;
×
1081
        tt = outterm; t = term;
×
1082
        while ( t < tstop ) *tt++ = *t++;
×
1083
        *tt++ = loopfun;
×
1084
        if ( functions[loopfun-FUNCTION].spec == TENSORFUNCTION ) {
×
1085
                *tt++ = FUNHEAD+nloop;
×
1086
                FILLFUN(tt)
×
1087
                if ( option1 == -VECTOR ) {
×
1088
                        for ( i = 0; i < nloop; i++ ) *tt++ = loop[i]+AM.OffsetVector;
×
1089
                }
1090
                else {
1091
                        for ( i = 0; i < nloop; i++ ) *tt++ = loop[i];
×
1092
                }
1093
        }
1094
        else {
1095
                *tt++ = FUNHEAD+nloop*2;
×
1096
                FILLFUN(tt)
×
1097
                for ( i = 0; i< nloop; i++ ) {
×
1098
                        *tt++ = option1;
×
1099
                        if ( option1 == -VECTOR ) *tt++ = loop[i] + AM.OffsetVector;
×
1100
                        else *tt++ = loop[i];
×
1101
                }
1102
        }
1103
        while ( t < tstop1 ) *tt++ = *t++;
×
1104
        *outterm = tt - outterm;
×
1105
        AT.WorkPointer = tt;
×
1106
        if ( Generator(BHEAD outterm,level) ) {
×
1107
                MesCall("LoopOutput");
×
1108
                Terminate(-1);
×
1109
        }
1110
        AT.WorkPointer = outterm;
×
1111
}
×
1112

1113
/*
1114
          #] LoopOutput : 
1115
          #[ AllPaths :
1116

1117
        This routine has many similarities with AllLoops.
1118
        In AllLoops we have startingpoint and endpoint at the same vertex.
1119
        In AllPaths the startingpoint and the endpoints are different and 
1120
        given in advance. This endfun can occur only twice.
1121
*/
1122

1123
WORD AllPaths(PHEAD WORD *term,WORD level)
×
1124
{
1125
        CBUF *C = cbuf+AM.rbufnum;
×
1126
        WORD endcode = C->lhs[level][2];    /* The endpoint function */
×
1127
        WORD vcode   = C->lhs[level][3];    /* The intermediate function */
×
1128
        WORD option1 = C->lhs[level][5];    /* type of argument */
×
1129
        WORD option2 = C->lhs[level][6];    /* what to do when no loop */
×
1130
        WORD *t, *tstop, *tend1, *tend2, *tstart, *tend, numend, nvert, npass;
×
1131
        WORD *tfrom, *to, *tos, *from;
×
1132
        WORD *arglist, nargs, *path, npath, *a, *a1, *a2, *a3;
×
1133
        WORD i, j, jj, *v, *vv, action;
×
1134
        LONG vert,vert1; /* ,vert2; */
×
1135
        WORD numgenerated = 0;
×
1136
        WORD *oldworkpointer = AT.WorkPointer;
×
1137
        LONG oldpworkpointer = AT.pWorkPointer;
×
1138
/*
1139
        Search for the two occurrences of endcode.
1140
*/
1141
        tstop = term+*term; tstop -=  ABS(tstop[-1]);
×
1142
        t = term + 1;
×
1143
        while ( t < tstop && *t != endcode ) t += t[1];
×
1144
        if ( t == tstop ) { /* no endpoints */
×
1145
                if ( option2 == 0 ) return(0);
×
1146
                else return(Generator(BHEAD term,level));
×
1147
        }
1148
        tend1 = t;
1149
        numend = 0;
1150
        while ( t < tstop && *t == endcode ) { tend2 = t; t += t[1]; numend++; }
×
1151
        if ( numend != 2 ) { /* not 2 endpoints -> no path */
×
1152
                if ( option2 == 0 ) return(0);
×
1153
                else return(Generator(BHEAD term,level));
×
1154
        }
1155
/*
1156
        Search for the intermediate functions.
1157
*/
1158
        t = term + 1;
1159
        nvert = 0;
×
1160
        while ( t < tstop && *t != vcode ) t += t[1];
×
1161
        tstart = t;
1162
        while ( t < tstop && *t == vcode ) {
×
1163
                t += t[1]; nvert++;
×
1164
        }
1165
        tend = t;
1166
/*
1167
        Next we copy the relevant content of the various functions into the
1168
        WorkSpace. We keep pointers to the functions in pWorkSpace.
1169
        First the two endpoints and then the intermediate ones.
1170
*/
1171
        WantAddPointers((2*nvert+8));
×
1172
        vert = AT.pWorkPointer+2;
×
1173
        vert1 = AT.pWorkPointer;
×
1174
/*        vert2 = AT.pWorkPointer+1; */
1175
        AT.pWorkPointer += 2*nvert+8;
×
1176
        nvert = 0;
×
1177
/*
1178
        Copy the endpoints.
1179
*/
1180
        to = AT.WorkPointer;
×
1181

1182
        if ( functions[endcode-FUNCTION].spec == TENSORFUNCTION ) {
×
1183
                from = tend1; npass = 0;
1184
redo1:
×
1185
                tos = to++;
×
1186
                tfrom = from+from[1];
×
1187
                from += FUNHEAD;
×
1188
                while ( from < tfrom ) {
×
1189
                        if ( option1 == -INDEX && *from >= 0 ) {
×
1190
                                *to++ = *from++;
×
1191
                        }
1192
                        else if ( option1 == -VECTOR && *from < 0 ) {
×
1193
                                *to++ = *from++ - AM.OffsetVector;
×
1194
                        }
1195
                        else {
1196
                                from++;
×
1197
                        }
1198
                }
1199
                *tos = to-tos;
×
1200
                if ( *tos < 2 ) to = tos;
×
1201
                else AT.pWorkSpace[vert1+npass] = tos;
×
1202
                npass++;
×
1203
                if ( from == tend2 ) goto redo1;
×
1204
        }
1205
        else if ( functions[endcode-FUNCTION].spec == 0 ) {
×
1206
                from = tend1;
1207
                npass = 0;
1208
redo2:
×
1209
                tos = to++;
×
1210
                tfrom = from + from[1];
×
1211
                from += FUNHEAD;
×
1212
                while ( from < tfrom ) {
×
1213
                        if ( option1 == -VECTOR
×
1214
                                 && ( from[0] == -INDEX || from[0] == -VECTOR )
×
1215
                                 && from[1] < 0 ) {
×
1216
                                from++;
×
1217
                                *to++ = *from++ - AM.OffsetVector;
×
1218
                        }
1219
                        else if ( option1 == *from ) {
×
1220
                                from++; *to++ = *from++;
×
1221
                        }
1222
                        else {
1223
                                NEXTARG(from);
×
1224
                        }
1225
                }
1226
                *tos = to-tos;
×
1227
                if ( *tos < 2 ) to = tos;
×
1228
                else AT.pWorkSpace[vert1+npass] = tos;
×
1229
                npass++;
×
1230
                if ( from == tend2 ) goto redo2;
×
1231
        }
1232
        else {
1233
                AT.WorkPointer = oldworkpointer;
×
1234
                AT.pWorkPointer = oldpworkpointer;
×
1235
                if ( option2 == 0 ) return(0);
×
1236
                return(Generator(BHEAD term,level));
×
1237
        }
1238
/*
1239
        And now the intermediate functions
1240
*/
1241
        from = tstart;
×
1242
        if ( functions[vcode-FUNCTION].spec == TENSORFUNCTION ) {
×
1243
                from = tstart;
1244
                while ( from < tend ) {
×
1245
                        tos = to++;
×
1246
                        tfrom = from+from[1];
×
1247
                        from += FUNHEAD;
×
1248
                        while ( from < tfrom ) {
×
1249
                                if ( option1 == -INDEX && *from >= 0 ) {
×
1250
                                        *to++ = *from++;
×
1251
                                }
1252
                                else if ( option1 == -VECTOR && *from < 0 ) {
×
1253
                                        *to++ = *from++ - AM.OffsetVector;
×
1254
                                }
1255
                                else {
1256
                                        from++;
×
1257
                                }
1258
                        }
1259
                        *tos = to-tos;
×
1260
                        if ( *tos < 3 ) to = tos;
×
1261
                        else AT.pWorkSpace[vert+nvert++] = tos;
×
1262
                }
1263
        }
1264
        else if ( functions[vcode-FUNCTION].spec == 0 ) {
×
1265
                from = tstart;
1266
                while ( from < tend ) {
×
1267
                        tos = to++;
×
1268
                        tfrom = from + from[1];
×
1269
                        from += FUNHEAD;
×
1270
                        while ( from < tfrom ) {
×
1271
                                if ( option1 == -VECTOR
×
1272
                                         && ( from[0] == -INDEX || from[0] == -VECTOR )
×
1273
                                         && from[1] < 0 ) {
×
1274
                                        from++;
×
1275
                                        *to++ = *from++ - AM.OffsetVector;
×
1276
                                }
1277
                                else if ( option1 == *from ) {
×
1278
                                        from++; *to++ = *from++;
×
1279
                                }
1280
                                else {
1281
                                        NEXTARG(from);
×
1282
                                }
1283
                        }
1284
                        *tos = to-tos;
×
1285
                        if ( *tos < 3 ) to = tos;
×
1286
                        else AT.pWorkSpace[vert+nvert++] = tos;
×
1287
                }
1288
        }
1289
        else {
1290
                AT.WorkPointer = oldworkpointer;
×
1291
                AT.pWorkPointer = oldpworkpointer;
×
1292
                if ( option2 == 0 ) return(0);
×
1293
                return(Generator(BHEAD term,level));
×
1294
        }
1295
        AT.WorkPointer = to;
×
1296
/*
1297
        Now make a list of all relevant arguments.
1298
*/
1299
        a = arglist = AT.WorkPointer;
×
1300
        for ( i = -2; i < nvert; i++ ) {
×
1301
                v = AT.pWorkSpace[vert+i];
×
1302
                j = *v-1; v++;
×
1303
                NCOPY(a,v,j);
×
1304
        }
1305
        nargs = a-arglist;
×
1306
        AT.WorkPointer = a;
×
1307
/*
1308
        Now sort the list. Bubble type sort.
1309
*/
1310
        a1 = arglist; a2 = a1+1;
×
1311
        while ( a2 < a ) {
×
1312
                a3 = a2;
1313
                while ( a3 > a1 && a3[-1] > a3[0] ) {
×
1314
                        EXCH(*a3,a3[-1]);
×
1315
                        a3--;
×
1316
                }
1317
                a2++;
×
1318
        }
1319
/*
1320
        Now remove the elements from the list that do not occur exactly twice.
1321
*/
1322
        a1 = arglist; a2 = a1; a3 = a1+nargs;
×
1323
        while ( a2 < a3 ) {
×
1324
                if ( a2+1 == a3 ) { break; }
×
1325
                else if ( a2+2 == a3 ) {
×
1326
                        if ( a2[0] == a2[1] ) { *a1++ = a2[0]; }
×
1327
                        break;
1328
                }
1329
                else {
1330
                        if ( a2[0] != a2[1] ) { a2++; }
×
1331
                        else if ( a2[0] != a2[2] ) {
×
1332
                                *a1++ = a2[0]; a2 += 2;
×
1333
                        }
1334
                        else {
1335
                                a2++; while ( a2 < a3 && a2[-1] == a2[0] ) a2++;
×
1336
                        }
1337
                }
1338
        }
1339
        nargs = a1-arglist;
×
1340
/*
1341
        Now we need to redo the list of vertices and remove the elements
1342
        that are not in our arglist.
1343
*/
1344
        do {
×
1345
          action = 0;
×
1346
          for ( i = -2; i < nvert; i++ ) {
×
1347
                vv = v = AT.pWorkSpace[vert+i];
×
1348
                v++;
×
1349
                for ( j = 1; j < vv[0]; j++ ) {
×
1350
                        for ( jj = 0; jj < nargs; jj++ ) {
×
1351
                                if ( *v == arglist[jj] ) break;
×
1352
                        }
1353
                        if ( jj >= nargs ) {        /* was not in the list */
×
1354
                                vv[0] = vv[0]-1;
×
1355
                                for ( jj = j; jj < vv[0]; jj++ ) vv[jj] = vv[jj+1];
×
1356
                        }
1357
                        v++;
×
1358
                }
1359
          }
1360
/*
1361
          Next we need to remove vertices that have only one object remaining.
1362
          Also, the object can be removed from arglist. After that we go back
1363
          to clean up the list.
1364
*/
1365
          for ( i = -2; i < nvert; i++ ) {
×
1366
                vv = AT.pWorkSpace[vert+i];
×
1367
                if ( vv[0] == 1 ) {
×
1368
                        AT.pWorkSpace[vert+i] = AT.pWorkSpace[vert+nvert-1];
×
1369
                        nvert--; i--; continue;
×
1370
                }
1371
                else if ( vv[0] == 2 && i >= 0 ) {
×
1372
                        for ( j = 0; j < nargs; j++ ) {
×
1373
                                if ( arglist[j] == vv[1] ) break;
×
1374
                        }
1375
                        while ( j < nargs-1 ) arglist[j] = arglist[j+1];
×
1376
                        nargs--;
×
1377
                        AT.pWorkSpace[vert+i] = AT.pWorkSpace[vert+nvert-1];
×
1378
                        nvert--; i--; 
×
1379
                        action = 1;
×
1380
                }
1381
          }
1382
        } while ( action );
×
1383
/*
1384
        Now we have a clean list of connections and we can start building
1385
        the path. We start with summing over all objects in vert1.
1386
*/
1387
        path = AT.WorkPointer; npath = 0;
×
1388
        AT.WorkPointer += nvert+8;
×
1389

1390
        t = AT.pWorkSpace[vert1];
×
1391
        if ( *t >= 2 ) {
×
1392
                for ( i = 1; i < *t; i++ ) {
×
1393
                        AT.pWorkSpace[vert+nvert] = t;
×
1394
                        path[npath++] = t[i];
×
1395
                        numgenerated += GenPaths(BHEAD term,level,vert,nvert,arglist,nargs,path,npath);
×
1396
                        npath--;
×
1397
                }
1398
        }
1399
        AT.WorkPointer = oldworkpointer;
×
1400
        AT.pWorkPointer = oldpworkpointer;
×
1401
        if ( numgenerated == 0 && option2 != 0 ) return(Generator(BHEAD term,level));
×
1402
        return(0);
1403
}
1404

1405
/*
1406
          #] AllPaths : 
1407
          #[ GenPaths :
1408

1409
        We enter with an open line in path[npath-1]
1410
        We traverse though the vertices until we reach vert-1, the endpoint.
1411
*/
1412

1413
LONG GenPaths(PHEAD WORD *term, WORD level, LONG vert, WORD nvert,
×
1414
                WORD *arglist, WORD nargs, WORD *path, WORD npath)
1415
{
1416
        LONG numgenerated = 0;
×
1417
        WORD *t, *vpartner, *v, *vv;
×
1418
        WORD i, j;
×
1419
/*
1420
        Check whether path[npath-1] is part of the endpoint.
1421
*/
1422
        t = AT.pWorkSpace[vert-1];
×
1423
        for ( i = 1; i < *t; i++ ) {
×
1424
                if ( t[i] == path[npath-1] ) { /* Got a path! */
×
1425
                        PathOutput(BHEAD term,level,path,npath);
×
1426
                        numgenerated++;
×
1427
                        return(numgenerated);
×
1428
                }
1429
        }
1430
/*
1431
        Start with finding the partner.
1432
*/
1433
        for ( i = 0; i < nvert; i++ ) {
×
1434
                vpartner = AT.pWorkSpace[vert+i];
×
1435
                for ( j = 0; j < npath; j++ ) {
×
1436
                        if ( vpartner == AT.pWorkSpace[vert+nvert+j] ) break;
×
1437
                }
1438
                if ( j < npath ) continue;
×
1439
                v = vpartner+1; vv = vpartner + *vpartner;
×
1440
                while ( v < vv ) {
×
1441
                        if ( *v == path[npath-1] ) {
×
1442
/*
1443
                                Found the partner.
1444
                                Now we can sum over the remaining permitted arguments of this vertex.
1445
*/
1446
                                v = vpartner + 1;
1447
                                while ( v < vv ) {
×
1448
/*
1449
                                        *v should be in arglist.
1450
*/
1451
                                        for ( j = 0; j < nargs; j++ ) {
×
1452
                                                if ( *v == arglist[j] ) break;
×
1453
                                        }
1454
                                        if ( j >= nargs ) { v++; continue; }
×
1455
/*
1456
                                        *v should not be in path.
1457
*/
1458
                                        for ( j = 0; j < npath; j++ ) {
×
1459
                                                if ( *v == path[j] ) break;
×
1460
                                        }
1461
                                        if ( j >= npath ) {
×
1462
                                                AT.pWorkSpace[vert+nvert+npath] = vpartner;
×
1463
                                                path[npath++] = *v;
×
1464
                                                numgenerated += GenPaths(BHEAD term,level,vert,nvert,
×
1465
                                                                arglist,nargs,path,npath);
1466
                                                npath--;
×
1467
                                        }
1468
                                        v++;
×
1469
                                }
1470
                                return(numgenerated);
1471
                        }
1472
                        v++;
×
1473
                }
1474
        }
1475
/*
1476
        The partner is in a vertex we have finished before.
1477
*/
1478
        return(numgenerated);
1479
}
1480

1481
/*
1482
          #] GenPaths : 
1483
          #[ PathOutput :
1484
*/
1485

1486
void PathOutput(PHEAD WORD *term, WORD level, WORD *path, WORD npath)
×
1487
{
1488
        CBUF *C = cbuf+AM.rbufnum;
×
1489
        WORD pathfun = C->lhs[level][4];  /* The output function */
×
1490
        WORD option1 = C->lhs[level][5];  /* type of argument */
×
1491
        WORD *tstop, *tstop1, *t, *tt;
×
1492
        WORD *outterm;
×
1493
        WORD i;
×
1494
        tstop1 = term+*term; tstop = tstop1 - ABS(tstop1[-1]);
×
1495
        outterm = AT.WorkPointer;
×
1496
        tt = outterm; t = term;
×
1497
        while ( t < tstop ) *tt++ = *t++;
×
1498
        *tt++ = pathfun;
×
1499
        if ( functions[pathfun-FUNCTION].spec == TENSORFUNCTION ) {
×
1500
                *tt++ = FUNHEAD+npath;
×
1501
                FILLFUN(tt)
×
1502
                if ( option1 == -VECTOR ) {
×
1503
                        for ( i = 0; i < npath; i++ ) *tt++ = path[i]+AM.OffsetVector;
×
1504
                }
1505
                else {
1506
                        for ( i = 0; i < npath; i++ ) *tt++ = path[i];
×
1507
                }
1508
        }
1509
        else {
1510
                *tt++ = FUNHEAD+npath*2;
×
1511
                FILLFUN(tt)
×
1512
                for ( i = 0; i< npath; i++ ) {
×
1513
                        *tt++ = option1;
×
1514
                        if ( option1 == -VECTOR ) *tt++ = path[i] + AM.OffsetVector;
×
1515
                        else *tt++ = path[i];
×
1516
                }
1517
        }
1518
        while ( t < tstop1 ) *tt++ = *t++;
×
1519
        *outterm = tt - outterm;
×
1520
        AT.WorkPointer = tt;
×
1521
        if ( Generator(BHEAD outterm,level) ) {
×
1522
                MesCall("PathOutput");
×
1523
                Terminate(-1);
×
1524
        }
1525
        AT.WorkPointer = outterm;
×
1526
}
×
1527

1528

1529

1530
/*
1531
          #] PathOutput : 
1532
          #[ AllOnePI :
1533

1534
        We assume a graph that has loops and is OnePI.
1535
        This routine initializes the recursion that creates all onePI subgraphs.
1536

1537
        Algorithm:
1538
                a: have a routine that removes all bridges: RemoveBridges
1539
                b: output an empty diagram.
1540
                c: output the diagram itself
1541
                d: cut a line, followed by removing all bridges.
1542
                e: if the diagram still has lines, go to c, else go to the next line in d.
1543
        In order to avoid factorial blowup, we need to prune the tree as fast as possible.
1544

1545
    1: list of lines to be cut.
1546
        2: once we have tried a line and removed its bridges, we do not have to
1547
           try this line deeper in the tree, neither its bridges.
1548

1549

1550
         1 2 3
1551
                cut 1.                        x
1552
                        cut 2 -> bridge 3          x
1553
                cut 2.                        x
1554
                        cut 3 -> bridge 1   ????   mag niet
1555
                cut 3.                        x
1556
        Hence  1,2,3,4,5,6,7
1557
                1 still to go 2,3,4,5,6,7
1558
                2 still to go 3,4,5,6,7
1559
                3 still to go 4,5,6,7
1560
                etc.
1561
        bridges: if x is bridge, we take x from the list_to_go.
1562
        If we have a bridge that is a number lower than the list_to_go we skip this possibility.
1563
        We reach the end when the list_to_go is empty.
1564
*/
1565

1566
WORD AllOnePI(WORD *term,WORD level)
×
1567
{
1568
        CBUF *C = cbuf+AM.rbufnum;
×
1569
        WORD vcode   = C->lhs[level][2];    /* The vertex function */
×
1570
        WORD option1 = C->lhs[level][4];    /* type of argument */
×
1571
/*
1572
        First we have to collect all relevant information about the diagram.
1573
        We should start with removing bridges to make the real starting point onePI.
1574
*/
1575
        DUMMYUSE(term)
×
1576
        DUMMYUSE(vcode)
×
1577
        DUMMYUSE(option1)
×
1578
        return(0);
×
1579
}
1580

1581
/*
1582
          #] AllOnePI : 
1583
          #[ RemoveBridges :
1584
*/
1585

NEW
1586
int RemoveBridges(void)
×
1587
{
1588
        return(0);
×
1589
}
1590

1591
/*
1592
          #] RemoveBridges : 
1593
          #[ TakeOneLine :
1594
*/
1595

1596
int TakeOneLine(WORD*term,WORD level)
×
1597
{
1598
        DUMMYUSE(term)
×
1599
        DUMMYUSE(level)
×
1600
        return(0);
×
1601
}
1602

1603
/*
1604
          #] TakeOneLine : 
1605
          #[ OutputOnePI :
1606
*/
1607

1608
int OutputOnePI(PHEAD WORD *term,WORD level)
×
1609
{
1610
        return(Generator(BHEAD term,level));
×
1611
}
1612

1613
/*
1614
          #] OutputOnePI : 
1615
*/
1616

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc