6
$\begingroup$

I have come across a problem in Mathematica when I have tried to plot the contours of a compiled function.

f  = Compile[{{x}, {y}}, x^2 + y^2];
ContourPlot[f[x, y] == 0.1, {x, y} \[Element] Disk[{0, 0}, 1]]

this works perfectly but suppose I want to only plot a single contour:

ContourPlot[f[x, y] == 0.1, {x, y} \[Element] Disk[{0, 0}, 1]]

this then returns the error

compiled function error

but still plots the contour correctly. Evaluating f[x, y] == 0.1 gives x^2 + y^2 == 0.1 along with the same error message as the output so it's clear that the problem is that in order to plot the contour specified Mathematica requires the equation for the contour to be in symbolic form suggesting that ContourPlot is using a symbolic method to solve the problem.

However this is no good for anything difficult. I have a function longFunc[x,y] which is an extremely complicated expression and hence must be compiled and evaluated numerically. When I do a simple ContourPlot it works perfectly but if I specify a contour longFunc[x,y]==0.5 it falls back to a symbolic method and doesn't return an answer for a very long time.

So the question is: Is there an option within ContourPlot to force Mathematica to search for a solution to the equality using a numerical method?

Thank you!

Related:

ContourPlot is slow and unwieldy and generates a large-data graphic

Plot compiled function with LogLinearPlot

$\endgroup$
1
  • 1
    $\begingroup$ Dd you intend that your two code snippets would have different ContourPlot calls? They seem to be identical. $\endgroup$ Jan 23, 2019 at 15:04

4 Answers 4

5
$\begingroup$

Ok I figured it out. You specify the contours you want through the Contours option of the function, surprisingly.

f = Compile[{{x}, {y}}, x^2 + y^2];
ContourPlot[f[x, y], {x, y} \[Element] Disk[{0, 0}, 1], 
 Contours -> {0.1}, ContourShading -> False]

Works beautifully. If you specify an equality in the argument ContourPlot defaults to symbolic solving which is usually way too slow.

$\endgroup$
3
$\begingroup$

Try

f = Compile[{{x, _Real}, {y, _Real}}, x^2 + y^2];
ContourPlot[f[x, y] == 0.1, {x, y} \[Element]Disk[{0, 0}, 1]]

enter image description here

$\endgroup$
3
  • $\begingroup$ Doesn't change anything. The problem is that when you specify a contour to plot, Mathematica reverts back to trying to symbolically solve the equality. $\endgroup$
    – Takoda
    Jan 23, 2019 at 10:02
  • $\begingroup$ Contour is evaluated without error message, so obviously somthing changed. $\endgroup$ Jan 23, 2019 at 10:07
  • $\begingroup$ Not for me. I am using Mathematica 11.2 so that might be why. $\endgroup$
    – Takoda
    Jan 23, 2019 at 10:14
3
$\begingroup$

The message you are getting means that ContourPlot internally is calling f with symbolic arguments contrary to its documentation.

ContourPlot has attribute HoldAll, and evaluates the fi and gi only after assigning specific numerical values to x and y.

Nevertheless, many functions expect to be able to evaluate user-supplied functions symbolically. There is an idiomatic way to prevent these calls: tell the pattern matcher that the arguments must be numeric.

Clear[f, fCompiled];
fCompiled = Compile[{{x}, {y}}, x^2 + y^2];
f[x_?NumericQ, y_?NumericQ] := fCompiled[x, y];
ContourPlot[f[x, y] == 0.1, {x, y} \[Element] Disk[{0, 0}, 1]]

This produces no diagnostics.

There are two confusable conditions, ?NumberQ and ?NumericQ. Since NumberQ[Pi] == False, NumericQ[Pi] == True, and fCompiled[Pi,Pi] == 19.739208802178716`, NumberQ is too strict. Use NumericQ.

$\endgroup$
1
  • $\begingroup$ You can also add RuntimeOptions -> "EvaluateSymbolically" -> False to Compile. $\endgroup$
    – xzczd
    Jan 23, 2019 at 15:34
2
$\begingroup$

Here are a couple more ideas for displaying the contour at $z=1/10$

You could also define a helper function g that forces Plot3D to work with numeric values. Note: this will give a symbolic rather than a numeric tooltip for the contour.

g[x_?NumericQ, y_?NumericQ] := f[x, y];
ContourPlot[g[x, y] == 1/10, {x, -1, 1}, {y, -1, 1}, ContourShading -> False]

contour

You could also show the contour on the 3D surface defined by f:

Plot3D[f[x, y], {x, y} ∈ Disk[],
  MeshFunctions -> {#3 &},
  Mesh -> {{{1/10, Directive[Black, AbsoluteThickness[3.5]]}}},
  BoxRatios -> {1, 1, 1/3},
  ColorFunction -> (White &),
  Lighting -> "Neutral"]

surface

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.