Message Boards Message Boards

2
|
4875 Views
|
15 Replies
|
20 Total Likes
View groups...
Share
Share this post:

Why is RegionNearest not returning the closest point on a curve?

Novice user here. I was about to show off Mathematica's RegionNearest[] function to a mathematics teacher when I ran into the following. To simplify, the problem statement is: Find the closest point on the parabola y=x^2 to the point (-1/2,4), in decimals.

RegionNearest[ImplicitRegion[y - x^2 == 0, {x, y}], {-1/2, 4}] // N

gives the correct result. But if instead of (-1/2,4) you enter the point as (-0.5,4), i.e.

RegionNearest[ImplicitRegion[y - x^2 == 0, {x, y}], {-0.5, 4}]

you will get an (x,y) pair on the curve which is a local minimum in distance, not a global one. Minimize[EuclidieanDistance[]] seems to have the same issue.

On the other hand, if you form your own squared distance function (a quartic) and then apply Minimize[] to it, using either (-1/2,4) or (-0.5,4) for the point of interest, you will always get the correct value. I have attached a notebook demonstrating this behavior, including a plot. Minimize[] has been around for a long time and I would not be surprised it if checks the extrema and picks the global minimum for a polynomial function. RegionNearest[] does not seem to be doing that.

This is a bit concerning because I have been relying on RegionNearest[] as a shorthand way of getting the closest point on a curve to a point in the plane. Now I hope that no-one is using it for anything vital, such as directing a ship to shore!

Is this a bug or a feature that I have found, or am I missing the "point" somehow?

Attachments:
POSTED BY: Philip Blanco
15 Replies

RegionNearest is definitely a lot faster for discretized regions.

In[1]:= region = ImplicitRegion[(x - 2)^4 + (y - 3)^4 <= 1, {x, y}]

Out[1]= ImplicitRegion[(-2 + x)^4 + (-3 + y)^4 <= 1, {x, y}]

In[15]:= AbsoluteTiming @ RegionNearest[region, {-1, 2.1}]

Out[15]= {0.0891469, {1.02305, 2.4537}}

In[13]:= dregion = DiscretizeRegion[region];

In[16]:= AbsoluteTiming @ RegionNearest[dregion, {-1, 2.1}]

Out[16]= {0.00009683, {1.02987, 2.42768}}
POSTED BY: Frank Kampas

One possibility for the situation where one gets a local min is as follows. Intersect the region with a sphere of radius slightly larger than the given distance, centered at the query point. Now one can repeat with a better chance of getting the global min. Moreover one can get an approximation by meshing the subregion, extracting vertices, and using ordinary Nearest to find the closest vertex to the query point. I show this below.

Here is the original setup and the local min found.

pt = {-0.5, 4};
region = ImplicitRegion[y - x^2 == 0, {x, y}];
pt1 = RegionNearest[region, pt]
dist = EuclideanDistance[pt1, pt]

(* Out[64]= {1.83399714916, 3.36354556229}

Out[65]= 2.41921825051 *)

If we use a subregion comprised of points at most slightly further away, then we get a better minimal distance/closer point. We could of course go in the direction of being more exclusive, by taking a radius that excludes the point we found, and for some purposes that might be better. But I'll leave that for others to consider.

region2 = 
  ImplicitRegion[
   y - x^2 == 0 && ({x, y} - pt).({x, y} - pt) <= 1.01*dist^2, {x, y}];
pt2 = RegionNearest[region2, pt]
dist2 = EuclideanDistance[pt2, pt]

(* Out[68]= {-1.90556930822, 3.63119438843}

Out[69]= 1.45314922129 *)

Here is the meshing approach mentioned above.

ptlist = MeshCoordinates[DiscretizeRegion[region2]];
pt3 = First[Nearest[ptlist, pt]]
dist3 = EuclideanDistance[pt3, pt]

(* Out[71]= {-1.92080363722, 3.68948661277}

Out[72]= 1.4543388667 *)

One will note that it does give a good approximation to the globally closest point. This method might be slow, due to meshing algorithm internals, or too coarse, due to quality of mesh, so caveat emptor.

After writing the above I realized some of this is built in. One can just discretize the original region and do RegionNearest on that.

pt4 = RegionNearest[DiscretizeRegion[region], pt]
dist4 = EuclideanDistance[pt4, pt]

(* Out[74]= {-1.90493346777, 3.63315045973}

Out[75]= 1.45203878531 *)

Again, there might be speed issues and or artifacts from quality of the discretization such as a result that is too close (if discretization goes outside the boundary of the actual region) or too far (if discretization is too coarse to capture sufficient detail).

POSTED BY: Daniel Lichtblau

Thanks Daniel for explaining. Now the big question: is this considered a bug? Or should one be aware of possible other 'closer' points if one uses 'numerical' input (either starting point or region)?

POSTED BY: Sander Huisman

I do not know if this is regarded as a bug or feature of using approximate values/methods. I have passed the question on to people who might know.

POSTED BY: Daniel Lichtblau

Oh it's definitely a bug! Or at very least an "issue", even if one concludes that using RegionNearest[] in this way is a bad thing to do. As Sander's first reply to my post shows above, we get inconsistent results using (-0.5,4) vs. (+0.5,4) even for y=x^2, so there is some right-handed bias to the algorithm which (to me) hints at a much deeper problem with the way it searches for a global minimum.

At the very least, the documentation should have mention under Possible Issues that RegionNearest[] and RegionDistance[] may return values at a local minimum. NMinimize[] has a similar disclaimer (which personally I think should be more prominent).

For some reason I am not surprised that NMinimize[] sometimes falls into the trap of a local minimum. That's what happens. (Our students do this all the time, blindly setting the first derivative to zero without plotting the function to see what it looks like.)

But a function called RegionNearest[] sounds like it should "just work", especially for an easy case like this. Well the bug report has been submitted, so let's see what the developers come up with.

I greatly appreciate all the insights shared in these replies, thank you.

POSTED BY: Philip Blanco

Global optimization is quite difficult, so I'd say that the documentation statement " NMinimize may sometimes only find a local minimum" is overly optimistic.

POSTED BY: Frank Kampas

What you've done is flatten out the local minimum by discretizing the region?

POSTED BY: Frank Kampas

What I've done is to find a subregion containing the global min, which might or might not be the local one. I also keep the local min and in fact do it this way to make sure I do not have an empty region. I suppose I could allow it to be empty, and let region code tell me that, and deduce from there that the local min was also either a global one, or at least quite close.

POSTED BY: Daniel Lichtblau

I'll rephrase. Did the discretization turn the region around the local minimum into a linear function so there was no minimum there?

POSTED BY: Frank Kampas

It may have made it linear but that hardly means there is no (local) min there. We are minimizing distance from a point, and that doesn't care so much whether the "edges" are locally linear or actual curves.

What matters is that with a discretization we now have, internally, a simplicial complex in the sense of computational geometry. This has considerable structure, and internal code for RegonNearest is better equipped to handle that than it is to deal with a general implicit region.

POSTED BY: Daniel Lichtblau

Thank you for the insightful replies and I shall report this behavior for RegionNearest[]. Do I get a free waffle-maker from Wolfram for finding a bug? :)

I had wondered if RegionNearest[] called ArgMin[] or NArgMin[] at a lower level. How does one determine which functions are used by other functions? Is that documented or proprietary?

It was also interesting (for me anyway) to see that using EuclideanDistance[] reproduces the same problem that I found with RegionNearest[], i.e.

Minimize[{EuclideanDistance[{x, y}, {-1/2, 4}], y - x^2 == 0}, {x, y}] // N  

gives the correct result, while

Minimize[{EuclideanDistance[{x, y}, {-0.5, 4}], y - x^2 == 0}, {x, y}] 

gives the same wrong answer as before. (Note that in the second case, Minimize[] calls NMinimize[] to deal with the inexact value for x.) However, calling Minimize[] or NMinimize[] with my own squared-distance function, a quartic polynomial, works correctly for both (-1/2,4) and (-0.5/4). This is all shown in the original notebook that I attached.

For completeness, I shall mention that under "Possible Issues" for NMinimize[] in the Help documentation, it states "For nonlinear functions, NMinimize[] may sometimes find only a local minimum". Fair warning, although I hoped it would not matter whether my point was on the left or right of the y-axis when dealing with an even polynomial function like y=x^2.

POSTED BY: Philip Blanco

I think it would make more sense for Minimize and the related functions to rationalize inputs that are not infinite precision, rather than switching to the numerical version.

POSTED BY: Frank Kampas

I do not know the implications of such a change, but it sounds reasonable in most instances. At least if there was an option to force these functions to rationalise.

Meanwhile

myRegionNearest[reg_, p_] :=  N@RegionNearest[Rationalize[reg], Rationalize[p]]

might -with the obvious tweaks- work for the time being.

Cheers,

Marco

POSTED BY: Marco Thiel

Hi Philip,

Indeed, this seems a little strange but expected in some way. Either giving the starting point or the curve with some limited precision will give the same kinda error. Probably it will transfer to different algorithm once either the start or the curve has some precision.

For this curve it is quite straight-forward but you can imagine much harder cases where the curve makes loops and crossing et cetera. I think they have a general algorithm that looks for a minimum.

This does not change of course the fact that it is indeed wrong, please submit an bug-report with just:

{xcorrect, ycorrect} = RegionNearest[ImplicitRegion[y - x^2 == 0, {x, y}], {-1/2, 4}] // N
{xwrong, ywrong} = RegionNearest[ImplicitRegion[y - x^2 == 0, {x, y}], {-0.5, 4}] 

to https://www.wolfram.com/support/contact/email/ ("product feedback").

NB:

{xcorrect, ycorrect} = RegionNearest[ImplicitRegion[y - x^2 == 0, {x, y}], {1/2, 4}] // N
{xwrong, ywrong} = RegionNearest[ImplicitRegion[y - x^2 == 0, {x, y}], {0.5, 4}] 

does work correctly because the numerical minimalization is starting on the 'right' side.

POSTED BY: Sander Huisman

Hi,

I suppose that the problem is in ArgMin or more precisely NArgMin, which is/are used by RegionNearest:

ArgMin[{Sqrt[Abs[x + 0.5]^2 + Abs[y - 4]^2], {x, y} \[Element] ImplicitRegion[-x^2 + y == 0, {x, y}]}, {x, y}]
(*{1.834, 3.36355}*)

You can help it with:

ArgMin[{(x + 0.5)^2 + (y - 4)^2, {x, y} \[Element]  ImplicitRegion[-x^2 + y == 0, {x, y}] \[And] x < 0}, {x, y}]

but that's certainly not intended. ArgMin uses NArgMin when dealing with approximate numbers. And that seems to cause problems. The following option will help to mitigate the issue:

NArgMin[{(x + 0.5)^2 + (y - 4)^2, {x, y} \[Element] ImplicitRegion[-x^2 + y == 0, {x, y}]}, {x, y}, Method -> "DifferentialEvolution"]
(*{-1.90557, 3.63119}*)

Cheers,

Marco

POSTED BY: Marco Thiel
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract