Re: Strange behavior with polygon and NaN

From: Kyotaro Horiguchi <horikyota(dot)ntt(at)gmail(dot)com>
To: david(at)pgmasters(dot)net
Cc: tgl(at)sss(dot)pgh(dot)pa(dot)us, gkokolatos(at)pm(dot)me, pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: Strange behavior with polygon and NaN
Date: 2021-12-15 07:20:55
Message-ID: 20211215.162055.355076641764301199.horikyota.ntt@gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

At Mon, 15 Mar 2021 08:34:00 -0400, David Steele <david(at)pgmasters(dot)net> wrote in
> On 12/21/20 3:30 AM, Kyotaro Horiguchi wrote:
> > At Tue, 01 Dec 2020 10:03:42 -0500, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> wrote
> > in
> >> I think it should be "needs review" now.
> > Conflicted with some commit(s) uncertain to me. Rebased.

When I recently re-found the working tree on this topic in my laptop,
it contained an unfinished work of tristate geometric comparisons. I
had forgotten how come I started it but I found the starting thread
[1]. I've done that work to the level it anyhow looks working.

The first patch fixes arithmetic functions to handle NaNs, which is
the first motive of this thread. The second introduces tri-state
comparison as requested in [1]. The tri-state comparison returns
TS_NULL or SQL-NULL for comparisons involving NaNs. GiST index is
adjusted so that it treats null as false. On the way doing this, the
bug #17334 [2] and another bug raised earlier [3] are naturally fixed.

The first patch changes/fixes the behavior of geometric arithmetics as
follows *as the result*.

==== 1-a
Distance between an valid object and an object containing NaNs was 0.

select line '{-0.4,-1,-6}' <-> line '{3,NaN,5}'; -- 0 => NaN

==== 1-b
The distance between a point and a vertical or horizontal line was NaN
for some valid cases.

select point '(1e+300,Infinity)' <-> line '{-1,0,3}'; -- NaN -> Infinity

==== 1-c
The closest point of two objects could not be solved if it contains
Infinity.

select point '(1e+300,Infinity)' ## line '{1,0,5}'; -- null -> (-5,Infinity)

(I'm not sure the fix works for all possible cases..)

==== 1-d
Containment involving NaNs was falsely true for some kind of objects.

select point '(NaN,NaN)' <@ path '((1,2),(3,4))'; -- true -> null
select point '(NaN,NaN)' <@ polygon '((2,0),(2,4),(0,0))';-- true -> null

=== 1-e
The intersection detection of two objects containing NaNs was true.

select line '{-1,0,3}' ?# line '{3,NaN,5}'; -- true -> null

The second patch as the result changes/fixes the behavior of
geometrical arithmetics as the follows.

==== 2-a
The containment detection between a valid shape and a point containing
NaN(s) was false. This is not necessarirly wrong but it is changed
according to [1]

select point '(0.5, NaN)' <@ box '(0,0,1,1)'; -- false -> null
select point '(NaN, NaN)' <@ path '[(0,0),(1,0),(1,1),(0,1)]'; -- false -> null

==== 2-b
The equality of two lines containing NaNs can be true or false. This
is right assuming NaN == NaN. But it is changed according to the
policy that NaN makes an object invalid.

select line '{NaN, 1, NaN}' = line '{NaN, 1, NaN}'; -- true -> null
select line '{NaN, 1, NaN}' = line '{NaN, 2, NaN}'; -- false -> null

==== 2-c
The result of the following expression changed from Infinity to
NaN. The distance from the point to to the box is indeterminant.

select box '(-Infinity,500),(-Infinity,100)' <-> point '123,456';

The internal function is dist_bp(). The difference comes from the
behavior that lseg_closept_line() ignores the NaN returned from
line_closept_point() and uses the last one of the two ends of the lseg
as the result, which is (-inf, 500). With this patch the same
function returns (NaN, NaN) which leads to null as the final result.
The previos behavior (for these particular values) may be correct at a
glance but it is wrong at the time lseg_closept_line ignores the fact
that it could not determine which end is closer.

==== 2-d

The comparison between objects involving NaNs results was false, but
it is now null. So NaNs that were shown as a part of the following
query are now excluded. (I'm not sure this is the desired result.)

SELECT p1.f1, p2.f1 FROM
(VALUES (point '0,0'), (point '1,1'), (point 'NaN,NaN')) p1(f1),
(VALUES (point '0,0'), (point '1,1'), (point 'NaN,NaN')) p2(f1)
WHERE p1.f1 <> p2.f1;

f1 | f1
-----------+-----------
(0,0) | (1,1)
- (0,0) | (NaN,NaN)
(1,1) | (0,0)
- (1,1) | (NaN,NaN)
- (NaN,NaN) | (0,0)
- (NaN,NaN) | (1,1)
(6 rows)

==== 2-e

circle_same(~=) returned true for '<(3,5),NaN>' and circle
'<(3,5),0>', which is definitely bogus.
null.

SELECT circle '<(3,5),NaN>' ~= circle '<(3,5),0>'; -- true -> null
SELECT circle '<(3,5),NaN>' ~= circle '<(3,5),NaN>'; -- true -> null

[1] https://www.postgresql.org/message-id/CAOBaU_ZvJGkAuKqfFxQxnsirpaVci_-S3F3M5M1Wzrq1kGyC%3Dg%40mail.gmail.com
[2] https://www.postgresql.org/message-id/17334-135f485c21739caa%40postgresql.org
[3] https://www.postgresql.org/message-id/CAMbWs4-C9K-8V=cAY7q0ciZmJKBMiUnp_xBGzxgKpEWPKd0bng@mail.gmail.com

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

Attachment Content-Type Size
v9-0001-Fix-NaN-handling-of-geometric-arithmetics.patch text/x-patch 72.1 KB
v9-0002-Make-geometric-comparisons-tri-state.patch text/x-patch 95.1 KB

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Masahiko Sawada 2021-12-15 08:02:51 Re: parallel vacuum comments
Previous Message kuroda.hayato@fujitsu.com 2021-12-15 06:40:02 RE: [Proposal] Add foreign-server health checks infrastructure