Звоню в местный пакет Julia из C - PullRequest
2 голосов
/ 03 мая 2019

Документация Julia показывает примеры того, как вызывать базовые функции Julia из C (например, sqrt), которые я успешно копировал. Что меня действительно интересует, так это вызов локально разработанных модулей Julia, и из документации не совсем понятно, как можно вызывать неосновные функции. Есть несколько дискуссионных тем по этой проблеме несколько лет назад, но API, похоже, за это время изменились. Любые указатели будут оценены.

1 Ответ

1 голос
/ 07 мая 2019

Причина, по которой jl_eval_string("using SomeModule") возвращает NULL, заключается просто в том, что using SomeModule возвращает nothing.

Вы можете использовать функции из других модулей, сначала импортировав модуль, а затем получив объекты функций из этогоМодуль Julia в C. Например, давайте используем пакет GR и его функцию plot.Мы можем получить функцию plot с помощью

jl_eval_string("using GR") // this returns nothing
jl_module_t* GR = (jl_module_t *)jl_eval_string("GR") // this returns the module

/* get `plot` function */
jl_function_t *plot = jl_get_function(GR, "plot");

Здесь мы передали модуль GR в качестве первого аргумента jl_get_function.Мы можем, зная тот факт, что вещи будут загружены в модуль Main, а plot экспортируется из GR, вместо этого использовать следующий фрагмент кода, чтобы сделать то же самое.Обратите внимание, что jl_main_module содержит указатель на модуль Main.

jl_eval_string("using GR")

/* get `plot` function */
jl_function_t *plot = jl_get_function(jl_main_module, "plot");

Мы также можем использовать квалифицированное имя plot.

/* get `plot` function */
jl_function_t *plot = jl_get_function(jl_main_module, "GR.plot");

Тем не менее, вотзавершите пример построения массива значений, используя GR.В примере используется первый стиль для получения функции GR.plot.

#include <julia.h>

JULIA_DEFINE_FAST_TLS() // only define this once, in an executable (not in a shared library) if you want fast code.

#include <stdio.h>

int main(int argc, char *argv[])
{
    /* required: setup the Julia context */
    jl_init();

    /* create a 1D array of length 100 */
    double length = 100;
    double *existingArray = (double*)malloc(sizeof(double)*length);

    /* create a *thin wrapper* around our C array */
    jl_value_t* array_type = jl_apply_array_type((jl_value_t*)jl_float64_type, 1);
    jl_array_t *x = jl_ptr_to_array_1d(array_type, existingArray, length, 0);

    /* fill in values */
    double *xData = (double*)jl_array_data(x);
    for (int i = 0; i < length; i++)
        xData[i] = i * i;

    /* import `Plots` into `Main` module with `using`*/
    jl_eval_string("using GR");
    jl_module_t* GR = (jl_module_t *)jl_eval_string("GR");;

    /* get `plot` function */
    jl_function_t *plot = jl_get_function(GR, "plot");

    /* create the plot */
    jl_value_t* p = jl_call1(plot, (jl_value_t*)x);


    /* display the plot */
    jl_function_t *disp = jl_get_function(jl_base_module, "display");
    jl_call1(disp, p);

    getchar();

    /* exit */
    jl_atexit_hook(0);
    return 0;
}

Включение модуля Julia из локального файла и использование его в C

Я не знаю, что именно имеется в видулокальным пакетом Julia, но вы можете include свои файлы и затем импортировать модули в этих файлах, чтобы сделать то же самое.Вот пример модуля.

# Hello.jl
module Hello
export foo!

foo!(x) = (x .*= 2) # multiply entries of x by 2 inplace

end

Чтобы включить этот файл, вам нужно использовать jl_eval_string("Base.include(Main, \"Hello.jl\")");.По какой-то причине встроенная Джулия не может напрямую получить доступ к include.Вместо этого вам нужно использовать Base.include(Main, "/path/to/file").

jl_eval_string("Base.include(Main, \"Hello.jl\")");
jl_eval_string("using Main.Hello"); // or just '.Hello'
jl_module_t* Hello = (jl_module_t *)jl_eval_string("Main.Hello"); // or just .Hello

Вот полный пример на C.

#include <julia.h>

JULIA_DEFINE_FAST_TLS() // only define this once, in an executable (not in a shared library) if you want fast code.

#include <stdio.h>

int main(int argc, char *argv[])
{
    /* required: setup the Julia context */
    jl_init();

    /* create a 1D array of length 100 */
    double length = 100;
    double *existingArray = (double*)malloc(sizeof(double)*length);

    /* create a *thin wrapper* around our C array */
    jl_value_t* array_type = jl_apply_array_type((jl_value_t*)jl_float64_type, 1);
    jl_array_t *x = jl_ptr_to_array_1d(array_type, existingArray, length, 0);
    JL_GC_PUSH1(&x);
    /* fill in values */
    double *xData = (double*)jl_array_data(x);
    for (int i = 0; i < length; i++)
        xData[i] = i * i;

    /* import `Hello` module from file Hello.jl */
    jl_eval_string("Base.include(Main, \"Hello.jl\")");
    jl_eval_string("using Main.Hello");
    jl_module_t* Hello = (jl_module_t *)jl_eval_string("Main.Hello");

    /* get `foo!` function */
    jl_function_t *foo = jl_get_function(Hello, "foo!");

    /* call the function */
    jl_call1(foo, (jl_value_t*)x);

    /* print new values of x */
    for (int i = 0; i < length; i++)
        printf("%.1f ", xData[i]);

    printf("\n");
    JL_GC_POP();

    getchar();

    /* exit */
    jl_atexit_hook(0);
    return 0;
}
...