vermaseren / form

The FORM project for symbolic manipulation of very big expressions
GNU General Public License v3.0
982 stars 118 forks source link

$-variable pattern matching and nested denominators #400

Closed tueda closed 1 year ago

tueda commented 2 years ago

In the following program, in the 1st module, I use the denominators statement and then try a pattern matching (the id statement) with an expression captured in a $-variable, but it fails. After .sort, in the 2nd module, the same code somehow works.

#-
Off stats;
S x;
CF den;
L F = 1/(1+1/(1+x));
P +s;
.sort;
denominators den;
* Just after the denominators statement, the following doesn't work.
if (match(den(x?$x1)));
  P "matched: %$ in %t", $x1;
  id den($x1) = 1;
endif;
P +s;
.sort;
* After sorting, it works.
if (match(den(x?$x2)));
  P "matched: %$ in %t", $x2;
  id den($x2) = 1;
endif;
P +s;
.end;
FORM 4.2.1 (Nov 10 2020, v4.2.1-30-gb0e72a8) 64-bits  Run: Mon Nov 15 12:37:30 2021
    #-

   F =
       + 1/(1 + 1/(1 + x))
      ;

matched: 1 + den(1 + x) in  + den(1 + den(1 + x))

   F =
       + den(1 + den(1 + x))
      ;

matched: 1 + den(1 + x) in  + den(1 + den(1 + x))

   F =
       + 1
      ;

  0.00 sec out of 0.00 sec

If this works in the 2nd module, then it should also work in the 1st module.

benruijl commented 1 year ago

Before the sort, F looks like:

34  150  30  1  27  1  4  1  1  3  21  150  17  1  14  0  4  1  1  3  8  1  4  20
  1  1  1  3  1  1  3  1  1  3

and after like

  34  150  30  0  27  0  4  1  1  3  21  150  17  0  14  0  4  1  1  3  8  1  4  20
  1  1  1  3  1  1  3  1  1  3

The only difference is the dirty flag, which then seems to prevent the match.

Forcing a term normalization after denominators by adding a Multiply 1; removes the dirty flag and restores the pattern match.

So it seems a necessary normalization call is missing at the end of the denominators routine.

benruijl commented 1 year ago

Changing the code in proces.c to add normalization:

case TYPEDENOMINATORS:
    if ( DenToFunction(term,C->lhs[level][2]) ) Normalize(BHEAD term);
    break;

Only normalizes the first level for some reason:

34  150  30  0  27  1  4  1  1  3  21  150  17  1  14  0  4  1  1  3  8  1  4  20
  1  1  1  3  1  1  3  1  1  3
tueda commented 1 year ago

OK, so actually $-variables are not needed to reproduce this bug and a reduced test code is

S x;
CF den;
L F = 1/(1+1/(1+x));
.sort
denominators den;
P "%r";
multiply 1;
P "%r";
.end

where the two lines of P "%r" should print the same result, if the term is correctly normalized after denominators.

If you call Normalize() then maybe you need to check the return value for some errors (I'm totally not sure, though).

The following

if ( DenToFunction(term,C->lhs[level][2]) ) goto ReStart;

seems to work, but may be overkill?