4
$\begingroup$

I've been trying to compile a couple of functions in Mathematica, and I keep coming across an error that I do not know how to resolve. Consider the following function:

FindCircleVerticalLineIntersections = 
  Compile[{{circlePos, _Real, 1}, {radius}, {xIntercept}},
   Module[{points, θ, posRadius, yDist},
    (*First, let's initialize points*)
    (*This will not work any other way that I have tried*)
    points = {{0.0, 0.0}};

    (*First things first:  
    let's see if the vertical line is within the boundaries of the \
circle*)
    If[PointIsWithinCircleWidth[circlePos, radius, {xIntercept, 0}],
     (*If it is, let's see if it is right on the edge of the circle*)


     If[PointIsOnCircleWidth[circlePos, radius, {xIntercept, 0}],
       (*If it is, 
       then the list of all intersection points will have just one \
entry*)
       points = {{xIntercept, circlePos[[2]]}};
       ,
       (*Otherwise, let's find both intersections*)
       posRadius = Abs[radius];
       θ = ArcCos[(xIntercept - circlePos[[1]])/posRadius];
       yDist = posRadius*Sin[θ];
       points = {{xIntercept, circlePos[[2]] + yDist}, {xIntercept, 
          circlePos[[2]] - yDist}};
       ];
     ,
     (*Otherwise, we don't have any intersections, 
     let's just set points to an empty list*)
     points = Delete[points, 1];
     ];

    (*Finally, let's return points*)
    points
    ]
   , CompilationTarget -> "C"];

Now, this function works just as expected, and returns results well, but whenever I try to call it from any other compiled function, such as the following function:

f = Compile[{},
   FindCircleVerticalLineIntersections[{0.0, 0.0}, 1.0, 0.0]
   , CompilationTarget -> "C"];

I get the following undeclared identifier error:

CCompilerDriver`CreateLibrary::cmperr: Compile error: C:\Users\Surge\AppData\Roaming\Mathematica\ApplicationData\CCompilerDriver\BuildFolder\combinatoric-5700\Working-combinatoric-5700-2808-88\compiledFunction87.c(85) : error C2065: 'P1' : undeclared identifier >>

I've looked at the human-readable C form of this program, and I don't even see an identifier called P1:

        No argument
        2 Integer registers
        2 Real registers
        3 Tensor registers
        Underflow checking off
        Overflow checking off
        Integer overflow checking on
        RuntimeAttributes -> {}

        T(I1)0 = {0, 0}
        I1 = 1
        I0 = 3
        Result = T(R2)1

1   T(R2)1 = MainEvaluate[ Hold[FindCircleVerticalLineIntersections][ \
T(I1)0, I1, I1]]
2   Return

Does anyone know what the problem is?

EDIT

Here are the missing functions, my apologies for the delay:

    (*The following function determines wither a point pointPos is within \
a circle of a given radius centered on the origin*)
PointIsWithinCircleWidthOnOrigin = 
  Compile[{{radius}, {pointPos, _Real, 1}},
   Module[{posRad},
    (*First, 
    let's make sure the radius that was passed in is positive*)
    posRad = Abs[radius];

    (*Next, let's see if the X-
    componant of the point is within the boundary of the circle*)
    (*This If structure to my knowledge is unnecessary, 
    but it makes the code look a bit cleaner in my opinion since we \
are explictly passing back a True or a False*)
    If[Abs[pointPos[[1]]] <= posRad,
     True,
     False
     ]
    ]
   , CompilationTarget -> "C", RuntimeOptions -> "Speed"];

(*The following function determines whether some point pPos is within \
a circle of radius rad centered at cPos*)
PointIsWithinCircleWidth = 
  Compile[{{cPos, _Real, 1}, {rad}, {pPos, _Real, 1}},
   Module[{pos, pRad},
    (*First, 
    let's shift the entire system so that we can be dealing with a \
circle centered at the origin*)
    pos = pPos - cPos;

    (*Next, 
    let's call PointIsWithinCircleWidthOnOrigin and return whatever \
that returns*)
    PointIsWithinCircleWidthOnOrigin[rad, pos]
    ]
   , CompilationTarget -> "C", RuntimeOptions -> "Speed"];

(*This function determines whether a given point is on the left-most \
or right-most boundary of a circle on the origin given a radius*)
PointIsOnCircleWidthOnOrigin = Compile[{{radius}, {point, _Real, 1}},
   Module[{positiveRad, posXComponant},
    (*Let's first make sure the radius is positive*)
    positiveRad = Abs[radius];

    (*Next, let's find the absolute value of the X-componant*)
    posXComponant = Abs[point[[1]]];

    If[posXComponant == positiveRad,
     True,
     False
     ]
    ]
   , CompilationTarget -> "C", RuntimeOptions -> "Speed"];

(*This function determines whether a point is on the left-most or \
right-most boundary of a circle on the origin given a radius*)
PointIsOnCircleWidth = 
  Compile[{{cPos, _Real, 1}, {radius}, {point, _Real, 1}},
   Module[{pos},
    pos = point - cPos;

    PointIsOnCircleWidthOnOrigin[radius, pos]
    ]
   , CompilationTarget -> "C", RuntimeOptions -> "Speed"];
$\endgroup$
  • 4
    $\begingroup$ I upvoted your question because I think this probably should not happen. However, it is not really answerable without the definitions of PointIsWithinCircleWidth and PointIsOnCircleWidth given, so please include those in the question as well. Welcome to the site, by the way. It is a rarer thing than you would think for a brand-new user to post a (almost) fully formed and properly formatted question, and it is appreciated. $\endgroup$ – Oleksandr R. Jul 31 '15 at 0:00
  • $\begingroup$ Have you looked at "InlineCompiledFunctions"? $\endgroup$ – Michael E2 Jul 31 '15 at 0:42
  • $\begingroup$ I am sorry, but without those definitions, the issue is not reproducible and so the question is not answerable. Therefore I have to vote to close your question as it currently is. If it is closed before you are able to update it, please cast a vote to re-open after you have done so, and I'm sure other users will follow suit. $\endgroup$ – Oleksandr R. Aug 3 '15 at 17:17
2
$\begingroup$

When you call compiled functions inside another compiled function, you should consider to inline them. You can do this by wrapping a With statement around and using

CompilationOptions -> {"InlineCompiledFunctions" -> True}

as option to compile. I have cleaned your code, moving a lot of definitions of variable right where you declare it in Module. I have remove all the compilation targets and "Speed" runtime options and only used it in the very last FindCircleVerticalLineIntersections function. The function PointIsWithinCircleWidth contains an error because you declare pos and pRad in the Module but you don't give them values. I fixed this, but you need to check whether it is what you meant!

You can download the complete notebook at once by evaluating

Import["http://goo.gl/NaH6rM"]["http://i.stack.imgur.com/uxbnd.png"]

or you copy&paste it from below. The final function should work now:

PointIsWithinCircleWidthOnOrigin = 
  Compile[{{radius, _Real, 0}, {pointPos, _Real, 1}},
   Module[{posRad = Abs[radius]},
    If[Abs[pointPos[[1]]] <= posRad, True, False]]];


PointIsWithinCircleWidth = 
  With[{PointIsWithinCircleWidthOnOrigin = 
     PointIsWithinCircleWidthOnOrigin},
   Compile[{{cPos, _Real, 1}, {rad, _Real, 0}, {pPos, _Real, 1}}, 
    Module[{pos = cPos - pPos, pRad = rad}, 
     PointIsWithinCircleWidthOnOrigin[rad, pos]
     ],
    CompilationOptions -> {"InlineCompiledFunctions" -> True}
    ]
   ];

PointIsOnCircleWidthOnOrigin = 
  Compile[{{radius}, {point, _Real, 1}}, 
   Module[{positiveRad = Abs[radius], posXComponant = Abs[point[[1]]]},
    If[posXComponant == positiveRad, True, False]]
   ];


PointIsOnCircleWidth =
  With[{PointIsOnCircleWidthOnOrigin = PointIsOnCircleWidthOnOrigin},
   Compile[{{cPos, _Real, 1}, {radius, _Real, 0}, {point, _Real, 1}}, 
    Module[{pos = point - cPos},
     PointIsOnCircleWidthOnOrigin[radius, pos]],
    CompilationOptions -> {"InlineCompiledFunctions" -> True}
    ]
   ];

FindCircleVerticalLineIntersections =
  With[{
    PointIsWithinCircleWidth = PointIsWithinCircleWidth,
    PointIsOnCircleWidth = PointIsOnCircleWidth
    },
   Compile[{{circlePos, _Real, 1}, {radius}, {xIntercept}}, 
    Module[{points = {{0.0, 0.0}}, \[Theta], posRadius, yDist},
     If[PointIsWithinCircleWidth[circlePos, radius, {xIntercept, 0}], 
      If[PointIsOnCircleWidth[circlePos, radius, {xIntercept, 0}], 
       points = {{xIntercept, circlePos[[2]]}},
       posRadius = Abs[radius];
       \[Theta] = ArcCos[(xIntercept - circlePos[[1]])/posRadius];
       yDist = posRadius*Sin[\[Theta]];
       points = {{xIntercept, circlePos[[2]] + yDist}, {xIntercept, 
          circlePos[[2]] - yDist}}
       ],
      points = Delete[points, 1]
      ];
     points
     ],
    CompilationOptions -> {"InlineCompiledFunctions" -> True},
    CompilationTarget -> "C",
    RuntimeOptions -> "Speed"
    ]
   ];
$\endgroup$
  • $\begingroup$ What was the problem, though? I'm more interested in learning the inner workings of Mathematica than just getting code that works. $\endgroup$ – Surge Aug 25 '15 at 21:59
  • 1
    $\begingroup$ Beside the error in PointIsWithinCircleWidth that I pointed out, you cannot simply call a compiled function from within another compiled function and expect that it is properly included (injected). The combination of With and the option "InlineCompiledFunctions" is important because otherwise when you call your compiled function, it calls back to Mathematica which is not what you want. You want a compiled function to be fast compiled code only without callbacks to the Mathematica Kernel. The real problem was that with compilation target "C" this produced not only slow code... $\endgroup$ – halirutan Aug 25 '15 at 23:37
  • 1
    $\begingroup$ ...In your example, it gave a cryptic error. I couldn't even reproduce your error on my Linux machine. Here, the Kernel just crashed. Therefore, I can only tell you how to do it right and not, what exactly went wrong in your specific case. $\endgroup$ – halirutan Aug 25 '15 at 23:38
  • $\begingroup$ Thank you very much for your reply. Is this documented anywhere? The documentation in the help page of Mathematica is woefully insufficient on these particular points discussed here. $\endgroup$ – Surge Sep 1 '15 at 1:02
  • $\begingroup$ @Surge You mean the options to compile? Sure, see the Details and Options section of Compile and follow the links. In the doc of CompilationOptions you'll find examples. $\endgroup$ – halirutan Sep 1 '15 at 13:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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