scryer-prolog icon indicating copy to clipboard operation
scryer-prolog copied to clipboard

clpz: popcount/1 and (^)/2 crash

Open UWN opened this issue 2 years ago • 11 comments

?- X is -1^ -1.
   X = -1. % expected
?- X#=popcount(-1).
   X = 64. % not sure if this is OK
?- X#=popcount(-1^ -1).
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/machine/system_calls.rs:6834:51
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

UWN avatar Jan 28 '23 09:01 UWN

This X = 64. still looks strange to me.

UWN avatar Feb 03 '23 10:02 UWN

#999 still an issue? #998 popcount controversy; research participants :-) think it should be a domain error. Hint: In the Lisp spirit, the popcount of a negative integer is the number of 0 bits in 2's complement. So X = 64 is wrong.

flexoron avatar Feb 06 '23 12:02 flexoron

@flexoron: Ad domain_error: In general, a domain error may be produced by a built-in predicate like popcount/2, but not by arithmetic evaluation alone. Thus SWI's

?- catch(X is popcount(-1),error(E,_), true).
   E = domain_error(not_less_than_zero, -1), unexpected. % SWI
   E = evaluation_error(undefined). % 7.9.2 h, 7.12.2 g, 9.1.2. % expected, if considered to be an error

is highly problematic. It could be either evaluation_error(undefined) or à la rigueur some newly invented exceptional value (9.1.2) , if an error should be the outcome (I have no real opinion on it).

((The reason that I encountered this issue is just because I tried to test clpz systematically, taking the manual (and not knowing anything about the meaning of all these functors). After all, some of the issues that hinder exhaustive testing have been fixed recently, before there was too much leaking.))

?- X #= popcount(Y).
   clpz:(X#=popcount(Y)), unexpected. % current Scryer result
   X#=popcount(Y), unexpected.        % more compact formulation
   X in 0..sup, Y in 0..sup, X #= popcount(Y)  % hypothetically desirable, if popcount(-1) is undefined
|  % alternate outcome
   X in 0..sup, Y in inf..sup, X #= popcount(Y). % in case of LISP-ish meaning

UWN avatar Feb 07 '23 13:02 UWN

I see your point. If hypothetically desirable then:

?- X #= popcount(Y) , A #= X/Y.
X in 0..sup, Y in 0..sup, A in diverr..0..supinf ?

flexoron avatar Feb 07 '23 17:02 flexoron

Not clear what you mean, but 0 is excluded for division, no matter which:

?- A #= X/Y.
   clpz:(A*Y#=X), clpz:(Y in inf.. -1\/1..sup).
?- A #= X//Y.
   clpz:(X//Y#=A), clpz:(Y in inf.. -1\/1..sup).
?- A #= X div Y.
   clpz:(_A+_B#=X), clpz:(_A//Y#=A), clpz:(X mod Y#=_B), clpz:(Y in inf.. -1\/1..sup).

UWN avatar Feb 07 '23 17:02 UWN

x = 0/0. x * 0 = 0. x = (0..sup).
Anyway.

What I mean: Is X and Y (the result) available 
?- X #= popcount(Y) , A #= X*Y.
X in 0..sup, Y in 0..sup, A in 0..sup % Is this possible?
My opinion: Problem is tricky but the outcome shouldn't be an error.
For example:
Define popcount such that it counts the sign-bit inverted (bit set? count 0s, not set? count 1s)

flexoron avatar Feb 07 '23 17:02 flexoron

Just for the record, the oldest clpfd library of SICStus I can get hold of right now:

[ulrich@a9 lib]$ /usr/local/lib/sicstus3.8.4_2/bin/sicstus
SICStus 3.8.4 (x86-linux-glibc2.1): Sun Jul 23 14:25:19 CEST 2000
Licensed to complang.tuwien.ac.at
...
| ?- asserta(clpfd:full_answer).

yes
| ?- A #= X/Y.

clpfd:'x/y=z'(X,Y,A) ? ;

no
| ?- A #= X/Y, Y = 0.

no
| ?- A #= X//Y.
{DOMAIN ERROR: _71#=_68//_69 - arg 0: expected constraint, found _71#=_68//_69}
| ?- A #= X div Y.
{SYNTAX ERROR: in line 28 (within 28-29)}
** operator expected after expression ** 
?- A #= X 
** here **
div Y . 

whereas today it's:

| ?- A #= X/Y.
X//Y#=A,
X in inf..sup,
Y in(inf.. -1)\/(1..sup),
A in inf..sup ? 
yes
| ?- A #= X//Y.
X//Y#=A,
X in inf..sup,
Y in(inf.. -1)\/(1..sup),
A in inf..sup ? ;
no
| ?- A #= X div Y.
X div Y#=A,
X in inf..sup,
Y in(inf.. -1)\/(1..sup),
A in inf..sup ? ;
no
| ?- 

At least convergence on a certain level.

UWN avatar Feb 07 '23 20:02 UWN

I think the rug library returns an Option here because of what it says at this link.. namely, if the integer is less than 0, then the integer is considered to have an infinite number of 1s and the return value is the largest possible value of the internal value mp_bitcnt_t (64 in this case).

mthom avatar Feb 12 '23 02:02 mthom

Currently:

?- X#=popcount(-1^ -1).
thread 'main' panicked at 'assertion failed: sign == Sign::Positive', /home/ulrich/.cargo/git/checkouts/dashu-b0ac188b86787091/f934219/integer/src/repr.rs:148:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

UWN avatar Sep 12 '23 05:09 UWN

Right now:

?- X=popcount(-1 ^ -1).
   X = popcount(-1^ -1).
?- 

Which i assume is related to #2146.

razetime avatar Nov 08 '23 05:11 razetime

@razetime: Please note the missing #:

?- X#=popcount(-1 ^ -1).
   X = 0.

UWN avatar Nov 16 '23 13:11 UWN