6
votes

Hi I want to use the special functions of Julia implementation (https://juliamath.github.io/SpecialFunctions.jl/dev/functions_list/) inside c++.

Following the manual (https://docs.julialang.org/en/v1/manual/embedding/) I could not achieve so far.

For functions like sqrt we have something like

jl_function_t *func1 = jl_get_function(jl_base_module,"sqrt");

In a similar fashion what is the module for these special functions?

I tried to use

jl_function_t *func2 = jl_get_function(jl_specialfunctions_module,"polygamma");

which shows the following error:

signal (11): Segmentation fault
in expression starting at none:0
jl_mutex_wait at /buildworker/worker/package_linux64/build/src/locks.h:24 [inlined]
jl_mutex_lock at /buildworker/worker/package_linux64/build/src/locks.h:94 [inlined]
jl_get_binding_ at /buildworker/worker/package_linux64/build/src/module.c:280
jl_get_global at /buildworker/worker/package_linux64/build/src/module.c:561
jl_get_function at ./test (unknown line)
main at ./test (unknown line)
__libc_start_main at /lib/x86_64-linux-gnu/libc.so.6 (unknown line)
_start at ./test (unknown line)
Allocations: 2544 (Pool: 2535; Big: 9); GC: 0

It is not clear from the manual how one should use these special functions in c++. Any lead would be much appreciated!

I found that this was already asked by Federico (particularly for polygamma): (How to call a julia method defined in an imported package from c++?): Here is the example:

  #include<iostream>
  #include<julia.h>
  JULIA_DEFINE_FAST_TLS() ;

int main(){
   jl_init();
   jl_eval_string("print(sqrt(2.0))"); // see that Julia works

   jl_module_t* jl_specialfunctions_module = (jl_module_t*) 
   jl_get_binding(jl_main_module, jl_symbol("SpecialFunctions"));
   jl_function_t* func2 = jl_get_function(jl_specialfunctions_module,"polygamma");
   jl_value_t *argument1 = jl_box_int64(1);
   jl_value_t *argument2 = jl_box_float64(2.0);
   jl_value_t *arguments[2] = { argument1 , argument2 };
   jl_value_t *ret = jl_call(func2, arguments, 2);

   if (jl_typeis(ret, jl_float64_type)) {
    double ret_unboxed = jl_unbox_float64(ret);
    std::cout << "julia = " << ret_unboxed << std::endl;
    }
   else {
    std::cout << "Error" << std::endl;
   }

   jl_atexit_hook(0);
   return 0;
 }

No answer there unfortunately!

Similar happens when I try to adapt this: https://discourse.julialang.org/t/jl-get-function-throwing-segmentation-fault/37186

NB: The special functions extension was installed through import Pkg; Pkg.add("SpecialFunctions") and in the julia shell the special functions are accessible.

2
On the face of it, it looks like a bug in the Julia source. Could you post a minimal reproducible example? - molbdnilo
It looks like you need to tell C++ that you're using SpecialFunctions. The embedding documentation is missing docs for jl_module_import and friends, but I think that's what you're missing. - mbauman

2 Answers

5
votes

I answered this question in the other stackoverflow thread.

Basically, the easiest thing to do is to use the Julia @cfunction construct to let Julia compile the code into a C++ function pointer, which you can then call normally without worrying about unboxing etcetera.

(For passing complex numbers, @cfunction can exploit the fact that C++ std::complex<double> and Julia Complex{Float64} have identical memory representations.)

2
votes

Thanks to @Matt B, I looked into Julia codes and see how these modules are there. So the following could be one possible solution.

#include <julia.h>
#include<iostream>
JULIA_DEFINE_FAST_TLS() 

int main(){
  jl_init();

  jl_eval_string("using SpecialFunctions");
  jl_module_t* SpecialFunctions =(jl_module_t*)jl_eval_string("SpecialFunctions");

  jl_function_t *func2 = jl_get_function(SpecialFunctions, "polygamma");

  // arguments to pass to polygamma
  jl_value_t *argument1 = jl_box_int64(1);
  jl_value_t *argument2 = jl_box_float64(2.0);
  jl_value_t *arguments[2] = { argument1 , argument2 };
  jl_value_t *ret2 = jl_call(func2, arguments, 2);

  if (jl_typeis(ret2, jl_float64_type)){
    double ret_unboxed = jl_unbox_float64(ret2);
    std::cout << "\n julia result = " << ret_unboxed << std::endl;
  }
  else{
    std::cout<<"hello error!!"<<std::endl;
  }

  jl_atexit_hook(0);
  return 0;
 }

Now I need to see how can I pass complex numbers to the argument of polygamma which is why all these fuss about :) !