vermaseren / form

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

Getting a meaningful print output on errors #370

Closed vsht closed 3 years ago

vsht commented 3 years ago

Hi,

when writing my FORM codes I tend to introduce a lot of intermediate checks using if and occurs to ensure the correctness of my intermediate results.

This all works as expected, yet when my code does detect an error and initiates an emergency exit, I'm struggling with getting a meaningful print output.

Ideally, when the intermediate looks wrong I would like FORM to organize the terms in such a way that I can see what precisely triggered the watchdog.

To be more precise, consider e.g.

off statistics;
CF foo, bar;
Auto index i;
L exp = (foo(1,2,3) + foo(3,4,5) + foo(6,7,8,9))^6;

id foo(i1?,i2?,i3?) = bar(i1,i2,i3);

if (occurs(foo)) exit "not all foos were replaced!";

.end

The above code will correctly stop the evaluation when something goes wrong, but there is no way to tell what was the real reason for that. So one would need to temporarily edit the script and put in some bracket and print[] statements to diagnose the problem:

off statistics;
CF foo, bar;
Auto index i;
L exp = (foo(1,2,3) + foo(3,4,5) + foo(6,7,8,9))^6;

id foo(i1?,i2?,i3?) = bar(i1,i2,i3);

* if (occurs(foo)) exit "not all foos were replaced!";
b bar,foo;
print[];

.end

What I would like to achieve is that such bracketing occurs automatically, but only when there is an error, so that the check by itself doesn't degrade the performance.

The closest match I managed to come up with would be this

off statistics;
CF foo, bar;
Auto index i;
L exp = (foo(1,2,3) + foo(3,4,5) + foo(6,7,8,9))^6;

id foo(i1?,i2?,i3?) = bar(i1,i2,i3);

* if (occurs(foo)) exit "not all foos were replaced!";

#$errorOccurred = 0;
if (occurs(foo));
 $errorOccurred = 1;
endif;

* this sort can degrade the performance!
.sort

#if (`$errorOccurred'==1)
.sort
b bar,foo;
print[];
.sort
exit "not all foos were replaced!";
#endif

.end

I would be mostly satisfied with this solution, yet there is an issue: without .sort before #if the value of the dollar-variable $errorOccurred doesn't seem to be set correctly, so the check won't work. However, putting an intermediate .sort "just" for a consistency check is too expensive (especially when working with large expressions), so my solution is not really practical.

Perhaps I'm missing some obvious strategy here, so I'd be happy to learn that there is a better way to accomplish what I'm trying to achieve.

Cheers, Vladyslav

jodavies commented 3 years ago

If it is enough to just print the bad term, you can do

if (occurs(foo));
   print "error! not all foos were replaced: %t";
   exit;
endif;
vsht commented 3 years ago

Thanks, this is already something, although I hoped for some
nifty trick to allow for a more elaborate error handling, including the output showing the full expression.

I guess my problem is that I would like to call an end-of-module statement (.sort) from an if-environment (which is an executable statement), hence starting a new module and discard the rest of the current module. Alternatively, I would need to perform a goto jump from one module to another, which is equally not possible.

Perhaps there is no solution to that within the current functionality of FORM.

vermaseren commented 3 years ago

A “terminate module” statement would produce a lot of problems. 1: what to do with unprocessed expressions? 2: what to do with the unprocessed part of the current expression? 3: what to do with what has already been processed and sits in the sort buffers? 4: how about the dollar variables? In principle one could try to return to the beginning of the module and then skip the module, but that runs into the problem that $-variables may no longer be the same. And possibly other objects or settings.

What will be the best approximation of what you want? How about

.sort

$flag = 0;

if ( $flag == 0 ); …code…. if ( occurs(foo) ); $flag = 1; goto endofmodule; endif; …more code…. label endofmodule; endif; .sort

if ( `$flag’ > 0 )

message !@#$%

Bracket foo; Print; .end

endif

….more code….

The last .sort is the regular .sort that you would have at the end of your module. This code stops processing more terms once an error is detected. You can put more of these if statements if you think they are needed.

Maybe you can come up with something more tailored to your problem.

On 27 Nov 2020, at 11:11, Vladyslav Shtabovenko notifications@github.com wrote:

Thanks, this is already something, although I hoped for some nifty trick to allow for a more elaborate error handling, including the output showing the full expression.

I guess my problem is that I would like to call an end-of-module statement (.sort) from an if-environment (which is an executable statement), hence starting a new module and discard the rest of the current module. Alternatively, I would need to perform a goto jump from one module to another, which is equally not possible.

Perhaps there is no solution to that within the current functionality of FORM.

— 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/370#issuecomment-734756979, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABJPCEQU7NAHZRLAKNSSYE3SR53NLANCNFSM4UD3JI6Q.

vsht commented 3 years ago

Many thanks! I think that this solves my issue pretty well.

I will have to redesign some portions of my code to have the error handling at the beginning and the end of the corresponding modules, but this way I indeed can process the errors in a very flexible way. So it is definitely worth the effort.