# How should I debug a failed Manipulate of RegionPlot?

I am trying to build a package that will display a sector of an ellipse where the angle is taken from a focus of the ellipse rather than from the center. The code seems to work fine when called with individual values.

A problem arises when I try to embed a call to the code within a Manipulate. Here is a simplified failing version:

Manipulate[
Show[
RegionPlot[
Sector[5, 3, ang, ang + \[Pi]/6],
PlotRange -> {{-6, 6}, {-6, 6}}
]
],
{{ang, 0, "Initial angle"}, 0, \[Pi]/2, Appearance -> "Labeled"}
]


When I move the slider, I can see errors at some different values of ang (such as 1.5708 and 0.119381), while others work fine. The error message says "The cell Line[{1,1}] is degenerate." and seems to be coming from BoundedMeshRegion.

I have tried several approaches to debugging the problem:

1) I tried removing the Manipulate and plugging in a failing value, but the code worked fine.

2) I tried Trace, but the output was quite long and unenlightening to me.

3) Incidentally, removing the PlotRange call removes the error message, but the displayed plot is clipped on both ends.

My question is how to debug this problem? That is, how should I think about attacking the problem. Alternatively, am I misusing the computational resources (e.g. RegionPlot) in some way?

Note, the code for the package is available here (.txt or .wl). A secondary utility package is available here I am running Mathematica version 10.0.2.0.

Thanks.

Spencer

• The code for the package does not contain code for helped functions on which Sector depends, so unfortunately I am unable to reproduce your code. Would you be able to you provide those as well? – MarcoB Jun 15 '15 at 16:51
• I have added an additional link to the missing material in the question. – Spencer Rugaber Jun 15 '15 at 18:42
• My original question was about debugging. Both answers got rid of the bug, but they did it without treating the problem as a "bug". That is, they determined that I was using the language inappropriately rather than incorrectly. Can anyone recommend a strategy for determining, when an error message shows up, whether to treat it as a traditional bug to be corrected or an indication of incorrect usage, to be rethought? If the latter, how should one attack a situation where the system is indicating incorrect usage, but it is not clear which program element is being used incorrectly? – Spencer Rugaber Jun 18 '15 at 13:13

Manipulate typically changes the default value of the $PerformanceGoal control to "Speed" instead of "Quality", in order to speed up evaluation of dynamic content (see the first "basic example" in its documentation page). Typically this doesn't matter much, but in some cases this can influence the outcome of some algorithms that are sensitive to the working precision. Unfortunately, something in your implementation is among these algorithms, even without Manipulate. Compare the following two results, obtained using arbitrary vs. machine-precision arguments: GraphicsRow[ Table[ RegionPlot[Sector[5, 3, ang, ang + \[Pi]/6], PlotRange -> {{-6, 6}, {-6, 6}}], {ang, {Pi/20, Pi/20.}} ], ImageSize -> Full ]  Fortunately, however, you can manually set the $PerformanceGoal setting within Manipulate by wrapping its argument in a Block:

Manipulate[
Block[{$PerformanceGoal = "Quality"}, RegionPlot[ Sector[5, 3, ang, ang + Pi/6], PlotRange -> {{-6, 6}, {-6, 6}} ] ], {{ang, 0, "Initial angle"}, 0, Pi/2, Appearance -> "Labeled"} ]  Note also that I removed the Show wrapper because it wasn't really doing anything in your example, but that had nothing to do with your errors. This does not give me any more errors as I change the values of the ang parameter. Note that the quality of the plot is still not very good. To improve on that, you can e.g. specify an arbitrary-precision step for the ang variable within Manipulate: . . . {{ang, 0, "Initial angle"}, 0, Pi/2, Pi/20, Appearance -> "Labeled"} (* Notice the Pi/20 increment *) . .  I am going to try and address some of your questions in comments as best I can. Other shorter answers will just be added as comments below. Keep in mind that some of the issues you raise may be results of very complex interactions between features of the language, and some times "informed trial-and-error" is your best bet in figuring some of these issues out. On the issue of machine vs. arbitrary precision numbers, approximate numbers are practically distinguished by an explicit decimal point. If you don't specify precision further, then they will be evaluated using machine precision. I would suggest the following documentation pages and how-to's that frame the issue well: On the Pi/2 in the Manipulate: the key is in the fact that Manipulate's internals use machine-precision increments (as you can see in the value of the slider variable in the posted picture) even when you specify an arbitrary precision endpoint. The Pi/20 used above that induced Manipulate to use arbitrary-precision step increments instead. • Thank you for your answer. I have several followup question, which I have broken into separate comments. First, thank you for reminding of the difference between arbitrary and machine-precision computations. In your first example, it looks like the key to determining which is being used it whether Pi/20 is followed by a decimal point or not. Is this the case? In general, what are the rules for how the evaluator makes this distinction? – Spencer Rugaber Jun 18 '15 at 13:06 • Later, in the second example, in the Manipulate[] variable specification (ang), you used Pi/2 (instead of Pi/2.), but the truncated sector appeared (as opposed to the sharp sector in the arbitrary precision version of your first example). Why doesn't the Pi/2 version work like the previous Pi/20 example? In your third example, why did the introduction of Pi/20 put the evaluation into arbitrary precision mode when the Pi/2 did not? – Spencer Rugaber Jun 18 '15 at 13:06 • When I copied your first example into my notebook I was able to duplicate your graphs EXCEPT that both of the displayed regions in mine had been partitioned via a triangular mesh. These persisted even when I included the Mesh -> None option. Can you explain to me why I am seeing different output than you do and how I can control it? – Spencer Rugaber Jun 18 '15 at 13:07 • I was not aware of$PerformanceGoal before you mentioned it (thank you). I have since done a search for a list of other global constants without success. Is there any way you would recommend of my learning about other resources like PerformanceGoal? – Spencer Rugaber Jun 18 '15 at 13:08
• I was able to reproduce your second example (the Block[] with $PerformanceGoal) in my notebook and noted the same lack of "quality" improvement that you did. It looks like$PerformanceGoal is not helping here. Can you characterize when it should be applied? – Spencer Rugaber Jun 18 '15 at 13:09

It seems your Sector returns a region for which RegionMember can calculate its formula. RegionPlot is quite a bit faster on this fairly simple formula than on the region. Further, you don't run into the symbolic-numeric problem of reducing the RegionIntersection in whatever way Mathematica does under the hood. (I suspect it is using a algebraic/symbolic solver like Reduce on approximate machine-real input, whereas RegionPlot on a formula is purely numeric. I confess I don't fully understand the problem, because I am unable to reproduce it outside of Manipulate.)

Manipulate[
RegionPlot[
RegionMember[Sector[5, 3, ang, ang + π/6], {x, y}] // Evaluate,
{x, -6, 6}, {y, -6, 6}],
{{ang, 0, "Initial angle"}, 0, π/2, Appearance -> "Labeled"}]


You can control the quality of the plot with options like PerformanceGoal-> "Quality", PlotPoints->ControlActive[15, 51], and MaxRecursion. Note the Evaluate is very important, or RegionPlot will take a very long time. This ensures that RegionPlot is passed the algebraic formula; without it, the formula will be recalculated every time RegionPlot tests whether a point is in the region or not.

Side remark

It seems to me that you would do better with ParametricPlot than RegionPlot. It is usually much more efficient, both in speed and quality. All you need is to be able to parametrize the region. I think this draws the picture you want:

Manipulate[
ParametricPlot[
(1 - s) {FocalDistance[5, Eccentricity[5, 3]], 0} + s Polar2CartesianE[5, 3, t],
{s, 0, 1}, {t, ang, ang + π/6},
PlotRange -> {{-6, 6}, {-6, 6}}, Axes -> False],
{{ang, 0, "Initial angle"}, 0, π/2, Appearance -> "Labeled"}]


It will always have a nice, sharp corner at the focus.

• Thank you for your reply. I have several followup questions, which I have broken out into separate comments. The first set has to do with regions. I infer from your response that there are two separate kinds of regions: those defined by formula (e.g. ImplicitRegion and RegionPlot) and those defined by geometrical construction (e.g. HalfPlane). Have I got this right? You mention the use of RegionMember, which was not included in my original code. Is this used to convert between the two forms? Overall, is this the "symbolic-numeric problem" to which you refer? – Spencer Rugaber Jun 18 '15 at 12:55
• You mention the use of MaxRecursion. My code is not explicitly recursive. Is there some implicit recursion going on? – Spencer Rugaber Jun 18 '15 at 12:55
• You mention the use of ParametricPlot, and I like your solution. How would I know in general when it is better to use ParametricPlot than RegionPlot? Is it simply a matter of performance or are there semantic reasons? – Spencer Rugaber Jun 18 '15 at 12:57
• For PlotPoints, how did you choose the values 15 and 51? Are odd multiples of 3 preferred, or is this just a coincidence? – Spencer Rugaber Jun 18 '15 at 12:58
• With regard to the ParametricPlot, I am unfamiliar with the idiom (1-s)*f + s*g(t). Can you shed some light on this for me? – Spencer Rugaber Jun 18 '15 at 12:59

The root cause of the problem reported in the question was a bad formula. This led to a call to ArcCos that, with some arguments, produced a complex number as a result. When this value was given to any of the Region functions, an error resulted.

The only way that I could find to debug the problem was traditional: isolate a failing case, working step by step examining each computation.