朱莉娅是一种高性能编程语言,内置了许多实用的数值分析工具。它易于编写,并且拥有一个快速发展的生态系统,其中包含大量用于科学计算、机器学习等诸多领域的实用软件包。Julia 与 JMP 一样,是科学家、研究人员和工程师不可或缺的工具。
Julia 以其与其他编程语言的良好互操作性而闻名,我很好奇从 JSL 调用 Julia 会有多难。如果可行(事实证明确实可行!),我认为从 JSL 调用 Julia 具有巨大的潜力。您可以构建交互式 JMP 用户界面,调用高性能的 Julia 程序。您可以在 Julia 中构建模型,然后在 JMP 中绘制结果,反之亦然。您可以将 JMP 工作流程中耗时的部分用 Julia 来完成。
我将讨论两种从 JSL 调用 Julia 的方法。第一种方法是使用 JSL 调用 Python,再由 Python 调用 Julia。第二种方法是将 Julia 嵌入到用 C 语言编写的动态链接库 (DLL) 中。
请注意,我不会详细介绍 Julia 的编程。如果您想了解更多关于 Julia 的信息,请查阅其官方文档。Julia Academy也提供了一些学习资料。
通过 Python 调用 Julia
Python in JSL
JMP 14 新增了用于直接与 Python 交互的 JSL 命令。以下是脚本索引中的一个简单示例:
// Initialize the Python interface
PythonInit();
// Submit some Python code to run as a JSL string
PythonSubmit("\[message = 'The quick brown fox jumps over the lazy dog']\");
// message is now a variable in Python and can be accessed from JSL with PythonGet()
getStr = PythonGet(message);
Show(getStr);
// Terminate the Python interface
PythonTerm();
PyJulia
如果我们可以从 Python 调用 Julia,那么我们也可以从 JSL 调用 Julia。PyJulia 是一个 Python 包,它正是为此而设计的。让我们开始配置吧。注:我在 Mac 系统上成功使用了 Julia 1.5.4、Python 3.9.5、PyJulia 0.5.7 和 JMP 16.1。
假设 Python 已正确安装并运行,则设置步骤如下:
如果您尚未安装 Julia,请先进行安装。有关安装说明,请访问“官方二进制文件的平台特定说明” 。最新版本可在Julia 下载页面下载。
接下来,按照说明安装 PyJulia。
如果您能够在常规 Python 会话中使用 PyJulia 的使用说明,那就没问题了!
JSL 中的 PyJulia
现在,在 JSL 中,您首先需要在 Python 会话中初始化 Julia。请务必将 Julia 可执行文件的路径作为运行时关键字参数传递,如下所示。
Python Init();
// Initialize julia
Python Submit(
"\[
from julia import Julia
Julia(runtime="/usr/local/bin/julia")
]\");
从这里,您可以使用Python提交来运行任何 Julia 代码。
// Import the main module. This is Julia's workspace.
Python Submit("\[
from julia import Main
Main.xs = [1,2,3] # xs belongs to julia
sines = Main.eval("sin.(xs)") # This returns the sine of each element in xs
]\");
show(PythonGet(sines)); // [0.841470984807897 0.909297426825682 0.141120008059867]
如果您安装了其他 Julia 包,可以通过 Python 导入来访问它们。这里我使用了 Pandas.jl、DataFrames.jl 和 Lasso.jl 对 Big Class.jmp 数据集进行 Lasso 回归,以预测身高。然后我使用JMP Graph Builder 绘制了实际身高与预测身高的对比图。
// Convert datatable to julia dataframe
// Must convert it to a julia Pandas dataframe first
dt = open("$SAMPLE_DATA/Big Class.jmp");
Pythonsend(dt);
Python Submit(
"\[
from julia import Pandas
from julia import DataFrames
from julia import Lasso
Main.dt = dt
predicted = Main.eval("""
using Lasso
df = DataFrames.DataFrame(Pandas.DataFrame(dt))
m = fit(LassoModel, @formula(height ~ sex + weight), df)
predict(m, df)
""")
]\");
// Back to JMP where we plot Actual vs. Predicted
predicted = pythonget("predicted");
dt << newColumn("Predicted height", <
<SETVALUES></SETVALUES>
<P class="lia-align-center" style="text-align: center;" style="text-align: center;"><FONT size="2"><EM>实际值与预测值的对比图,结果用 Julia 计算得出。</EM></FONT></P> <P><SPAN class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="plot.png" style="width: 385px;"><span class="lia-inline-image-display-wrapper" image-alt="plot.png" style="width: 385px;"><img src="https://us.v-cdn.net/6038925/uploads/images/41854i1D3222BA026053FF/plot.png" role="button" title="plot.png" alt="plot.png" /></span><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">绘图.png</SPAN></SPAN></P> <BR /> <P><FONT size="5">将 Julia 嵌入到 DLL 中</FONT><BR />也可以将<A href="https://docs.julialang.org/en/v1/manual/embedding/" target="_self" rel="nofollow noopener noreferrer">Julia 嵌入</A>到 C 代码中。我会分享一些简单的例子,但我相信更熟悉 C 语言的人可以进一步拓展这方面的内容。</P> <P><STRONG><FONT size="4">LoadDLL</FONT></STRONG><BR />关键在于 JSL 的<FONT face="courier new,courier">LoadDLL</FONT>函数。 <A href="https://www.lexjansen.com/nesug/nesug10/ad/ad04.pdf" target="_blank" rel="noopener nofollow noreferrer">这篇论文</A>是学习如何使用<FONT face="courier new,courier">LoadDLL 的</FONT>绝佳资源。举个简单的例子,我们可以看看 test.c 文件中的以下 C 函数。</P> // test.c
double myMultiply(double num1, double num2)
{
return num1 * num2;
} 并编译成 DLL 文件。
# On Mac
gcc -shared -o test.dylib test.c
# On Windows
gcc -shared -o test.dll test.c
然后,在 JMP 中,我们可以调用 C 函数。
dll = loadDLL(convertfilepath("/path/to/my/test.dylib"));
dll << declareFunction("myMultiply",
Convention( STDCALL ),
Arg(Double, "num1"),
Arg(Double, "num2"),
Returns( Double )
);
show(dll << myMultiply(Pi(), 100));
dll << unloadDLL; Julia DLL
现在我们来看一个嵌入了 Julia 代码的 DLL。我们将创建一个函数来计算其输入的正弦值,其中输入单位为度。
// call_julia.c
#include
double sineInDegrees(double degrees)
{
// required: setup the Julia context
jl_init();
// You can evaluate Julia code from strings
jl_value_t *factor = jl_eval_string("pi/180");
double factor_unboxed = jl_unbox_float64(factor);
double radians = degrees * factor_unboxed;
// You can call Julia functions directly
jl_function_t *func = jl_get_function(jl_base_module, "sin");
jl_value_t *argument = jl_box_float64(radians);
jl_value_t *ret = jl_call1(func, argument);
double ret_unboxed = jl_unbox_float64(ret);
jl_atexit_hook(0);
return ret_unboxed;
}
在 Mac 上运行以下命令进行编译,其中`$JULIA_DIR`是一个环境变量,指向 Julia 二进制文件的路径。对我来说,路径是 `/Applications/Julia-1.7.app/Contents/Resources/julia`。我没有在 Windows 上测试过,但类似的方法应该也适用。
# On Mac
gcc -shared -o call_julia.dylib call_julia.c -fPIC -I$JULIA_DIR/include/julia -L$JULIA_DIR/lib -Wl,-rpath,$JULIA_DIR/lib -ljulia
现在我们可以在 JSL 中调用sinInDegrees了!
dll = loadDLL(convertfilepath("/path/to/my/call_julia.dylib"));
dll << declareFunction("sineInDegrees",
Convention( STDCALL ),
Arg( Double, "degrees" ),
Returns( Double )
);
show(dll << sineInDegrees(90)); // 1
dll << unloadDLL; 结论
JSL 的 Python 和LoadDLL接口使我们能够超越 JMP 本身,调用 Julia。虽然经过一些尝试才最终实现,但一旦配置完成,它就能很好地工作。我在本文中展示了一些简单的示例,但我看到了 JMP 和 Julia 结合使用构建新颖有趣应用程序的巨大潜力。
感谢阅读。希望本文能激发您探索的兴趣。
关于版本的说明
我只在Mac平台上使用Julia 1.5和Julia 1.8 beta版,通过Python成功运行了Julia。在Windows平台上,我尝试的Julia版本没有Mac平台上那么多,但通过Python运行Julia失败了。我的所有测试都使用了JMP 16。