SWI-Prolog / issues

Dummy repository for issue tracking
7 stars 3 forks source link

Version 8.0.1 non-termination (exception handling?) #82

Closed ridgeworks closed 5 years ago

ridgeworks commented 5 years ago

SWI-Prolog version 8.0.1 on MacOS 10.13.4

I've been working on a CLP over reals using interval arithmetic and have a test example that worked as expected on version 7.6.4 but fails to terminate on 8.0.1. It can be reproduced using the the clpBNR module at https://github.com/ridgeworks/clpBNR_pl . This version is entirely implemented in SWI-Prolog; no foreign language component as in previous incarnations.

To reproduce load consult the file "clpBNR.pl" in the src/ directory and enter the query:

?- {-2*X2+3XY+4sin(Y)==6,3X2-2XY*2+3cos(X)== -4},solve(X).

and keep producing answers (using ';' key). The behaviour on Versions 7.6.4 and 8.0.1 are shown below. Version 7.6.4 produces 6 answers; version 8.0.1 produces 1 answer and then hangs. If I interrupt it (Ctrl-C) and output the goal stack, it seems to be always in the area of recovering from floating point exceptions. Floating point exceptions are expected but there is code to handle them (which seems to work as expected in 7.6.4). The problem may not be in the exception handling, but that's my best guess. I'll keep working to find a simpler example.


Welcome to SWI-Prolog (threaded, 64 bits, version 7.6.4) SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software. Please run ?- license. for legal details.

For online help and background, visit http://www.swi-prolog.org For built-in help, use ?- help(Topic). or ?- apropos(Word).

% v0.7alpha_clpBNR_pl/src/clpBNR.pl compiled into clpBNR 0.07 sec, 660 clauses

clpBNR v0.7alpha ?- {-2*X2+3XY+4sin(Y)==6,3X2-2XY*2+3cos(X)== -4},solve(X). X = _258::real(-1.1125369292536007e-308,0.0), Y = _480::real(-1.0Inf,1.0Inf) X = _258::real(0.0,4.450147717014403e-308), Y = _480::real(-1.0Inf,1.0Inf) X = _258::real(0.5798290523438088,0.5798291270022011), Y = _480::real(2.546209087404023,2.5462093160895334) X = _258::real(2.592164240559099,2.592164611046004), Y = _480::real(2.041151895581895,2.0411523411356467) X = _258::real(2.592164611046004,2.5921649815329615), Y = _480::real(2.041151994554312,2.0411524401080783) X = _258::real(2.5921649815329615,2.5921653520199723), Y = _480::real(2.0411520935267653,2.041152539080547) false.

?-


Welcome to SWI-Prolog (threaded, 64 bits, version 8.0.1) SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software. Please run ?- license. for legal details.

For online help and background, visit http://www.swi-prolog.org For built-in help, use ?- help(Topic). or ?- apropos(Word).

% swiCLPBNR/v0.7alpha_clpBNR_pl/src/clpBNR.pl compiled into clpBNR 0.07 sec, 660 clauses

clpBNR v0.7alpha ?- {-2*X2+3XY+4sin(Y)==6,3X2-2XY*2+3cos(X)== -4},solve(X). X = _258::real(-1.1125369292536007e-308,0.0), Y = 480::real(-1.0Inf,1.0Inf) Action (h for help) ? goals [351] clpBNR:recover(2.247204650252256e-951.0Inf,float_overflow,_79128) [350] clpBNR:recover(2.247204650252256e-951.0Inf,error(evaluation_error(float_overflow),context(system:(is)/2,_79146)),_79128) [349] catch(,error(evaluation_error(float_overflow),context(system:(is)/2,_79146)),) [348] clpBNR:isH(_79128,) [347] clpBNR:multCase(s,s,,,[-1.0Inf,_79104]) Action (h for help) ? continue Action (h for help) ? goals [430] prolog_exception_hook(error(evaluation_error(float_overflow),context(system:(is)/2,_96000)),_96052,27211,27169) [428] _96050 is 4.758640944966844e-117 -1.0Inf [427] clpBNR:evalDown(_95942,4.758640944966844e-117 -1.0Inf) [426] catch(clpBNR:evalDown(_95942,4.758640944966844e-117 -1.0Inf),error(evaluation_error(float_overflow),context(system:(is)/2,_96000)),clpBNR:recover(4.758640944966844e-117 -1.0Inf,error(evaluation_error(float_overflow),context(system:(is)/2,_96000)),_95942)) [425] clpBNR:isL(,) Action (h for help) ? continue Action (h for help) ? goals [468] prolog_exception_hook(error(evaluation_error(float_overflow),context(system:(is)/2,_104898)),_104950,29815,29773) [466] _104948 is 1.731183490834826e-1281.0Inf [465] clpBNR:evalUp(_104840,1.731183490834826e-1281.0Inf) [464] catch(clpBNR:evalUp(_104840,1.731183490834826e-1281.0Inf),error(evaluation_error(float_overflow),context(system:(is)/2,_104898)),clpBNR:recover(1.731183490834826e-1281.0Inf,error(evaluation_error(float_overflow),context(system:(is)/2,_104898)),_104840)) [463] clpBNR:isH(,) Action (h for help) ? abort % Execution Aborted ?-

JanWielemaker commented 5 years ago

?- {-2_X2+3_X_Y+4_sin(Y)==6,3_X2-2_X_Y**2+3_cos(X)== -4},solve(X).

ERROR: Syntax error: Operator expected ERROR: {- ERROR: here ERROR: 2X2+3XY+4sin(Y)==6,3X2-2XY**2+3cos(X)== -4},solve(X) .

which seems quite reasonable. What am I missing?

ridgeworks commented 5 years ago

I appear to have been "markdowned". Here's the plain text query:

?- {-2*X2+3XY+4sin(Y)==6,3X2-2XY*2+3cos(X)== -4},solve(X).

Sorry for the confusion.

Rick

On Jan 29, 2019, at 3:25 PM, Jan Wielemaker notifications@github.com wrote:

?- {-2_X2+3_X_Y+4_sin(Y)==6,3_X2-2_X_Y**2+3_cos(X)== -4},solve(X).

ERROR: Syntax error: Operator expected ERROR: {- ERROR: here ERROR: 2X2+3XY+4sin(Y)==6,3X2-2XY**2+3cos(X)== -4},solve(X) .

which seems quite reasonable. What am I missing?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/SWI-Prolog/issues/issues/82#issuecomment-458693719, or mute the thread https://github.com/notifications/unsubscribe-auth/AG5UwShQY_o8xk_fsLMX3jtmsE4yXXmNks5vIK4lgaJpZM4aY2XK.

JanWielemaker commented 5 years ago

On Linux we get this, both on 7.6 and 8.1.

7 ?- {-2*X**2+3*X*Y+4*sin(Y)==6,3*X**2-2*X*Y**2+3*cos(X)== -4},solve(X).
Aborted

And gdb tells me

Thread 1 "swipl" received signal SIGFPE, Arithmetic exception.
__GI_raise (sig=<optimized out>) at ../sysdeps/unix/sysv/linux/raise.c:51
51  ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  __GI_raise (sig=<optimized out>) at ../sysdeps/unix/sysv/linux/raise.c:51
#1  0x00007ffff71de66e in __gmp_invalid_operation ()
   from /usr/lib/x86_64-linux-gnu/libgmp.so.10
#2  0x00007ffff71f6a85 in __gmpz_set_d ()
   from /usr/lib/x86_64-linux-gnu/libgmp.so.10
#3  0x00007ffff7ab9494 in ar_integer (n1=0x7fffffffd028, r=0x7fffffffcf20)
    at ../src/pl-arith.c:2925
#4  0x00007ffff7abc287 in valueExpression (expr=expr@entry=344, 
    result=result@entry=0x7fffffffd2f0, 
    __PL_ld=__PL_ld@entry=0x7ffff7dd23a0 <PL_local_data>)
    at ../src/pl-arith.c:837
#5  0x00007ffff7abcbb1 in pl_is2_va (PL__t0=343, PL__ac=<optimized out>, 
    PL__ctx=<optimized out>) at ../src/pl-arith.c:3561

That is not supposed to happen ... There is no change AFAIK to arithmetic that seems relevant, so I guess the most likely cause is the new CMake based configuration. Anyway, first the above should become a normal Prolog exception.

JanWielemaker commented 5 years ago

Hmm. What about this:

(gdb) call PL_backtrace(25,0)
 [23] _7468 is round(-1.0Inf)
 [22] <meta-call>(clpBNR:(_7468 is round(-1.0Inf),_7474 is round(1.0Inf)))
 [21] catch(clpBNR:(_7468 is round(-1.0Inf),_7474 is round(1.0Inf)),_7798,clpBNR:fail)

Of course this should be a Prolog exception, but is this expected? ini is not an ISO concept and the IEEE special values are mostly supported to get input from foreign code that passes NaN values. Arithmetic using them is not very well defined. Probably anything but A is inf and A =:= inf and similar constructs should raise an exception.

What do you expect from NaN support?

ridgeworks commented 5 years ago

For completeness, my "real" domain should include the infinities as possibilities for upper and lower bounds, as in CLP(FD) . The intent is turn exceptions into appropriate values for the bounds. Of course it can be difficult to narrow an interval with infinite bounds, so it's best to constrain them to a more "useful" range. But that's a "user" issue.

As long as proper Prolog exceptions are raised and the recovery underpinnings, i.e., catch, work as advertised, I'm happy.

On Jan 29, 2019, at 3:46 PM, Jan Wielemaker notifications@github.com wrote:

Hmm. What about this:

(gdb) call PL_backtrace(25,0) [23] _7468 is round(-1.0Inf) [22] (clpBNR:(_7468 is round(-1.0Inf),_7474 is round(1.0Inf))) [21] catch(clpBNR:(_7468 is round(-1.0Inf),_7474 is round(1.0Inf)),_7798,clpBNR:fail) Of course this should be a Prolog exception, but is this expected? ini is not an ISO concept and the IEEE special values are mostly supported to get input from foreign code that passes NaN values. Arithmetic using them is not very well defined. Probably anything but A is inf and A =:= inf and similar constructs should raise an exception.

What do you expect from NaN support?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/SWI-Prolog/issues/issues/82#issuecomment-458700520, or mute the thread https://github.com/notifications/unsubscribe-auth/AG5Uwf_0XMD8196z1PYCvH8XgvBbep5Fks5vILMogaJpZM4aY2XK.

ridgeworks commented 5 years ago

As previously stated, proper Prolog exceptions should do the trick. I'm a bit baffled that Linux and Mac behave so differently, but maybe that's just the CMake issue. Come to think of it, CMake may be root cause of the Mac GUI issues as well (#83).

On Jan 29, 2019, at 3:37 PM, Jan Wielemaker notifications@github.com wrote:

On Linux we get this, both on 7.6 and 8.1.

7 ?- {-2*X2+3XY+4sin(Y)==6,3X2-2XY*2+3cos(X)== -4},solve(X). Aborted And gdb tells me

Thread 1 "swipl" received signal SIGFPE, Arithmetic exception. __GI_raise (sig=) at ../sysdeps/unix/sysv/linux/raise.c:51 51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory. (gdb) bt

0 __GI_raise (sig=) at ../sysdeps/unix/sysv/linux/raise.c:51

1 0x00007ffff71de66e in __gmp_invalid_operation ()

from /usr/lib/x86_64-linux-gnu/libgmp.so.10

2 0x00007ffff71f6a85 in __gmpz_set_d ()

from /usr/lib/x86_64-linux-gnu/libgmp.so.10

3 0x00007ffff7ab9494 in ar_integer (n1=0x7fffffffd028, r=0x7fffffffcf20)

at ../src/pl-arith.c:2925

4 0x00007ffff7abc287 in valueExpression (expr=expr@entry=344,

result=result@entry=0x7fffffffd2f0, 
__PL_ld=__PL_ld@entry=0x7ffff7dd23a0 <PL_local_data>)
at ../src/pl-arith.c:837

5 0x00007ffff7abcbb1 in pl_is2_va (PLt0=343, PLac=,

PL__ctx=<optimized out>) at ../src/pl-arith.c:3561

That is not supposed to happen ... There is no change AFAIK to arithmetic that seems relevant, so I guess the most likely cause is the new CMake based configuration. Anyway, first the above should become a normal Prolog exception.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/SWI-Prolog/issues/issues/82#issuecomment-458697799, or mute the thread https://github.com/notifications/unsubscribe-auth/AG5UwUEsKxTQnvlPpzKLbzhlazFrKByIks5vILEkgaJpZM4aY2XK.

ridgeworks commented 5 years ago

As stated previously, proper Prolog exceptions and handling should be fine. But I'm a bit baffled at the difference between Mac and Linux; maybe that's all attributable to CMake. Come to think of it, maybe CMake is also the root cause of the Mac GUI regression (#83).

While we're discussing arithmetic on infinities: on either 7.6.4 or 8.0.1 Mac versions:

?- Xcp is ceiling(inf), Xcm is ceiling(-inf), Xfp is floor(inf), Xfm is floor(-inf). Xcp = Xcm, Xcm = Xfp, Xfp = Xfm, Xfm = -9223372036854775808.

?- Xr is round(inf). ERROR: Caught signal 8 (fpe) ERROR: In: ERROR: [8] _4858 is round(inf) ERROR: [7]

which isn't correct IMO.

On Jan 29, 2019, at 3:37 PM, Jan Wielemaker notifications@github.com wrote:

On Linux we get this, both on 7.6 and 8.1.

7 ?- {-2*X2+3XY+4sin(Y)==6,3X2-2XY*2+3cos(X)== -4},solve(X). Aborted And gdb tells me

Thread 1 "swipl" received signal SIGFPE, Arithmetic exception. __GI_raise (sig=) at ../sysdeps/unix/sysv/linux/raise.c:51 51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory. (gdb) bt

0 __GI_raise (sig=) at ../sysdeps/unix/sysv/linux/raise.c:51

1 0x00007ffff71de66e in __gmp_invalid_operation ()

from /usr/lib/x86_64-linux-gnu/libgmp.so.10

2 0x00007ffff71f6a85 in __gmpz_set_d ()

from /usr/lib/x86_64-linux-gnu/libgmp.so.10

3 0x00007ffff7ab9494 in ar_integer (n1=0x7fffffffd028, r=0x7fffffffcf20)

at ../src/pl-arith.c:2925

4 0x00007ffff7abc287 in valueExpression (expr=expr@entry=344,

result=result@entry=0x7fffffffd2f0, 
__PL_ld=__PL_ld@entry=0x7ffff7dd23a0 <PL_local_data>)
at ../src/pl-arith.c:837

5 0x00007ffff7abcbb1 in pl_is2_va (PLt0=343, PLac=,

PL__ctx=<optimized out>) at ../src/pl-arith.c:3561

That is not supposed to happen ... There is no change AFAIK to arithmetic that seems relevant, so I guess the most likely cause is the new CMake based configuration. Anyway, first the above should become a normal Prolog exception.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/SWI-Prolog/issues/issues/82#issuecomment-458697799, or mute the thread https://github.com/notifications/unsubscribe-auth/AG5UwUEsKxTQnvlPpzKLbzhlazFrKByIks5vILEkgaJpZM4aY2XK.

JanWielemaker commented 5 years ago

as in CLP(FD)

CLP(FD) represents unbounded interval as inf..sup, two Prolog atoms and wraps the arithmetic operators to deal with this in an appropriate way.

(ISO) Prolog defines floating point operations that result in NaN/Inf to raise an exception, so these numbers never enter the computation. SWI-Prolog, following ECLiPSe, added Inf and NaN to the syntax, so we can deal with import and export of these reserved floats through the foreign interface. AFAIK, ECLiPSe also has a mode that deals with these numbers, so A is inf+inf results in A =:= inf. In SWI-Prolog that raises a float_overflow exception.

I'm unsure what should happen. Surely A is round(inf) shouldn't crash. What should it do though? There is no suitable integer representation for infinity. So, ceiling, floor, round, etc. must raise an error. I'm not entirely sure which one. Possibly float_overflow is the most obvious choice?

JanWielemaker commented 5 years ago

pushed 54866ebb818b13aaa548325318f6c1900e3e1bd5 to swipl-devel that calls check_float() whenever a float needs to be converted into an integer. check_float() normally maps Inf/Nan, etc to exceptions after a floating point computation.

ridgeworks commented 5 years ago

I think my requirements are simple, and it all works in 7.6.4 Mac version with the exception of ceiling/floor where I've added "guard" code to handle the special case.

  1. Any IEEE 754 Inf/NaN results should generate "catchable" Prolog exceptions, presumably float overflow and undefined as is done presently (for the most part).

  2. Any functions that take floats as arguments but return integers, like ceiling/floor, should do likewise.

The alternative would require the SWI-Prolog arithmetic support to deal with non-numbers like ECLIPSe does. That would be nice, but I'm not asking for it.

However, I don't think this is addressing the main problem raised by the bug report, namely the seeming nontermination in 8.0.1 that didn't occur in 7.6.4 on the Mac release. (I understand that the Linux version might be different again.). Re-reading the notes in the "News" item, this gave me pause:

Stability Many fixes to exception handling Avoid that exceptions are silently ignored in C code and thus abort or timeout is ignored. More sensible handling of exceptions while exceptions are being processed.

On Jan 30, 2019, at 4:29 AM, Jan Wielemaker notifications@github.com wrote:

as in CLP(FD)

CLP(FD) represents unbounded interval as inf..sup, two Prolog atoms and wraps the arithmetic operators to deal with this in an appropriate way.

(ISO) Prolog defines floating point operations that result in NaN/Inf to raise an exception, so these numbers never enter the computation. SWI-Prolog, following ECLiPSe, added Inf and NaN to the syntax, so we can deal with import and export of these reserved floats through the foreign interface. AFAIK, ECLiPSe also has a mode that deals with these numbers, so A is inf+inf results in A =:= inf. In SWI-Prolog that raises a float_overflow exception.

I'm unsure what should happen. Surely A is round(inf) shouldn't crash. What should it do though? There is no suitable integer representation for infinity. So, ceiling, floor, round, etc. must raise an error. I'm not entirely sure which one. Possibly float_overflow is the most obvious choice?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/SWI-Prolog/issues/issues/82#issuecomment-458873804, or mute the thread https://github.com/notifications/unsubscribe-auth/AG5UwV2-qrf8LDhA-wWB2WWb2LHtbYppks5vIWYCgaJpZM4aY2XK.

JanWielemaker commented 5 years ago

With the given patch , I get this:

6 ?- time(({-2*X**2+3*X*Y+4*sin(Y)==6,3*X**2-2*X*Y**2+3*cos(X)== -4},solve(X))).
% 11,235 inferences, 0.002 CPU in 0.002 seconds (100% CPU, 4846334 Lips)
X = _468::real(-1.1125369292536007e-308,0.0),
Y = _690::real(-1.0Inf,1.0Inf) ;
% 6,451,661 inferences, 31.237 CPU in 31.237 seconds (100% CPU, 206542 Lips)
X = _456::real(0.0,4.450147717014403e-308),
Y = _678::real(-1.0Inf,1.0Inf) ;
% 5,674,941 inferences, 13.642 CPU in 13.642 seconds (100% CPU, 415982 Lips)
X = _456::real(0.5798290523438088,0.5798291270022011),
Y = _678::real(2.546209087404023,2.5462093160895334) ;
% 1,762,832 inferences, 0.252 CPU in 0.252 seconds (100% CPU, 6993080 Lips)
X = _456::real(2.592164240559099,2.592164611046004),
Y = _678::real(2.041151895581895,2.0411523411356467) ;
% 5,042 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 6266904 Lips)
X = _456::real(2.592164611046004,2.5921649815329615),
Y = _678::real(2.041151994554312,2.0411524401080783) ;
% 51,294 inferences, 0.009 CPU in 0.009 seconds (100% CPU, 6005264 Lips)
X = _456::real(2.5921649815329615,2.5921653520199723),
Y = _678::real(2.0411520935267653,2.041152539080547) ;
% 2,649,573 inferences, 0.462 CPU in 0.462 seconds (100% CPU, 5733225 Lips)
false.

Same result on the mac when compiling with this patch. The second answer is slow. I don't know whether that is very different from what it used to be. Apparently round(inf) did not crash on the Mac, did it do anything sensible though? And (how) did this result affect the computation?

ridgeworks commented 5 years ago

This is the expected result (see original bug report 7.6.4), so this issue can be closed. This query is part of an informal test suite to make sure infinite bounds are handled, but normal use would constrain the bounds.

Regarding round, the only place it's used is within a catch/3 where the exception can be "any" and recovery goal is fail:

catch((MXl is round(FMl), MXh is round(FMh)),_,fail),

And, in this case, failure is an expected result whenever the interval range is too wide. On the Mac an exeception is raised, just not a floating point overflow, but it doesn't matter.

?- X is round(inf). ERROR: Caught signal 8 (fpe) ERROR: In: ERROR: [8] _1158 is round(inf) ERROR: [7]

On Jan 30, 2019, at 10:08 AM, Jan Wielemaker notifications@github.com wrote:

With the given patch , I get this:

6 ?- time(({-2*X2+3XY+4sin(Y)==6,3X2-2XY*2+3cos(X)== -4},solve(X))). % 11,235 inferences, 0.002 CPU in 0.002 seconds (100% CPU, 4846334 Lips) X = _468::real(-1.1125369292536007e-308,0.0), Y = _690::real(-1.0Inf,1.0Inf) ; % 6,451,661 inferences, 31.237 CPU in 31.237 seconds (100% CPU, 206542 Lips) X = _456::real(0.0,4.450147717014403e-308), Y = _678::real(-1.0Inf,1.0Inf) ; % 5,674,941 inferences, 13.642 CPU in 13.642 seconds (100% CPU, 415982 Lips) X = _456::real(0.5798290523438088,0.5798291270022011), Y = _678::real(2.546209087404023,2.5462093160895334) ; % 1,762,832 inferences, 0.252 CPU in 0.252 seconds (100% CPU, 6993080 Lips) X = _456::real(2.592164240559099,2.592164611046004), Y = _678::real(2.041151895581895,2.0411523411356467) ; % 5,042 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 6266904 Lips) X = _456::real(2.592164611046004,2.5921649815329615), Y = _678::real(2.041151994554312,2.0411524401080783) ; % 51,294 inferences, 0.009 CPU in 0.009 seconds (100% CPU, 6005264 Lips) X = _456::real(2.5921649815329615,2.5921653520199723), Y = _678::real(2.0411520935267653,2.041152539080547) ; % 2,649,573 inferences, 0.462 CPU in 0.462 seconds (100% CPU, 5733225 Lips) false. Same result on the mac when compiling with this patch. The second answer is slow. I don't know whether that is very different from what it used to be. Apparently round(inf) did not crash on the Mac, did it do anything sensible though? And (how) did this result affect the computation?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/SWI-Prolog/issues/issues/82#issuecomment-458978048, or mute the thread https://github.com/notifications/unsubscribe-auth/AG5UwRdDpfIDbbXSDHPmObKVG_gB3SPGks5vIbVTgaJpZM4aY2XK.

JanWielemaker commented 5 years ago

?- X is round(inf). ERROR: Caught signal 8 (fpe)

This may be part of the problem. Signals and threads are a difficult combination and mapping signals to exceptions was broken for a long time, where it sometimes worked. In 7.6 there was just a single thread if you didn't use threads, but recent versions always run multiple threads unless you really tell it not to do so.