Hello,
I have just published a Nim wrapper for ArrayFire on github: https://github.com/bitstormGER/ArrayFire-Nim
This is my first Nim project but the wrapper seems quite usable to me.
I hope this helps (ones it is working properly) to make Nim even more attractive for scientific computing - my main area of interest. I am currently mostly using Python but would love to see more work being done with Nim.
The wrapper is based on the unified backend of ArrayFire so you can change backends at runtime. Supported backends are CPU, OpenCL and CUDA - this means you have access to GPU accelerated operations and even parallel for loops (see gfor in the documentation on github)
To give an idea how code with the wrapper looks - here are some code examples:
Some linear algebra computations - ArrayFire is extremely fast and feature rich
var ain = matrix(2,3,@[1'f32, 4'f32, 2'f32, 5'f32, 3'f32, 6'f32])
var (u,s_vec,vt) = ain.svd()
var s_mat = diag(s_vec ,0, false)
var in_recon = matmul(u,s_mat, vt[mseq(2), span])
Computer Vision (translated from a c++ example)
setDevice(0)
info()
var img_color = loadImage("assets/man.jpg",true)
let img = colorSpace(img_color, CSpace.GRAY, CSpace.RGB)
img_color /= 255
let feat = fast(img,20.0, 9, true, 0.05)
let hx = feat.getX().to_seq(float)
let hy = feat.getY().to_seq(float)
let draw_len = 3
for f in 0..<feat.getNumFeatures():
let x = int(hx[f])
let y = int(hy[f])
img_color[y, mseq(int(x)-draw_len, x+draw_len), 0] = 0
img_color[y, mseq(int(x)-draw_len, x+draw_len), 1] = 1
img_color[y, mseq(int(x)-draw_len, x+draw_len), 2] = 0
img_color[mseq(y-draw_len, y+draw_len), x, 0] = 0
img_color[mseq(y-draw_len, y+draw_len), x, 1] = 1
img_color[mseq(y-draw_len, y+draw_len), x, 2] = 0
echo "Features found: $1" % $feat.getNumFeatures
var wnd : Window
wnd.set_title("FAST Feature Detector")
while not wnd.close():
wnd.image(img_color)
The wrapper requires the C++ backend of Nim and has only been tested on Arch linux - I would expect it to work on Linux in general but I did not have time to check other OS.
Excellent! :D
I wonder how this would affect Nim's standing in the kostya/benchmarks (which were just recently mentioned here), namely matrix multiplication...
Hi - I think the reason for Julia being so fast in the matmul benchmark is that it uses many high performance c/c++ libraries in the background, I am not sure what they use for matrices but the julia result is probably just what you would get with c/c++ and blas or atlas.
My guess is that with the CPU backend the results for ArrayFire would be very similar - I did not do any optimization yet but I would assume that the Nim wrapper does not slow down things too much - the results would be quite similar to the Julia results.
For me Julia is a good example how clever integration of existing libraries can make a language interesting for scientific applications. After ArrayFire I am planning to make Nim wrapper for some more libraries - c2nim is a very fine tool although the documentation for it and Nim in general has the density of a neutron star ;-)
Best Regards
I'm really excited to see this! I'm using Nim for data science and I would love more wrappers and libraries :)
There's also:
https://github.com/stavenko/nim-glm
https://github.com/unicredit/linear-algebra
if looking for other libraries with similar aims. I've used andreaferreti's linear-algebra library for a project, and it's been great. The one thing I really would like is higher-dimensional matrices (which it looks like this provides). Awesome!
Hey everyone. I'm working on a program using the awesome ArrayFire Nim.
aftest0.nim
import ArrayFireNim
# that all
compile aftest0.nim
nim c --backend:cpp --passC:-I/opt/ArrayFire-3.8.3-Linux/include --passL:-L/opt/ArrayFire-3.8.3-Linux/lib64 aftest0.nim
73821 lines; 1.920s; 75.781MiB peakmem; proj: /home/my/test/aftest0.nim; out: /home/my/test/aftest0 [SuccessX]
The code compiled successfully in nim 1.6.14 version.
but I got an error in nim 2.0.0 version.
Please tell me how to fix.
error: T1_ was not declared in this scope
42 | N_LIB_PRIVATE af::index span__65rray70ire78im_u8759(T1_ );
Error: execution of an external compiler program g++ -c -std=gnu++17 -funsigned-char-w -fmax-errors=3 -fpermissive -pthread -std=c++11
failed with exit code: 1
@mArrayFireNim.nim.cpp v1.6.14
/* Generated by Nim Compiler v1.6.14 */
/* Compiled for: Linux, amd64, gcc */
/* Command for C compiler:
g++ -c -std=gnu++14 -funsigned-char-w -fmax-errors=3 -fpermissive -std=c++11 -g -I/opt/ArrayFire-3.8.3-Linux/include -I/home/my/.choosenim/toolchains/ nim-1.6.14/lib -I/home/my/test -o /home/my/.cache/nim/aftest0_d/@mArrayFireNim.nim.cpp.o /home/my/.cache/nim/aftest0_d/@mArrayFireNim.nim.cpp */
#define NIM_INTBITS 64
#include "nimbase.h"
#include "arrayfire.h"
#undef LANGUAGE_C
#undef MIPSEB
#undef MIPSEL
#undef PPC
#undef R3000
#undef R4000
#undef i386
#undef linux
#undef mips
#undef near
#undef far
#undef powerpc
#undef unix
#define nimfr_(proc, file) \
TFrame FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; nimFrame(&FR_);
#define nimfrs_(proc, file, slots, length) \
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; VarSlot s[slots];} FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; nimFrame((TFrame*)&FR_);
#define nimln_(n, file) \
FR_.line = n; FR_.filename = file;
N_LIB_PRIVATE N_NIMCALL(af::seq, aseq__65rray70ire78im_7881)(NI first, NI last, NI step);
static N_INLINE(void, nimFrame)(TFrame* s);
N_LIB_PRIVATE N_NOINLINE(void, callDepthLimitReached__system_2993)(void);
static N_INLINE(void, popFrame)(void);
N_LIB_PRIVATE NIM_CONST int iend__65rray70ire78im_6818 = ((int) -1);
N_LIB_PRIVATE af::index span__65rray70ire78im_7898;
....
}
}
@mArrayFireNim.nim.cpp v2.0.0
/* Generated by Nim Compiler v2.0.0 */
/* Compiled for: Linux, amd64, gcc */
/* Command for C compiler:
g++ -c -std=gnu++17 -funsigned-char-w -fmax-errors=3 -fpermissive -pthread -std=c++11 -g -I/opt/ArrayFire-3.8.3-Linux/include -I/home/my/.choosenim/ toolchains/nim-2.0.0/lib -I/home/my/test -o /home/my/.cache/nim/aftest0_d/@mArrayFireNim.nim.cpp.o /home/my/.cache/nim/aftest0_d/@mArrayFireNim.nim.cpp */
#define NIM_INTBITS 64
#include "nimbase.h"
#include "arrayfire.h"
#undef LANGUAGE_C
#undef MIPSEB
#undef MIPSEL
#undef PPC
#undef R3000
#undef R4000
#undef i386
#undef linux
#undef mips
#undef near
#undef far
#undef powerpc
#undef unix
#define nimfr_(proc, file) \
TFrame FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; nimFrame(&FR_);
#define nimfrs_(proc, file, slots, length) \
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename;NI len;VarSlot s[slots];} FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; nimFrame((TFrame*)&FR_);
#define nimln_(n) \
FR_.line = n;
#define nimlf_(n, file) \
FR_.line = n; FR_.filename = file;
N_LIB_PRIVATE N_NIMCALL(af::seq, aseq__65rray70ire78im_u8732)(NI first_p0, NI last_p1, NI step_p2);
static N_INLINE(void, nimFrame)(TFrame* s_p0);
N_LIB_PRIVATE N_NOINLINE(void, callDepthLimitReached__system_u4570)(void);
static N_INLINE(void, popFrame)(void);
N_LIB_PRIVATE NIM_CONST int iend__65rray70ire78im_u7521 = ((int)-1);
extern NIM_THREADVAR TFrame* framePtr__system_u4006;
N_LIB_PRIVATE af::index span__65rray70ire78im_u8759(T1_);
static N_INLINE(void, nimFrame)(TFrame* s_p0) {
....
}
}