vermaseren / form

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

Identification statement set restrictions don't work with preprocessor variable/procedure argument sets #408

Closed kozytskyiad closed 2 years ago

kozytskyiad commented 2 years ago

Copied almost verbatim from the FORM tutorial, answer to task 3 of section 3.1.6:

Set vec: ;
Set mat: ;

#procedure workout(mat,vec,dim)
  id p?'vec'.q?'vec' = <p(1)*q(1)> + ... + <p('dim')*q('dim')>;
  id a?'mat'(?x,p?'vec',?y) = <p(1)*a(?x,1,?y)>
                            + ...
                            + <p('dim')*a(?x,'dim',?y)>;
#endprocedure

Vectors p,q,u,v,w;
Indices i,j,k;
Tensor t,a,b;
Local F1 = u.v;
Local F2 = u.v+u.w;
Local F3 = a(i,j)*v(j);
Local F4 = a(i,j)*u(i);
Local F5 = a(i,j)*u(i)*v(j);
Local F6 = b(i,j,k)*u(i)*v(j)*w(k);
Print;
.sort

Set matrices: a, b;
Set vectors: u, v, w;
repeat;
  #call workout(matrices, vectors, 2)
endrepeat;
Print;
.end

This results in:

    repeat;
      #call workout(matrices, vectors, 2)
workout Line 2 --> Illegal option p in id-statement
workout Line 2 --> Illegal option vectors in id-statement
workout Line 2 --> Internal error in code generator. Unknown object: -5
workout Line 2 --> Internal error in code generator. Unknown object: 16
workout Line 5 ==> Undefined preprocessor variable dim
Program terminating at workout Line 3 --> 
  0.00 sec out of 0.00 sec

FORM seems to be running into issues interpreting the arguments as sets. Reducing the procedure to a minimal example:

#procedure workout(mat,vec,dim)
  id p?'vec' = 1;
#endprocedure

produces:

    repeat;
      #call workout(matrices, vectors, 2)
workout Line 2 --> Illegal option p in id-statement
workout Line 2 --> Internal error in code generator. Unknown object: -5
workout Line 2 --> Internal error in code generator. Unknown object: 16
    endrepeat;
    Print;
    .end
Program terminating at ex-3-1-6/3.frm Line 25 --> 
  0.00 sec out of 0.00 sec
tueda commented 2 years ago

The tutorial was written for FORM version 2, which is a different language from version 4 (in the sense of Python 2 vs. Python 3, or FORTRAN 77 vs. Fortran 2018). It may be a fun exercise to rewrite the FORM version 2 answer in such a way that it works with version 4.

(For future reference: can we update the tutorial for the latest version of FORM?)

The issue here is that one needs to use the #call instruction without spaces:

  #call workout(matrices,vectors,2)

Otherwise, erroneous spaces will contaminate the preprocessed source code and lead to the syntax error you saw. (Running with the -y option, form -y program.frm, shows what FORM parsed, line by line.)

For completeness, here is the rewritten answer and its output (of the 2nd module):

Set mat: ;
Set vec: ;

#procedure workout(mat,vec,dim)
  id p?`vec'.q?`vec' = <p(1)*q(1)> + ... + <p(`dim')*q(`dim')>;
  id t?`mat'(?a,p?`vec',?b) =
     <p(1)*t(?a,1,?b)> + ... + <p(`dim')*t(?a,`dim',?b)>;
#endprocedure

Vectors p,q,u,v,w;
Indices i,j,k;
Tensor t,a,b;
Local F1 = u.v;
Local F2 = u.v+u.w;
Local F3 = a(i,j)*v(j);
Local F4 = a(i,j)*u(i);
Local F5 = a(i,j)*u(i)*v(j);
Local F6 = b(i,j,k)*u(i)*v(j)*w(k);
Print;
.sort

Set matrices:  a,b;
Set vectors: u,v,w;
repeat;
  #call workout(matrices,vectors,2)
endrepeat;
Print;
.end
   F1 =
      u(1)*v(1) + u(2)*v(2);

   F2 =
      u(1)*v(1) + u(1)*w(1) + u(2)*v(2) + u(2)*w(2);

   F3 =
      a(i,1)*v(1) + a(i,2)*v(2);

   F4 =
      a(1,j)*u(1) + a(2,j)*u(2);

   F5 =
      a(1,1)*u(1)*v(1) + a(1,2)*u(1)*v(2) + a(2,1)*u(2)*v(1) + a(2,2)*u(2)*
      v(2);

   F6 =
      b(1,1,1)*u(1)*v(1)*w(1) + b(1,1,2)*u(1)*v(1)*w(2) + b(1,2,1)*u(1)*v(2)*
      w(1) + b(1,2,2)*u(1)*v(2)*w(2) + b(2,1,1)*u(2)*v(1)*w(1) + b(2,1,2)*u(2)
      *v(1)*w(2) + b(2,2,1)*u(2)*v(2)*w(1) + b(2,2,2)*u(2)*v(2)*w(2);
kozytskyiad commented 2 years ago

This works, thank you for the hint!