vermaseren / form

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

Loop over currently active expressions #175

Closed jodavies closed 7 years ago

jodavies commented 7 years ago

This is a question rather than a bug report,

If I don't know what expressions are currently active or their names, is there any way to perform an operation like

#do i = {list of active expressions}
   Local `i' = `i' + something;
#enddo

?

Thanks, Josh.

tueda commented 7 years ago

This is a feature what I wanted to add into FORM, to improve a user interface of some library, but other collaborators seemed not to be interested in. Now we have at least 2 persons who want to do this within FORM without external scripting. One way is to introduce a new preprocessor variable that returns a list of active expressions, say exprs_, implemented like tueda/form@5777c9eb37f81b4062100530a0dff786ca7a1e2f (maybe more proper names?, like numactiveexprs_ and activeexprnames_). Once a consensus is achieved for the names (and if there is no apparent bug), I can push this patch.

tueda commented 7 years ago

And the following is a way with calling FORM from FORM (not recommended):

*--#[ GetExprs : GetExprs(outvarname)

#procedure GetExprs(outvarname)
* Extract active expression names from "Expressions to be printed" of
* "On names".

* FIXME: The following code gives wrong results when the names contain
*        double quotations (e.g., ["x"]).
  #ifndef `GETEXPRS_'
    #system form -D GETEXPRS_ `NAME_' >`NAME_'.`PID_'.exprs.tmp
    #system printf "#redefine `outvarname'\"" >`NAME_'.`PID_'.exprs.out
    #system cat `NAME_'.`PID_'.exprs.tmp \
      | sed "1,/GETEXPRS START/d" \
      | sed "1,/Expressions to be printed/d" \
      | sed -n "/^   /!q;p" \
      | perl -pe "s/\\n/ /g" \
      | perl -pe "s/ +/ /g;s/^ //;s/ $//" \
      | perl -pe "s/,/\\\\,/g;s/ /,/g" \
      >>`NAME_'.`PID_'.exprs.out
    #system echo "\"" >>`NAME_'.`PID_'.exprs.out
    #include `NAME_'.`PID_'.exprs.out
    #remove <`NAME_'.`PID_'.exprs.tmp>
    #remove <`NAME_'.`PID_'.exprs.out>
  #else
    .sort
    #message GETEXPRS START
    On names;
    P;
    .end
  #endif
#endprocedure

*--#] GetExprs :

L F = 1;
L G = 1;
.sort

#define list
#call GetExprs(list)
#message `list'
.end
benruijl commented 7 years ago

I think this is a very good addition.

vermaseren commented 7 years ago

I agree

Jos

On 17 mrt. 2017, at 12:00, Ben Ruijl notifications@github.com wrote:

I think this is a very good addition.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/vermaseren/form/issues/175#issuecomment-287325934, or mute the thread https://github.com/notifications/unsubscribe-auth/AFLxEt9-OdAi9y_cANg4O2up0h9rSNu_ks5rmmfSgaJpZM4MgZDq.

tueda commented 7 years ago

So, numactiveexprs_ and activeexprnames_ would be OK? In this way we could later put other variables for inactive or hidden expressions, etc., if one needs in future.

@vermaseren What is the difference between variables defined in startup.c and those without PutPreVar?

vermaseren commented 7 years ago

Sounds fine.

On 17 mrt. 2017, at 15:20, Takahiro Ueda notifications@github.com wrote:

So, numactiveexprs and activeexprnames would be OK? In this way we could later put other variables for inactive or hidden expressions, etc., if one needs in future.

@vermaseren https://github.com/vermaseren What is the difference between variables defined in startup.c and those without PutPreVar?

Mainly history. It started without and later PutPreVar was used.

Jos

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/vermaseren/form/issues/175#issuecomment-287366668, or mute the thread https://github.com/notifications/unsubscribe-auth/AFLxEhvhIPnRjpl_On5lTSNvgwfekhCDks5rmpa-gaJpZM4MgZDq.

tueda commented 7 years ago

Jos, so I should put dummy values somehow for numactiveexprs_ and activeexprnames_ in the startup, right?

tueda commented 7 years ago

timer_ and stopwatch_ are relatively new but don't have dummy values in startup.c???

vermaseren commented 7 years ago

Hi Takahiro,

At inspection, it is not entirely history. The variables that have a fixed value go via PutPreVar.

Here you can do without PutPreVar. You just check for the trailing underscore and then you go through a list of possibilities as with time or timer. Hence you just add your two variables and put the proper code in place. If you want to keep a concise structure, for the list of variables you can make a subroutine, if the code becomes too long. Because the size is not fixed you will have to have a way to free it if its value is not zero and hence there should be a string pointer in the AP struct for this.

Cheers

Jos

On 17 mrt. 2017, at 15:32, Takahiro Ueda notifications@github.com wrote:

Jos, so I should put dummy values somehow for numactiveexprs and activeexprnames in the startup, right?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/vermaseren/form/issues/175#issuecomment-287369898, or mute the thread https://github.com/notifications/unsubscribe-auth/AFLxEthwmOc5eoQNZ1D0vW06cxkmAxk9ks5rmpl2gaJpZM4MgZDq.

tueda commented 7 years ago

The patch is merged to the master branch and now you can test it.

jodavies commented 7 years ago

Thanks! This loop works as expected:

#do expr = {`activeexprnames_'}
    #if `ZERO_`expr''
        Local `expr' = `expr';
    #else
        Local `expr' = `expr' + something;
    #endif
#enddo
jodavies commented 7 years ago

Hello,

I found some buggy behaviour; redefined expressions mess up `activeexprnames_' within the module they are redefined. Everything is OK after a sort. For eg,

#-
Off Statistics;
Symbol x;

Local test1 = x;
Local test2 = x;
Local test3 = x;
* redeclare!
Local test1 = x;

* Fixes problem:
*.sort

#message `numactiveexprs_'
#message `activeexprnames_'
.end

gives

~~~3
~~~test2,test3,

Thanks! Josh.

tueda commented 7 years ago

I assumed that strlen(AC.exprnames->namebuffer + e->name) is always equals to e->namesize, but apparently wrong in this case (the latter is 0). Now I'm starting to wonder the meaning of e->namesize...

jodavies commented 7 years ago

Further, and presumably related, in a case like

#-
Off Statistics;

CFunction F1,F2,F3;

Local [F1(1,1,1,1)] = F1(1,1,1,1);
Local [F2(-1,1,1,1)] = F2(-1,1,1,1);
.sort

* Redefine:
Local [F1(1,1,1,1)] = F1(1,1,1,1);
.sort

#message `activeexprnames_'

#do i = {`activeexprnames_'}
    #if `ZERO_`i''
        Drop `i';
    #endif
#enddo

.end

The ] gets chopped from the the name of [F2(-1\,1\,1\,1)], resulting in

TFORM 4.1 (Mar 17 2017, v4.1-20131025-304-g7c56626) 64-bits 4 workers  Run: Fri Mar 31 15:18:06 2017
    #-
~~~[F2(-1\,1\,1\,1),[F1(1\,1\,1\,1)]
test2.frm Line 18 ==> Undefined preprocessor variable ZERO_[F2(-1,1,1,1)
Program terminating in thread 0 at test2.frm Line 17 --> 
Max. space for expressions:                 476 bytes
  0.00 sec + 0.00 sec: 0.00 sec out of 0.00 sec

Josh.

tueda commented 7 years ago

@vermaseren It turned out that e->namesize is not reliable when replacements of expressions occur. Instead, can I assume that AC.exprnames->namebuffer + e->name always points to a valid address such that I can just use StrLen()?

vermaseren commented 7 years ago

If you look in names.c in AddExpression you can see what happens. In the case of reusing the same name the namesize seems to be set to zero. Otherwise it is the stringlength+1, because it is the size it takes in the buffer. The overwriting just copies the address of the original name (to avoid getting holes in the nametree). Hence I would not have expected problems there. On the other hand: the namesize does not seem to be used much. Maybe it should also be set nonzero in names.c, but at the moment I cannot oversee whether that would cause other problems. Because everything there seemed to work before the new feature, it seems best to leave things as they are there, unless the exchanging of expressions gives problems after redefining expressions.

Jos

On 31 mrt. 2017, at 15:28, Takahiro Ueda notifications@github.com wrote:

@vermaseren https://github.com/vermaseren It turned out that e->namesize is not reliable when replacements of expressions occur. Instead, can I assume that AC.exprnames->namebuffer + e->name is always valid such that I can just use StrLen()?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/vermaseren/form/issues/175#issuecomment-290711950, or mute the thread https://github.com/notifications/unsubscribe-auth/AFLxEjjb4qrsceQWscO8aaL1xnhkhpsMks5rrP-agaJpZM4MgZDq.

tueda commented 7 years ago

Use of StrLen() with assuming e->name is always valid seems to work.