<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://prasunanand.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://prasunanand.github.io/" rel="alternate" type="text/html" /><updated>2026-11-09T12:16:51+00:00</updated><id>https://prasunanand.github.io/feed.xml</id><title type="html">Prasun’s Blog</title><subtitle>Prasun Anand&apos;s blog on GPU computing, scientific computing in Ruby, and tools for data science.</subtitle><author><name>Prasun Anand</name></author><entry><title type="html">RbCUDA: Installation and Architecture</title><link href="https://prasunanand.github.io/cuda/opencl/ruby/rbcuda/2018/02/24/rubygrant17-rbcuda-installation-and-architecture.html" rel="alternate" type="text/html" title="RbCUDA: Installation and Architecture" /><published>2018-02-24T06:40:41+00:00</published><updated>2018-02-24T06:40:41+00:00</updated><id>https://prasunanand.github.io/cuda/opencl/ruby/rbcuda/2018/02/24/rubygrant17-rbcuda-installation-and-architecture</id><content type="html" xml:base="https://prasunanand.github.io/cuda/opencl/ruby/rbcuda/2018/02/24/rubygrant17-rbcuda-installation-and-architecture.html"><![CDATA[<p>RBCuda is a software library designed to integrate with Ruby. It provides an interface for leveraging NVIDIA CUDA technology to accelerate computations on GPUs (Graphics Processing Units). This can significantly speed up tasks like matrix operations, simulations, and data processing by harnessing the parallel processing power of modern GPUs. Essentially, RBCuda helps Ruby users perform complex calculations more efficiently by offloading them to a GPU.</p>

<p>The main objectives of RbCUDA are:</p>

<ul>
  <li>Map all of CUDA into Ruby</li>
  <li>Ready-made on-GPU linear algebra, reduction, scan using cuBLAS, cuMath, cuSolver libraries.</li>
  <li>Random Numer generator using cuRand</li>
  <li>Near-zero wrapping overhead.</li>
  <li>CUDA profiler for Ruby.</li>
</ul>

<p>This post explains the architecture of <code class="language-plaintext highlighter-rouge">RbCUDA</code> and how you can install it on your machine.</p>

<h1 id="installation">Installation</h1>

<p>Install <code class="language-plaintext highlighter-rouge">CUDA</code> on your machine.</p>

<h3 id="building-rbcuda-from-source">Building <code class="language-plaintext highlighter-rouge">RbCUDA</code> from source.</h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/prasunanand/rbcuda
<span class="nb">cd </span>rbcuda
bundle <span class="nb">install
</span>rake compile
</code></pre></div></div>

<h3 id="installing-the-gem">Installing the gem</h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gem build rbcuda.gemspec
gem <span class="nb">install </span>rbcuda-0.0.0.gem
</code></pre></div></div>

<p>To check if installation was successful, run pry.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">rake</span> <span class="n">pry</span>
<span class="n">pry</span> <span class="o">-</span><span class="n">r</span> <span class="s1">'./lib/rbcuda.rb'</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">RbCUDA</span><span class="o">::</span><span class="no">CUDA</span><span class="p">.</span><span class="nf">cuInit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">device</span> <span class="o">=</span> <span class="no">RbCUDA</span><span class="o">::</span><span class="no">CUDA</span><span class="p">.</span><span class="nf">cuDeviceGet</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="nb">puts</span> <span class="n">device</span>
<span class="c1">#&lt;RbCUDA::RbCuDevice:0x00000001a9a2d0&gt;</span>
<span class="o">=&gt;</span> <span class="kp">nil</span>
<span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="nb">puts</span> <span class="no">RbCUDA</span><span class="o">::</span><span class="no">CUDA</span><span class="p">.</span><span class="nf">cuDeviceGetName</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="n">device</span><span class="p">);</span>
<span class="no">GeForce</span> <span class="no">GTX</span> <span class="mi">750</span> <span class="no">Ti</span>
</code></pre></div></div>
<p>If you are successfully able to retrive the name of GPU card, you are all set.</p>

<h1 id="code-organisation">Code organisation</h1>

<p><code class="language-plaintext highlighter-rouge">extconf.rb</code> that helps in building the shared object file can be found <a href="https://github.com/prasunanand/rbcuda/blob/master/ext/rbcuda/extconf.rb">here</a>.</p>

<p><code class="language-plaintext highlighter-rouge">rbcuda.h</code> defines all the Ruby structs that correspond to CUDA types. In the following code <code class="language-plaintext highlighter-rouge">CUfunction</code> type can be represented as <code class="language-plaintext highlighter-rouge">function_ptr</code>.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">typedef</span> <span class="n">struct</span> <span class="no">FUNCTION_PTR</span>
<span class="p">{</span>
  <span class="no">CUfunction</span> <span class="n">function</span><span class="p">;</span>
<span class="p">}</span><span class="n">function_ptr</span><span class="p">;</span>

<span class="n">typedef</span> <span class="n">struct</span> <span class="no">DEVICE_PTR</span>
<span class="p">{</span>
  <span class="no">CUdevice</span> <span class="n">device</span><span class="p">;</span>
<span class="p">}</span><span class="n">device_ptr</span><span class="p">;</span>

</code></pre></div></div>
<p>The struct <code class="language-plaintext highlighter-rouge">fuction_ptr</code> is then wrapped by a Ruby object called <code class="language-plaintext highlighter-rouge">RbCuFunction</code> in the file <code class="language-plaintext highlighter-rouge">ruby_rbcuda.c</code>.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">RbCUDA</span> <span class="o">=</span> <span class="n">rb_define_module</span><span class="p">(</span><span class="s2">"RbCUDA"</span><span class="p">);</span>

<span class="no">VALUE</span> <span class="no">RbCuDevice</span> <span class="o">=</span> <span class="no">Qnil</span><span class="p">;</span>
<span class="no">VALUE</span> <span class="no">RbCuFunction</span> <span class="o">=</span> <span class="no">Qnil</span><span class="p">;</span>

<span class="no">RbCuDevice</span>    <span class="o">=</span> <span class="n">rb_define_class_under</span><span class="p">(</span><span class="no">RbCUDA</span><span class="p">,</span> <span class="s2">"RbCuDevice"</span><span class="p">,</span>    <span class="n">rb_cObject</span><span class="p">);</span>
<span class="no">RbCuFunction</span>  <span class="o">=</span> <span class="n">rb_define_class_under</span><span class="p">(</span><span class="no">RbCUDA</span><span class="p">,</span> <span class="s2">"RbCuFunction"</span><span class="p">,</span>  <span class="n">rb_cObject</span><span class="p">);</span>

</code></pre></div></div>

<h1 id="dev-array">Dev Array</h1>

<p>An array in RbCUDA is handled using Dev_Array class. Implementation is as follows:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>typedef struct DEV_PTR
{
  double* carray;
}dev_ptr;

Dev_Array = rb_define_class_under(RbCUDA, "Dev_Array", rb_cObject);

</code></pre></div></div>
<p>A Dev Array stores the pointer to the array data stored on the GPU. The usage will be explained in the next blog.</p>

<h1 id="functionalities">Functionalities</h1>

<p>RbCUDA has the following modules:</p>
<ol>
  <li>CUDA : It consists of low-level APIs called the CUDA driver APIs.</li>
  <li>Runtime : It consists of higher-level APIs called the CUDA runtime APIs that are implemented on top of the CUDA driver APIs.</li>
  <li>CuBLAS : It consists of BLAS APIs provided by cuBLAS library.</li>
  <li>CuSolver : It consists of APIs provided by cuSolver library.</li>
  <li>CuRand : It consists APIs provided by cuRand library.</li>
  <li>Profiler : It consists of APIs for profiling CUDA code.</li>
</ol>

<h1 id="conclusion">Conclusion</h1>

<p>I have explained how the underlying architecture looks like.</p>

<p>We have got <code class="language-plaintext highlighter-rouge">RbCUDA</code> successfully installed on our system. In the next blog I will talk about implementing Runtime APIs.</p>

<div id="disqus_thread"></div>
<script>
/**
* RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
* LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
*/
/*
var disqus_config = function () {
this.page.url = PAGE_URL; // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};
*/
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');

s.src = '//prasunanandblog.disqus.com/embed.js';

s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>]]></content><author><name>Prasun Anand</name></author><category term="cuda" /><category term="opencl" /><category term="ruby" /><category term="rbcuda" /><summary type="html"><![CDATA[RBCuda is a software library designed to integrate with Ruby. It provides an interface for leveraging NVIDIA CUDA technology to accelerate computations on GPUs (Graphics Processing Units). This can significantly speed up tasks like matrix operations, simulations, and data processing by harnessing the parallel processing power of modern GPUs. Essentially, RBCuda helps Ruby users perform complex calculations more efficiently by offloading them to a GPU.]]></summary></entry><entry><title type="html">RbCUDA: CUDA bindings for Ruby</title><link href="https://prasunanand.github.io/cuda/opencl/ruby/rbcuda/2017/12/30/rubygrant17-rbcuda-introduction.html" rel="alternate" type="text/html" title="RbCUDA: CUDA bindings for Ruby" /><published>2017-12-30T06:40:41+00:00</published><updated>2017-12-30T06:40:41+00:00</updated><id>https://prasunanand.github.io/cuda/opencl/ruby/rbcuda/2017/12/30/rubygrant17-rbcuda-introduction</id><content type="html" xml:base="https://prasunanand.github.io/cuda/opencl/ruby/rbcuda/2017/12/30/rubygrant17-rbcuda-introduction.html"><![CDATA[<p>I have been working on a new project called <strong>RbCUDA</strong>.</p>

<p>In this project, I want to make it possible to combine the
beauty of Ruby with transparent GPU processing with minimal overheads, so that software developers can easily use
that power when available, and farm out computations transparently to GPU and CPU.</p>

<p>Nvidia has been developing a lot of GPU accelerated libraries for linear algebra(CUDA, cuBLAS, cuSolver), Random Number
Generation(cuRand), fast-fourier transform(cuFFT), Parallel Primitives and Data Structures(Thrust) and image processing
(NVIDIA Performance Primitives Library). Many Python/Julia/C++ libraries are being built on top of these libraries.
RbCUDA would fill this gap in the Ruby ecosystem making it a highly-preferable option for GPU computing.
It will work on Nvidia hardware running on client computers and on servers that make use of TESLA’s.</p>

<p>Recently, I was at Nvidia Developer Connect in my city. I was completely amazed by the new hardware launched by Nvidia this year. It
makes me really confident about the great impact this project will create in the Ruby ecosystem.</p>

<h1 id="previous-efforts">Previous Efforts</h1>

<p><a href="https://github.com/xman/sgc-ruby-cuda">sgc-ruby-cuda</a> is an existing alternative for CUDA Ruby bindings. However, this library just helps in executing custom kernels.
It also doesn’t have support cuBLAS, and other cuMath libraries.</p>

<h1 id="objectives">Objectives</h1>

<p>The main objectives of RbCUDA are:</p>

<ol>
  <li>Map all of CUDA into Ruby</li>
  <li>Ready-made on-GPU linear algebra, reduction, scan using cuBLAS, cuMath, cuSolver libraries.</li>
  <li>Random Numer generator using cuRand</li>
  <li>Near-zero wrapping overhead.</li>
  <li>CUDA profiler for Ruby.</li>
</ol>

<p>In the near future:</p>

<ol>
  <li>fast-fourier transform(cuFFT)</li>
  <li>Parallel Primitives and Data Structures(Thrust)</li>
  <li>Image processing (NVIDIA Performance Primitives Library).</li>
  <li>Use CuDNN to power a Deep Learning Library written in Ruby.</li>
</ol>

<h1 id="codebase">Codebase</h1>

<p><a href="https://github.com/prasunanand/rbcuda">https://github.com/prasunanand/rbcuda</a></p>

<p>Contributions are welcome!</p>

<h1 id="example">Example</h1>

<p>Most of the times, when we want to use CUDA for accelerating our code, we end up optimizing matrix-multiplication.
I wrote an <a href="https://github.com/prasunanand/rbcuda/blob/master/examples/matmul.rb">example</a> that showcases how RbCUDA
is the most efficient Ruby library to be used for Number crunching.</p>

<p>The example copies two matrices from CPU to GPU, runs matrix multiplication over it. Then the resulting matrix is copied
back to the CPU from GPU.</p>

<p>I benchmarked my code and compare it with other existing Ruby libraries.</p>

<p><img src="https://github.com/prasunanand/resume/blob/master/img/rbcuda/rbcuda_gemm.png?raw=true" alt="rbcuda_gemm" title="Fig.1. Matrix Multiplication" /></p>

<p>(Note: The above benchmarks have been done on an AMD FX 8350 octacore processor and Nvidia GTX 750Ti GPU.
CUDA backend of ArrayFire was used with double floating points.)</p>

<p><strong>RbCUDA is the fastest among all. Yay!</strong></p>

<p>RbCUDA is the fastest of all the Ruby libraries. The time taken for matrix multiplication is 0.000017s on my machine. The plain C code
takes me 0.000013s for this calculation.</p>

<p>RbCUDA is 24x faster than ArrayFire for matrix multiplication, Most of the speed gain going straight to CUDA is probably from
removing an interaction layer (and buffers) as well as how the data is organized and fed to the underlying architecture.</p>

<p>Hence, an overhead of 0.000004s over plain C code makes, it highly efficient Maths library in Ruby.</p>

<p>The great thing about this example is that the code is very Rubyish &lt;3.</p>

<p>The Code Implementation of matrix multiplication will be discussed in my upcoming blog posts.</p>

<h1 id="profiling-matrix-multiplication">Profiling matrix multiplication.</h1>

<p>I have also created a profiler for RbCUDA . The profiling example can be found <a href="https://github.com/prasunanand/rbcuda/blob/master/examples/profiler.rb">here</a>.</p>

<p>Output of the code.</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">#</span><span class="w"> </span><span class="err">CUDA_PROFILE_LOG_VERSION</span><span class="w"> </span><span class="mf">2.0</span><span class="w">
</span><span class="err">#</span><span class="w"> </span><span class="err">CUDA_DEVICE</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="err">GeForce</span><span class="w"> </span><span class="err">GTX</span><span class="w"> </span><span class="mi">750</span><span class="w"> </span><span class="err">Ti</span><span class="w">
</span><span class="err">#</span><span class="w"> </span><span class="err">CUDA_CONTEXT</span><span class="w"> </span><span class="mi">1</span><span class="w">
</span><span class="err">#</span><span class="w"> </span><span class="err">TIMESTAMPFACTOR</span><span class="w"> </span><span class="mi">14e96</span><span class="err">c</span><span class="mi">24317</span><span class="err">d</span><span class="mi">8324</span><span class="w">
</span><span class="err">method,gputime,cputime,occupancy</span><span class="w">
</span><span class="err">method=</span><span class="p">[</span><span class="w"> </span><span class="err">memcpyHtoD</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">gputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">16.544</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">cputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">18.705</span><span class="w"> </span><span class="p">]</span><span class="w">
</span><span class="err">method=</span><span class="p">[</span><span class="w"> </span><span class="err">memcpyHtoD</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">gputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">16.288</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">cputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">22.089</span><span class="w"> </span><span class="p">]</span><span class="w">
</span><span class="err">method=</span><span class="p">[</span><span class="w"> </span><span class="err">memcpyHtoD</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">gputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">1.216</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">cputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">6.923</span><span class="w"> </span><span class="p">]</span><span class="w">
</span><span class="err">method=</span><span class="p">[</span><span class="w"> </span><span class="err">_Z</span><span class="mi">19</span><span class="err">gemm_kernel</span><span class="mi">2</span><span class="err">x</span><span class="mi">2</span><span class="err">_coreIdLb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">EEvPT_PKS</span><span class="mi">0</span><span class="err">_S</span><span class="mi">3</span><span class="err">_iiiiiiS</span><span class="mi">1</span><span class="err">_S</span><span class="mi">1</span><span class="err">_S</span><span class="mi">0</span><span class="err">_S</span><span class="mi">0</span><span class="err">_i</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">gputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">76.736</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">cputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">11.967</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">occupancy=</span><span class="p">[</span><span class="w"> </span><span class="mf">0.469</span><span class="w"> </span><span class="p">]</span><span class="w">
</span><span class="err">method=</span><span class="p">[</span><span class="w"> </span><span class="err">_Z</span><span class="mi">19</span><span class="err">gemm_kernel</span><span class="mi">2</span><span class="err">x</span><span class="mi">2</span><span class="err">_coreIdLb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">EEvPT_PKS</span><span class="mi">0</span><span class="err">_S</span><span class="mi">3</span><span class="err">_iiiiiiS</span><span class="mi">1</span><span class="err">_S</span><span class="mi">1</span><span class="err">_S</span><span class="mi">0</span><span class="err">_S</span><span class="mi">0</span><span class="err">_i</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">gputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">73.024</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">cputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">6.485</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">occupancy=</span><span class="p">[</span><span class="w"> </span><span class="mf">0.469</span><span class="w"> </span><span class="p">]</span><span class="w">
</span><span class="err">method=</span><span class="p">[</span><span class="w"> </span><span class="err">_Z</span><span class="mi">19</span><span class="err">gemm_kernel</span><span class="mi">2</span><span class="err">x</span><span class="mi">2</span><span class="err">_coreIdLb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">EEvPT_PKS</span><span class="mi">0</span><span class="err">_S</span><span class="mi">3</span><span class="err">_iiiiiiS</span><span class="mi">1</span><span class="err">_S</span><span class="mi">1</span><span class="err">_S</span><span class="mi">0</span><span class="err">_S</span><span class="mi">0</span><span class="err">_i</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">gputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">72.928</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">cputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">5.739</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">occupancy=</span><span class="p">[</span><span class="w"> </span><span class="mf">0.469</span><span class="w"> </span><span class="p">]</span><span class="w">
</span><span class="err">method=</span><span class="p">[</span><span class="w"> </span><span class="err">_Z</span><span class="mi">19</span><span class="err">gemm_kernel</span><span class="mi">2</span><span class="err">x</span><span class="mi">2</span><span class="err">_coreIdLb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">EEvPT_PKS</span><span class="mi">0</span><span class="err">_S</span><span class="mi">3</span><span class="err">_iiiiiiS</span><span class="mi">1</span><span class="err">_S</span><span class="mi">1</span><span class="err">_S</span><span class="mi">0</span><span class="err">_S</span><span class="mi">0</span><span class="err">_i</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">gputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">72.928</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">cputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">5.725</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">occupancy=</span><span class="p">[</span><span class="w"> </span><span class="mf">0.469</span><span class="w"> </span><span class="p">]</span><span class="w">
</span><span class="err">method=</span><span class="p">[</span><span class="w"> </span><span class="err">_Z</span><span class="mi">19</span><span class="err">gemm_kernel</span><span class="mi">2</span><span class="err">x</span><span class="mi">2</span><span class="err">_coreIdLb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">ELb</span><span class="mi">0</span><span class="err">EEvPT_PKS</span><span class="mi">0</span><span class="err">_S</span><span class="mi">3</span><span class="err">_iiiiiiS</span><span class="mi">1</span><span class="err">_S</span><span class="mi">1</span><span class="err">_S</span><span class="mi">0</span><span class="err">_S</span><span class="mi">0</span><span class="err">_i</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">gputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">72.896</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">cputime=</span><span class="p">[</span><span class="w"> </span><span class="mf">5.701</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="err">occupancy=</span><span class="p">[</span><span class="w"> </span><span class="mf">0.469</span><span class="w"> </span><span class="p">]</span><span class="w">
</span></code></pre></div></div>
<p>(Note: The unit of time is microsecond).</p>

<h1 id="ruby-grant-2017">Ruby Grant 2017</h1>

<p>This project is funded by Ruby Association. I am very thankful to them for supporting this project.
<a href="http://www.ruby.or.jp/en/news/20171206">Link</a>.</p>

<h1 id="contributions-are-welcome">Contributions are welcome!</h1>

<p>I request all the Rubyists if you have a Ruby code that you want to be accelerated by GPU, please try RbCUDA / ArrayFire. If you are
into Deep learning, let me know if you want to use RbCUDA to power your neural nets for GPU acceleration.</p>

<p>Feel free to open an issue!</p>

<p>Stay tuned for more posts about GPU computing with Ruby.</p>

<div id="disqus_thread"></div>
<script>
/**
* RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
* LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
*/
/*
var disqus_config = function () {
this.page.url = PAGE_URL; // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};
*/
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');

s.src = '//prasunanandblog.disqus.com/embed.js';

s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>]]></content><author><name>Prasun Anand</name></author><category term="cuda" /><category term="opencl" /><category term="ruby" /><category term="rbcuda" /><summary type="html"><![CDATA[I have been working on a new project called RbCUDA.]]></summary></entry><entry><title type="html">GSoC 2017: Creating the fastest math libraries for Ruby by using the GPU through OpenCL and ArrayFire.</title><link href="https://prasunanand.github.io/arrayfire/cuda/opencl/ruby/2017/08/28/gsoc17-project-report.html" rel="alternate" type="text/html" title="GSoC 2017: Creating the fastest math libraries for Ruby by using the GPU through OpenCL and ArrayFire." /><published>2017-08-28T02:40:41+00:00</published><updated>2017-08-28T02:40:41+00:00</updated><id>https://prasunanand.github.io/arrayfire/cuda/opencl/ruby/2017/08/28/gsoc17-project-report</id><content type="html" xml:base="https://prasunanand.github.io/arrayfire/cuda/opencl/ruby/2017/08/28/gsoc17-project-report.html"><![CDATA[<p>GSoC 2017 is about to end. This post summarises my work during the course of summer.</p>

<p>Few people realise it, but even modest computers today, including mobile phones, have powerful GPUs. And these GPUs can be used serially and in parallel to CPUs, potentially delivering awesome performance.</p>

<p>In this project I wanted to make it possible to combine the beauty of Ruby with transparent GPU processing so that software developers can easily use that power when available, and farm out computations transparently to GPU and CPU. This will work both on client computers and on servers that make use of TESLA’s and Intel Xeon Phi solutions.</p>

<h1 id="application">Application</h1>

<p>The GSoC 2017 application can be found <a href="https://github.com/prasunanand/resume/wiki/GSoC-2017-proposal">here</a>.</p>

<h1 id="code">Code</h1>

<p><a href="https://github.com/prasunanand/arrayfire-rb">ArrayFire-rb</a>: The <a href="https://github.com/arrayfire/arrayfire-rb/pull/3">pull request</a> is undergoing a review.</p>

<p>ArrayFire-rb Benchmarks: Codebase can be found <a href="https://github.com/prasunanand/arrayfire-rb-benchmark-suite">here</a>.</p>

<p>Bio::FasterLmmD : Codebase can be found <a href="https://github.com/prasunanand/bio-faster_lmm_d">here</a></p>

<h1 id="goals">Goals</h1>

<p>ArrayFire-rb now supports linear algebra on GPU and CPU. Currently only <strong>double</strong> dtype has been implemented.
It supports dense and sparse matrices. It has multiple backends namely, CUDA, OpenCL and CPU.</p>

<p>The work on creating the bindings have been explained in last nine blog posts:</p>

<ol>
  <li><a href="/ruby-c-extensions/2017/06/23/gsoc17-ruby-c-extensions-for-complex-projects.html">Ruby C extensions for complex projects</a></li>
  <li><a href="/arrayfire/2017/06/23/gsoc17-arrayfire-ruby-bindings-part-1-installation.html">Installation</a></li>
  <li><a href="/arrayfire/2017/07/04/gsoc17-arrayfire-ruby-bindings-part-2-af_array.html">Af_Array</a>(see performance)</li>
  <li><a href="/arrayfire/2017/07/22/gsoc17-arrayfire-ruby-bindings-part-3-minitest-algorithm.html">Test-suite and Algorithm class</a></li>
  <li><a href="/arrayfire/2017/08/16/gsoc17-arrayfire-ruby-bindings-part-4-blas-lapack.html">BLAS and LAPACK routines</a>(see performance)</li>
  <li><a href="/arrayfire/2017/08/17/gsoc17-arrayfire-ruby-bindings-part-4-statistics-and-random-engine.html">Statistics and Random Engine routines</a></li>
  <li><a href="/arrayfire/2017/08/22/gsoc17-arrayfire-ruby-bindings-part-6-device.html">Device and Util</a></li>
  <li><a href="/arrayfire/2017/08/24/gsoc17-arrayfire-ruby-bindings-part-7-backend-cuda-and-opencl.html">Multiple Backends: CUDA, OpenCL and CPU</a></li>
  <li><a href="/arrayfire/2017/08/24/gsoc17-arrayfire-ruby-bindings-part-8-nmatrix-interface.html">ArrayFire-NMatrix Interface</a></li>
</ol>

<p>The performance of ArrayFire-rb is outstanding as expected.</p>

<p>I took a side-track working on <code class="language-plaintext highlighter-rouge">Bio::FasterLmmD</code> . This work is not complete and still in progress.
It is an effort to <code class="language-plaintext highlighter-rouge">call D from Ruby</code>. The work has been explained in a previous <a href="/gpu-computing/2017/07/25/gsoc17-calling-d-from-ruby-for-gpu-computing.html">blog post</a>.</p>

<p>The work on ArrayFire-rb - JRuby has been postponed for now as I wanted to concentrate on MRI for
the best results.</p>

<h1 id="future-work">Future Work</h1>

<p>The future work involves improving the ArrayFire-rb code and writing tutorials. ArrayFire is not limited to
linear algebra so I will create bindings for Signal Processing, Computer Vision, etc. I will also add support
for data types other than <code class="language-plaintext highlighter-rouge">double</code>.</p>

<p>The work on ArrayFire-rb - JRuby will begin as soon as ArrayFire gem is published.</p>

<h1 id="foss">FOSS</h1>

<p>This has been my second GSoC with SciRuby. It has been more than an year contibuting extensively to FOSS.
It has made me a 1000X better programmer that I used to be.</p>

<p>I really appreciate the effort by Google Open Source Committee for conducting GSoC every year. It is the
best platform for the aspiring programmers improve their skill and give back to society by developing free
and open source software.</p>

<p>Last year’s GSoC work helped me to present a talk at FOSDEM 2017 and Ruby Conf India 2017.  I got active
in the Indian Ruby Community. Recently, I have been invited as a speaker to Ruby World Conference 2017, Matsue, Japan
to talk on “GPU computing with Ruby”.</p>

<p>I plan to continue contributing to open source, strive for improving my skills, and help new programmers
contribute to FOSS. I would be glad if I could mentor students for upcoming GSoCs.</p>

<h1 id="acknowledgements">Acknowledgements</h1>

<p>I would like to express my sincere gratitude to my mentor Pjotr Prins, for his guidance, patience and support.
I have learn a lot from him since my last GSoC and still learning. I couldn’t have hoped for a better mentor.</p>

<p>I am grateful to Google and the Ruby Science Foundation for this golden opportunity.</p>

<p>I am very thankful to John Woods, Sameer Deshmukh, Alexej Gossmann, Gaurav Tamba and Pradeep Garigipati
who mentored me through the project.</p>

<div id="disqus_thread"></div>
<script>
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');

s.src = '//prasunanandblog.disqus.com/embed.js';

s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>]]></content><author><name>Prasun Anand</name></author><category term="arrayfire" /><category term="cuda" /><category term="opencl" /><category term="ruby" /><summary type="html"><![CDATA[GSoC 2017 is about to end. This post summarises my work during the course of summer.]]></summary></entry><entry><title type="html">ArrayFire Ruby Bindings (Part VII : Multiple Backends: CUDA, OpenCL and CPU)</title><link href="https://prasunanand.github.io/arrayfire/2017/08/24/gsoc17-arrayfire-ruby-bindings-part-7-backend-cuda-and-opencl.html" rel="alternate" type="text/html" title="ArrayFire Ruby Bindings (Part VII : Multiple Backends: CUDA, OpenCL and CPU)" /><published>2017-08-24T08:30:00+00:00</published><updated>2017-08-24T08:30:00+00:00</updated><id>https://prasunanand.github.io/arrayfire/2017/08/24/gsoc17-arrayfire-ruby-bindings-part-7-backend-cuda-and-opencl</id><content type="html" xml:base="https://prasunanand.github.io/arrayfire/2017/08/24/gsoc17-arrayfire-ruby-bindings-part-7-backend-cuda-and-opencl.html"><![CDATA[<p>ArrayFire can run not just on GPU devices but also on CPU devices, which is one of its really cool features.
With version <strong>3.2</strong> the <strong>unified-backend</strong> helps in changing the ArrayFire backend on the fly.
When using the unified-backend, the preference order for the default backend is CUDA &gt; OpenCL &gt; CPU.</p>

<p>The CPU backend requires <code class="language-plaintext highlighter-rouge">Intel MKL libraries</code> be installed. To install Intel MKL library, go to the official
download <a href="https://software.intel.com/en-us/mkl">link</a>. Next extract the file and run <code class="language-plaintext highlighter-rouge">sudo install.sh</code> from the
project root directory.</p>

<p>For an AMD CPU, you need to specify the location of <code class="language-plaintext highlighter-rouge">libmkl_rt.so</code>.</p>

<p>To solve this on a debian machine:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">cd</span> /etc/ld.so.conf.d/
<span class="nv">$ </span><span class="nb">sudo </span>nano mylibs.conf
</code></pre></div></div>

<p>Paste line:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/opt/intel/compilers_and_libraries_2017/linux/mkl/lib/intel64_lin/
</code></pre></div></div>

<p>Next, run</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo ldconfig
</code></pre></div></div>

<p>Now download arrayfire-rb from <a href="https://github.com/prasunanand/arrayfire-rb">link</a></p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">git</span> <span class="nb">clone</span> <span class="n">https</span><span class="ss">:/</span><span class="o">/</span><span class="n">github</span><span class="p">.</span><span class="nf">com</span><span class="o">/</span><span class="n">prasunanand</span><span class="o">/</span><span class="n">arrayfire</span><span class="o">-</span><span class="n">rb</span>
<span class="err">$</span> <span class="n">rake</span> <span class="n">compile</span>
<span class="err">$</span> <span class="n">rake</span> <span class="n">pry</span>
<span class="n">pry</span> <span class="o">-</span><span class="n">r</span> <span class="s1">'./lib/arrayfire.rb'</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Backend</span><span class="p">.</span><span class="nf">get_backend_count</span>
<span class="o">=&gt;</span> <span class="mi">3</span>
<span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Backend</span><span class="p">.</span><span class="nf">get_active_backend</span>
<span class="o">=&gt;</span> <span class="s2">"AF_BACKEND_CUDA"</span>
<span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Backend</span><span class="p">.</span><span class="nf">set_backend</span><span class="p">(</span><span class="ss">:AF_BACKEND_CPU</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="kp">nil</span>
<span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Backend</span><span class="p">.</span><span class="nf">get_active_backend</span>
<span class="o">=&gt;</span> <span class="s2">"AF_BACKEND_CPU"</span>
</code></pre></div></div>

<p>Voila! You can run ArrayFire on CPU.</p>

<p>Lets look into the implementation and what else can we do.</p>

<h1 id="backend">Backend</h1>

<p>The class structure of Backend class is as follows:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kt">void</span> <span class="nf">Init_arrayfire</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">ArrayFire</span> <span class="o">=</span> <span class="n">rb_define_module</span><span class="p">(</span><span class="s">"ArrayFire"</span><span class="p">);</span>

  <span class="n">Backend</span> <span class="o">=</span> <span class="n">rb_define_class_under</span><span class="p">(</span><span class="n">ArrayFire</span><span class="p">,</span> <span class="s">"Backend"</span><span class="p">,</span> <span class="n">rb_cObject</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Backend</span><span class="p">,</span> <span class="s">"get_backend_count"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_get_backend_count</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Backend</span><span class="p">,</span> <span class="s">"get_available_backends"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_get_available_backends</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Backend</span><span class="p">,</span> <span class="s">"get_backend_id"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_get_backend_id</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Backend</span><span class="p">,</span> <span class="s">"get_active_backend"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_get_active_backend</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Backend</span><span class="p">,</span> <span class="s">"get_device_id"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_get_backend_device_id</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Backend</span><span class="p">,</span> <span class="s">"set_backend"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_set_backend</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The C bindings were implemented as:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_get_backend_count</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">){</span>
  <span class="n">uint</span> <span class="n">num_backends</span><span class="p">;</span>
  <span class="n">af_get_backend_count</span><span class="p">(</span><span class="o">&amp;</span><span class="n">num_backends</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">UINT2NUM</span><span class="p">(</span><span class="n">num_backends</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_get_available_backends</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">){</span>
  <span class="kt">int</span> <span class="n">backends</span><span class="p">;</span>
  <span class="n">af_get_available_backends</span><span class="p">(</span><span class="o">&amp;</span><span class="n">backends</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">INT2NUM</span><span class="p">(</span><span class="n">backends</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_get_backend_id</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">array_val</span><span class="p">){</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">input</span><span class="p">;</span>
  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">array_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span>
  <span class="n">af_backend</span> <span class="n">backend</span><span class="p">;</span>
  <span class="n">af_get_backend_id</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">backend</span><span class="p">,</span> <span class="n">input</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">backend_name</span> <span class="o">=</span> <span class="n">get_backend_name</span><span class="p">(</span><span class="n">backend</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">rb_str_new_cstr</span><span class="p">(</span><span class="n">backend_name</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_get_active_backend</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">){</span>
  <span class="n">af_backend</span> <span class="n">backend</span><span class="p">;</span>
  <span class="n">af_get_active_backend</span><span class="p">(</span><span class="o">&amp;</span><span class="n">backend</span><span class="p">);</span>
  <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">backend_name</span> <span class="o">=</span> <span class="n">get_backend_name</span><span class="p">(</span><span class="n">backend</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">rb_str_new_cstr</span><span class="p">(</span><span class="n">backend_name</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_set_backend</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">backend_val</span><span class="p">){</span>
  <span class="n">af_backend</span> <span class="n">backend</span> <span class="o">=</span> <span class="n">arf_backend_type_from_rbsymbol</span><span class="p">(</span><span class="n">backend_val</span><span class="p">);</span>
  <span class="n">af_set_backend</span><span class="p">(</span><span class="n">backend</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">Qnil</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>An <code class="language-plaintext highlighter-rouge">af_backend</code>  symbol can be <code class="language-plaintext highlighter-rouge">:AF_BACKEND_DEFAULT</code>, <code class="language-plaintext highlighter-rouge">:AF_BACKEND_CPU</code>, <code class="language-plaintext highlighter-rouge">:AF_BACKEND_CUDA</code>, or <code class="language-plaintext highlighter-rouge">:AF_BACKEND_OPENCL</code>.
The implemetation is given below.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">*</span><span class="p">,</span> <span class="kt">size_t</span><span class="o">&gt;</span> <span class="n">BACKEND_TYPES</span> <span class="o">=</span> <span class="p">{</span>
  <span class="p">{</span><span class="s">"AF_BACKEND_DEFAULT"</span> <span class="p">,</span> <span class="mi">0</span><span class="p">},</span>                        <span class="c1">///&lt; Default backend order: OpenCL -&gt; CUDA -&gt; CPU</span>
  <span class="p">{</span><span class="s">"AF_BACKEND_CPU"</span>     <span class="p">,</span> <span class="mi">1</span><span class="p">},</span>                        <span class="c1">///&lt; CPU a.k.a sequential algorithms</span>
  <span class="p">{</span><span class="s">"AF_BACKEND_CUDA"</span>    <span class="p">,</span> <span class="mi">2</span><span class="p">},</span>                        <span class="c1">///&lt; CUDA Compute Backend</span>
  <span class="p">{</span><span class="s">"AF_BACKEND_OPENCL"</span>  <span class="p">,</span> <span class="mi">4</span><span class="p">}</span>                         <span class="c1">///&lt; OpenCL Compute Backend</span>
<span class="p">};</span>

<span class="n">af_backend</span> <span class="nf">arf_backend_type_from_rbsymbol</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">sym</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">ID</span> <span class="n">sym_id</span> <span class="o">=</span> <span class="n">SYM2ID</span><span class="p">(</span><span class="n">sym</span><span class="p">);</span>

  <span class="k">for</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">*</span><span class="p">,</span> <span class="kt">size_t</span><span class="o">&gt;::</span><span class="n">value_type</span><span class="o">&amp;</span> <span class="n">entry</span> <span class="o">:</span> <span class="n">BACKEND_TYPES</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">sym_id</span> <span class="o">==</span> <span class="n">rb_intern</span><span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">first</span><span class="p">))</span> <span class="p">{</span>
      <span class="k">return</span> <span class="n">static_cast</span><span class="o">&lt;</span><span class="n">af_backend</span><span class="o">&gt;</span><span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">second</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="n">VALUE</span> <span class="n">str</span> <span class="o">=</span> <span class="n">rb_any_to_s</span><span class="p">(</span><span class="n">sym</span><span class="p">);</span>
  <span class="n">rb_raise</span><span class="p">(</span><span class="n">rb_eArgError</span><span class="p">,</span> <span class="s">"invalid backend type symbol (:%s) specified"</span><span class="p">,</span> <span class="n">RSTRING_PTR</span><span class="p">(</span><span class="n">str</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">ArrayFire::Backend.get_available_backends</code> lets you know the backends available.
This is the table that helps you decipher the backends available.</p>

<table>
  <thead>
    <tr>
      <th>Value</th>
      <th style="text-align: left">Backends</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td style="text-align: left">None</td>
    </tr>
    <tr>
      <td>1</td>
      <td style="text-align: left">CPU</td>
    </tr>
    <tr>
      <td>2</td>
      <td style="text-align: left">CUDA</td>
    </tr>
    <tr>
      <td>3</td>
      <td style="text-align: left">CPU and CUDA</td>
    </tr>
    <tr>
      <td>4</td>
      <td style="text-align: left">OpenCL</td>
    </tr>
    <tr>
      <td>5</td>
      <td style="text-align: left">CPU and OpenCL</td>
    </tr>
    <tr>
      <td>6</td>
      <td style="text-align: left">CUDA and OpenCL</td>
    </tr>
    <tr>
      <td>7</td>
      <td style="text-align: left">CPU, CUDA and OpenCL</td>
    </tr>
  </tbody>
</table>

<p>Using <code class="language-plaintext highlighter-rouge">rake pry</code> to investigate the backend and device available for computing:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">rake</span> <span class="n">pry</span>
<span class="n">pry</span> <span class="o">-</span><span class="n">r</span> <span class="s1">'./lib/arrayfire.rb'</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">backends</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Backend</span><span class="p">.</span><span class="nf">get_available_backends</span>
<span class="o">=&gt;</span> <span class="mi">7</span>
<span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Backend</span><span class="p">.</span><span class="nf">get_backend_count</span>
<span class="o">=&gt;</span> <span class="mi">3</span>
<span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Backend</span><span class="p">.</span><span class="nf">get_active_backend</span>
<span class="o">=&gt;</span> <span class="s2">"AF_BACKEND_CUDA"</span>
<span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Device</span><span class="p">.</span><span class="nf">info</span>
<span class="no">ArrayFire</span> <span class="n">v3</span><span class="o">.</span><span class="mf">4.0</span> <span class="p">(</span><span class="no">CUDA</span><span class="p">,</span> <span class="mi">64</span><span class="o">-</span><span class="n">bit</span> <span class="no">Linux</span><span class="p">,</span> <span class="n">build</span> <span class="mi">75</span><span class="n">cad40</span><span class="p">)</span>
<span class="no">Platform</span><span class="p">:</span> <span class="no">CUDA</span> <span class="no">Toolkit</span> <span class="mf">7.5</span><span class="p">,</span> <span class="no">Driver</span><span class="p">:</span> <span class="mf">375.66</span>
<span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="no">GeForce</span> <span class="no">GTX</span> <span class="mi">750</span> <span class="no">Ti</span><span class="p">,</span> <span class="mi">4042</span> <span class="no">MB</span><span class="p">,</span> <span class="no">CUDA</span> <span class="no">Compute</span> <span class="mf">5.0</span>
<span class="o">=&gt;</span> <span class="kp">nil</span>
<span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Backend</span><span class="p">.</span><span class="nf">set_backend</span><span class="p">(</span><span class="ss">:AF_BACKEND_CPU</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="kp">nil</span>
<span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Device</span><span class="p">.</span><span class="nf">info</span>
<span class="no">ArrayFire</span> <span class="n">v3</span><span class="o">.</span><span class="mf">4.0</span> <span class="p">(</span><span class="no">CPU</span><span class="p">,</span> <span class="mi">64</span><span class="o">-</span><span class="n">bit</span> <span class="no">Linux</span><span class="p">,</span> <span class="n">build</span> <span class="mi">75</span><span class="n">cad40</span><span class="p">)</span>
<span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="no">AMD</span><span class="p">:</span> <span class="no">AMD</span> <span class="no">FX</span><span class="p">(</span><span class="n">tm</span><span class="p">)</span><span class="o">-</span><span class="mi">8350</span> <span class="no">Eight</span><span class="o">-</span><span class="no">Core</span> <span class="no">Processor</span>           <span class="p">,</span> <span class="mi">16077</span> <span class="no">MB</span><span class="p">,</span> <span class="no">Max</span> <span class="n">threads</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="kp">nil</span>
<span class="p">[</span><span class="mi">7</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Backend</span><span class="p">.</span><span class="nf">set_backend</span><span class="p">(</span><span class="ss">:AF_BACKEND_OPENCL</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="kp">nil</span>
<span class="p">[</span><span class="mi">8</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Device</span><span class="p">.</span><span class="nf">info</span>
<span class="no">ArrayFire</span> <span class="n">v3</span><span class="o">.</span><span class="mf">4.0</span> <span class="p">(</span><span class="no">OpenCL</span><span class="p">,</span> <span class="mi">64</span><span class="o">-</span><span class="n">bit</span> <span class="no">Linux</span><span class="p">,</span> <span class="n">build</span> <span class="mi">75</span><span class="n">cad40</span><span class="p">)</span>
<span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="no">NVIDIA</span>  <span class="p">:</span> <span class="no">GeForce</span> <span class="no">GTX</span> <span class="mi">750</span> <span class="no">Ti</span><span class="p">,</span> <span class="mi">4041</span> <span class="no">MB</span>

</code></pre></div></div>

<p>ArrayFire also helps in interacting custom <code class="language-plaintext highlighter-rouge">OpenCL</code> and <code class="language-plaintext highlighter-rouge">CUDA</code> kernels. Since, Ruby currently
doesn’t have <code class="language-plaintext highlighter-rouge">rbCUDA</code> and <code class="language-plaintext highlighter-rouge">rbOpenCL</code> gems (Ruby bindings for  CUDA and OpenCL respectively), we
can’t do much with <code class="language-plaintext highlighter-rouge">ArrayFire-rb</code>.</p>

<h1 id="conclusion">Conclusion</h1>

<p><code class="language-plaintext highlighter-rouge">ArrayFire-rb</code> can be used as a standalone linear algebra library not restricted to GPUs.</p>

<p>A user can change the backend on fly making it easier to leverage the power of CUDA and OpenCL. The
order of preference of default backend to harness maximum computing power helps him
not worry too much about performance tuning in the early stages of development, hence supporting
the philosophy of preferring <strong>convention over configuration</strong>.</p>

<p>In the next blog post, I will discuss about interfacing <code class="language-plaintext highlighter-rouge">ArrayFire-rb</code> to <code class="language-plaintext highlighter-rouge">NMatrix</code>.</p>

<div id="disqus_thread"></div>
<script>
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');

s.src = '//prasunanandblog.disqus.com/embed.js';

s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>]]></content><author><name>Prasun Anand</name></author><category term="arrayfire" /><summary type="html"><![CDATA[ArrayFire can run not just on GPU devices but also on CPU devices, which is one of its really cool features. With version 3.2 the unified-backend helps in changing the ArrayFire backend on the fly. When using the unified-backend, the preference order for the default backend is CUDA &gt; OpenCL &gt; CPU.]]></summary></entry><entry><title type="html">ArrayFire Ruby Bindings (Part VIII : Interfacing to NMatrix)</title><link href="https://prasunanand.github.io/arrayfire/2017/08/24/gsoc17-arrayfire-ruby-bindings-part-8-nmatrix-interface.html" rel="alternate" type="text/html" title="ArrayFire Ruby Bindings (Part VIII : Interfacing to NMatrix)" /><published>2017-08-24T08:30:00+00:00</published><updated>2017-08-24T08:30:00+00:00</updated><id>https://prasunanand.github.io/arrayfire/2017/08/24/gsoc17-arrayfire-ruby-bindings-part-8-nmatrix-interface</id><content type="html" xml:base="https://prasunanand.github.io/arrayfire/2017/08/24/gsoc17-arrayfire-ruby-bindings-part-8-nmatrix-interface.html"><![CDATA[<p>ArrayFire-rb has been interfaced to NMatrix so that they can work together. Sometimes, copying data
from GPU memory to CPU memory and vice versa can be slower than the computation time. Hence, a lot of
developers prefer to use GPU computing for the most time consuming task. The interface between <code class="language-plaintext highlighter-rouge">ArrayFire-rb</code>
and <code class="language-plaintext highlighter-rouge">NMatrix</code> helps in providing maximum freedom to the developers to use the libraries of their choice.</p>

<p>This post explains how NMatrix and ArrayFire-rb interface has been created. It starts with adding
nmatrix as a dependency to <code class="language-plaintext highlighter-rouge">arrayfire</code>.</p>
<h2 id="gemspec">Gemspec</h2>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">gem</span><span class="p">.</span><span class="nf">add_development_dependency</span> <span class="s1">'nmatrix'</span><span class="p">,</span> <span class="s1">'~&gt; 0.2.1'</span>
</code></pre></div></div>

<h2 id="extconfrb">extconf.rb</h2>

<p>Next add <code class="language-plaintext highlighter-rouge">nmatrix.h</code> header file allowing us to call <code class="language-plaintext highlighter-rouge">nmatrix</code>’s <code class="language-plaintext highlighter-rouge">C/C++ methods</code> from <code class="language-plaintext highlighter-rouge">arrayfire</code>.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">nmatrix_path</span> <span class="o">=</span> <span class="no">Gem</span><span class="o">::</span><span class="no">Specification</span><span class="p">.</span><span class="nf">find_all_by_name</span><span class="p">(</span><span class="s1">'nmatrix'</span><span class="p">).</span><span class="nf">compact</span>
<span class="nb">abort</span> <span class="s2">"Cannot locate NMatrix installation"</span> <span class="k">unless</span> <span class="n">nmatrix_path</span>
<span class="n">nmatrix_header_dir</span> <span class="o">=</span> <span class="no">File</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">nmatrix_path</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nf">require_path</span><span class="p">)</span>

<span class="no">HEADER_DIRS</span> <span class="o">=</span> <span class="p">[</span>
  <span class="s1">'/opt/local/include'</span><span class="p">,</span>
  <span class="s1">'/usr/local/include'</span><span class="p">,</span>
  <span class="no">INCLUDEDIR</span><span class="p">,</span>
  <span class="s1">'/usr/include'</span><span class="p">,</span>
  <span class="n">nmatrix_header_dir</span>
<span class="p">]</span>

<span class="no">LIB_DIRS</span> <span class="o">=</span> <span class="p">[</span>
  <span class="s1">'/opt/local/lib'</span><span class="p">,</span>
  <span class="s1">'/usr/local/lib'</span><span class="p">,</span>
  <span class="no">LIBDIR</span><span class="p">,</span>
  <span class="s1">'/usr/lib'</span><span class="p">,</span>
  <span class="n">nmatrix_header_dir</span>
<span class="p">]</span>

<span class="n">dir_config</span><span class="p">(</span><span class="n">extension_name</span><span class="p">,</span> <span class="no">HEADER_DIRS</span><span class="p">,</span> <span class="no">LIB_DIRS</span><span class="p">)</span>

<span class="n">have_library</span><span class="p">(</span><span class="s1">'af'</span><span class="p">)</span>
</code></pre></div></div>
<h2 id="nmatrix-c-api">NMatrix C++ API</h2>

<p>An NMatrix Ruby C object is denoted by <code class="language-plaintext highlighter-rouge">cNMatrix</code>. Since, <code class="language-plaintext highlighter-rouge">cNMatrix</code> has been initially defined in <code class="language-plaintext highlighter-rouge">nmatrix.h</code> file
we represent it as extern <code class="language-plaintext highlighter-rouge">VALUE</code> and <code class="language-plaintext highlighter-rouge">C++</code> has been specified as we are using the <code class="language-plaintext highlighter-rouge">C++</code>interface.</p>

<p>Next, we create the Ruby bindings.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">extern</span> <span class="s">"C++"</span> <span class="p">{</span>
  <span class="n">VALUE</span> <span class="n">cNMatrix</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">Init_arrayfire</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">ArrayFire</span> <span class="o">=</span> <span class="n">rb_define_module</span><span class="p">(</span><span class="s">"ArrayFire"</span><span class="p">);</span>

  <span class="n">Af_Array</span> <span class="o">=</span> <span class="n">rb_define_class_under</span><span class="p">(</span><span class="n">ArrayFire</span><span class="p">,</span> <span class="s">"Af_Array"</span><span class="p">,</span> <span class="n">rb_cObject</span><span class="p">);</span>
  <span class="n">rb_define_method</span><span class="p">(</span><span class="n">Af_Array</span><span class="p">,</span> <span class="s">"to_nmatrix"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_af_array_to_nmatrix</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>

  <span class="n">cNMatrix</span> <span class="o">=</span> <span class="n">rb_define_class</span><span class="p">(</span><span class="s">"NMatrix"</span><span class="p">,</span> <span class="n">rb_cObject</span><span class="p">);</span>
  <span class="n">rb_define_method</span><span class="p">(</span><span class="n">cNMatrix</span><span class="p">,</span> <span class="s">"to_af_array"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_nmatrix_to_af_array_method</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The C functions have been implemented as the following code snippets.</p>

<p><code class="language-plaintext highlighter-rouge">nm</code> namespace is used to store <code class="language-plaintext highlighter-rouge">NMatrix</code> <code class="language-plaintext highlighter-rouge">types</code> and <code class="language-plaintext highlighter-rouge">structs</code>.</p>

<h1 id="af_array-to-nmatrix">Af_Array to NMatrix</h1>

<p>An <code class="language-plaintext highlighter-rouge">Af_Array#to_nmatrix</code> is called to convert an <code class="language-plaintext highlighter-rouge">Af_Array</code> object to <code class="language-plaintext highlighter-rouge">NMatrix</code> object. The <code class="language-plaintext highlighter-rouge">#to_nmatrix</code> method calls
<code class="language-plaintext highlighter-rouge">arf_af_array_to_nmatrix</code> method which is responsible for calling <code class="language-plaintext highlighter-rouge">NMatrix C++ APIs</code>.
The <code class="language-plaintext highlighter-rouge">rb_nmatrix_dense_create()</code> is NMatrix API to create a dense <code class="language-plaintext highlighter-rouge">NMatrix</code> object. <code class="language-plaintext highlighter-rouge">nm::FLOAT64</code> is the <code class="language-plaintext highlighter-rouge">dtype</code> of NMatrix.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ext/mri/interface/nmatrix.c</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_af_array_to_nmatrix</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">input</span><span class="p">;</span>
  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span>
  <span class="n">dim_t</span> <span class="n">count</span><span class="p">;</span>
  <span class="n">uint</span> <span class="n">ndims</span><span class="p">;</span>
  <span class="n">af_get_numdims</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ndims</span><span class="p">,</span> <span class="n">input</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="n">dim_t</span><span class="o">*</span> <span class="n">dims</span> <span class="o">=</span> <span class="p">(</span><span class="n">dim_t</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">ndims</span> <span class="o">*</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">dim_t</span><span class="p">));</span>

  <span class="n">af_get_dims</span><span class="p">(</span><span class="o">&amp;</span><span class="n">dims</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="o">&amp;</span><span class="n">dims</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="o">&amp;</span><span class="n">dims</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="o">&amp;</span><span class="n">dims</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">input</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="kt">size_t</span><span class="o">*</span> <span class="n">shape</span> <span class="o">=</span> <span class="p">(</span><span class="kt">size_t</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">ndims</span> <span class="o">*</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">size_t</span><span class="p">));;</span>
  <span class="k">for</span> <span class="p">(</span><span class="n">dim_t</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">index</span> <span class="o">&lt;</span> <span class="n">ndims</span><span class="p">;</span> <span class="n">index</span><span class="o">++</span><span class="p">){</span>
    <span class="n">shape</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="kt">size_t</span><span class="p">)(</span><span class="n">dims</span><span class="p">[</span><span class="n">index</span><span class="p">]);</span>
  <span class="p">}</span>

  <span class="n">af_get_elements</span><span class="p">(</span><span class="o">&amp;</span><span class="n">count</span><span class="p">,</span> <span class="n">input</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="kt">double</span><span class="o">*</span> <span class="n">elements</span> <span class="o">=</span> <span class="p">(</span><span class="kt">double</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">count</span> <span class="o">*</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">double</span><span class="p">));</span>
  <span class="n">af_get_data_ptr</span><span class="p">(</span><span class="n">elements</span><span class="p">,</span> <span class="n">input</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="k">return</span> <span class="n">rb_nmatrix_dense_create</span><span class="p">(</span><span class="n">nm</span><span class="o">::</span><span class="n">FLOAT64</span><span class="p">,</span> <span class="n">shape</span><span class="p">,</span> <span class="n">ndims</span><span class="p">,</span> <span class="n">elements</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">count</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<h1 id="nmatrix-to-af_array">NMatrix to Af_Array</h1>

<p>An <code class="language-plaintext highlighter-rouge">NMatrix#to_af_array</code> is called to convert an <code class="language-plaintext highlighter-rouge">NMatrix</code> object to <code class="language-plaintext highlighter-rouge">Af_Array</code> object. The <code class="language-plaintext highlighter-rouge">#to_af_array</code> method calls
<code class="language-plaintext highlighter-rouge">arf_nmatrix_to_af_array_method</code> method which is responsible for calling <code class="language-plaintext highlighter-rouge">NMatrix C++ APIs</code>. <code class="language-plaintext highlighter-rouge">NM_DTYPE()</code> is used  to check
the dtype of an <code class="language-plaintext highlighter-rouge">NMatrix</code> object. Currentlt, only <code class="language-plaintext highlighter-rouge">nm::FLOAT64</code> is supported.</p>

<p>The <code class="language-plaintext highlighter-rouge">arf_nmatrix_to_af_array</code> is called by <code class="language-plaintext highlighter-rouge">arf_nmatrix_to_af_array_method</code> method and an <code class="language-plaintext highlighter-rouge">Af_Array</code> object.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ext/mri/interface/nmatrix.c</span>

<span class="k">extern</span> <span class="n">VALUE</span> <span class="nf">arf_nmatrix_to_af_array_method</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">nmatrix</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">NM_DIM</span><span class="p">(</span><span class="n">nmatrix</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">4</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">rb_raise</span><span class="p">(</span><span class="n">rb_eStandardError</span><span class="p">,</span>
      <span class="s">"NMatrix must not have greater than 4 dimensions."</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">NM_DTYPE</span><span class="p">(</span><span class="n">nmatrix</span><span class="p">)</span> <span class="o">==</span> <span class="n">nm</span><span class="o">::</span><span class="n">FLOAT64</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">Data_Wrap_Struct</span><span class="p">(</span><span class="n">Af_Array</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">arf_free</span><span class="p">,</span> <span class="n">arf_nmatrix_to_af_array</span><span class="p">(</span><span class="n">nmatrix</span><span class="p">));</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="p">{</span>
    <span class="n">rb_raise</span><span class="p">(</span><span class="n">rb_eStandardError</span><span class="p">,</span>
      <span class="s">"NMatrix should be either :complex64, :complex128, :int32 or :float64 type."</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="n">Qnil</span><span class="p">;</span>
<span class="p">}</span>


<span class="n">afstruct</span><span class="o">*</span> <span class="nf">arf_nmatrix_to_af_array</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">nm</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">DENSE_STORAGE</span><span class="o">*</span> <span class="n">nmat</span> <span class="o">=</span> <span class="n">NM_STORAGE_DENSE</span><span class="p">(</span><span class="n">nm</span><span class="p">);</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">output</span> <span class="o">=</span> <span class="n">ALLOC</span><span class="p">(</span><span class="n">afstruct</span><span class="p">);</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">nmat</span><span class="o">-&gt;</span><span class="n">dtype</span> <span class="o">!=</span> <span class="n">nm</span><span class="o">::</span><span class="n">FLOAT64</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">rb_raise</span><span class="p">(</span><span class="n">rb_eStandardError</span><span class="p">,</span> <span class="s">"requires dtype of :float64 to convert to an Af_Array"</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="n">dim_t</span><span class="o">*</span> <span class="n">shape</span> <span class="o">=</span> <span class="p">(</span><span class="n">dim_t</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">nmat</span><span class="o">-&gt;</span><span class="n">dim</span> <span class="o">*</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">dim_t</span><span class="p">));;</span>
  <span class="k">for</span> <span class="p">(</span><span class="kt">size_t</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">index</span> <span class="o">&lt;</span> <span class="n">nmat</span><span class="o">-&gt;</span><span class="n">dim</span><span class="p">;</span> <span class="n">index</span><span class="o">++</span><span class="p">){</span>
    <span class="n">shape</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="kt">size_t</span><span class="p">)(</span><span class="n">nmat</span><span class="o">-&gt;</span><span class="n">shape</span><span class="p">[</span><span class="n">index</span><span class="p">]);</span>
  <span class="p">}</span>

  <span class="n">af_create_array</span><span class="p">(</span><span class="o">&amp;</span><span class="n">output</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">nmat</span><span class="o">-&gt;</span><span class="n">elements</span><span class="p">,</span> <span class="n">nmat</span><span class="o">-&gt;</span><span class="n">dim</span><span class="p">,</span> <span class="n">shape</span><span class="p">,</span> <span class="n">f64</span><span class="p">);</span>

  <span class="k">return</span> <span class="n">output</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Let’s  pry it out.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">rake</span> <span class="n">pry</span>
<span class="n">pry</span> <span class="o">-</span><span class="n">r</span> <span class="s1">'./lib/arrayfire.rb'</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="nb">require</span> <span class="s1">'nmatrix'</span>
<span class="o">=&gt;</span> <span class="kp">true</span>
<span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">a</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span><span class="mi">4</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>  <span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span> <span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">3</span> <span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">9</span><span class="p">]</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">4</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">1.0000</span>    <span class="o">-</span><span class="mf">2.0000</span>     <span class="mf">1.0000</span>     <span class="mf">0.0000</span>
    <span class="mf">2.0000</span>     <span class="mf">2.0000</span>     <span class="mf">4.0000</span>    <span class="o">-</span><span class="mf">3.0000</span>
    <span class="mf">2.0000</span>     <span class="mf">1.0000</span>     <span class="mf">3.0000</span>     <span class="mf">2.0000</span>
    <span class="mf">0.0000</span>     <span class="mf">3.0000</span>     <span class="mf">1.0000</span>     <span class="mf">9.0000</span>

<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x000000019bd6f0&gt;</span>
<span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">b</span> <span class="o">=</span> <span class="n">a</span><span class="p">.</span><span class="nf">to_nmatrix</span>
<span class="o">=&gt;</span>
<span class="p">[</span>
  <span class="p">[</span> <span class="mf">1.0</span><span class="p">,</span>  <span class="mf">2.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">]</span>
  <span class="p">[</span><span class="o">-</span><span class="mf">2.0</span><span class="p">,</span>  <span class="mf">2.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">]</span>
  <span class="p">[</span> <span class="mf">1.0</span><span class="p">,</span>  <span class="mf">4.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">]</span>
  <span class="p">[</span> <span class="mf">0.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">3.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">9.0</span><span class="p">]</span>
<span class="p">]</span>

<span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">c</span> <span class="o">=</span> <span class="n">b</span><span class="p">.</span><span class="nf">to_af_array</span>
<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x00000001a4d340&gt;</span>
<span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">c</span><span class="p">.</span><span class="nf">elements</span>
<span class="o">=&gt;</span> <span class="p">[</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">2.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">4.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">3.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">9.0</span><span class="p">]</span>
<span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Util</span><span class="p">.</span><span class="nf">print_array</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">4</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">1.0000</span>    <span class="o">-</span><span class="mf">2.0000</span>     <span class="mf">1.0000</span>     <span class="mf">0.0000</span>
    <span class="mf">2.0000</span>     <span class="mf">2.0000</span>     <span class="mf">4.0000</span>    <span class="o">-</span><span class="mf">3.0000</span>
    <span class="mf">2.0000</span>     <span class="mf">1.0000</span>     <span class="mf">3.0000</span>     <span class="mf">2.0000</span>
    <span class="mf">0.0000</span>     <span class="mf">3.0000</span>     <span class="mf">1.0000</span>     <span class="mf">9.0000</span>

<span class="o">=&gt;</span> <span class="kp">true</span>
<span class="p">[</span><span class="mi">7</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Util</span><span class="p">.</span><span class="nf">print_array</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">4</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">1.0000</span>    <span class="o">-</span><span class="mf">2.0000</span>     <span class="mf">1.0000</span>     <span class="mf">0.0000</span>
    <span class="mf">2.0000</span>     <span class="mf">2.0000</span>     <span class="mf">4.0000</span>    <span class="o">-</span><span class="mf">3.0000</span>
    <span class="mf">2.0000</span>     <span class="mf">1.0000</span>     <span class="mf">3.0000</span>     <span class="mf">2.0000</span>
    <span class="mf">0.0000</span>     <span class="mf">3.0000</span>     <span class="mf">1.0000</span>     <span class="mf">9.0000</span>

<span class="o">=&gt;</span> <span class="kp">true</span>
<span class="p">[</span><span class="mi">8</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">c</span> <span class="o">=</span> <span class="n">b</span><span class="p">.</span><span class="nf">to_af_array</span>
<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x00000001436088&gt;</span>
</code></pre></div></div>

<p>It works!.</p>

<p>Hence, NMatrix and ArrayFire can be easily interfaced to each other.</p>

<h1 id="benchmarks">Benchmarks</h1>

<p>Now, we can see how using ArrayFire can beneficial over using NMatrix. I benchmarked the matrix multiplication for
two matrices with same elements using <a href="https://github.com/prasunanand/arrayfire-rb-benchmark-suite/blob/master/bin/interface.rb">code</a>.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">shapeArray</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">shape</span><span class="o">|</span>
  <span class="n">elements1</span> <span class="o">=</span> <span class="no">Array</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">*</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="p">{</span> <span class="nb">rand</span><span class="p">(</span><span class="mi">1</span><span class="o">...</span><span class="mi">999999</span><span class="p">)</span> <span class="p">}</span>
  <span class="n">elements2</span> <span class="o">=</span> <span class="no">Array</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">*</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="p">{</span> <span class="nb">rand</span><span class="p">(</span><span class="mi">1</span><span class="o">...</span><span class="mi">999999</span><span class="p">)</span> <span class="p">}</span>
  <span class="n">cpu_matrix1</span> <span class="o">=</span> <span class="no">NMatrix</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">shape</span><span class="p">,</span> <span class="n">elements1</span><span class="p">,</span> <span class="ss">dtype: :float64</span><span class="p">)</span>
  <span class="n">cpu_matrix2</span> <span class="o">=</span> <span class="no">NMatrix</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">shape</span><span class="p">,</span> <span class="n">elements2</span><span class="p">,</span> <span class="ss">dtype: :float64</span><span class="p">)</span>

  <span class="n">gpu_matrix1</span> <span class="o">=</span> <span class="n">cpu_matrix1</span><span class="p">.</span><span class="nf">to_af_array</span>
  <span class="n">gpu_matrix2</span> <span class="o">=</span> <span class="n">cpu_matrix2</span><span class="p">.</span><span class="nf">to_af_array</span>

  <span class="n">iters</span><span class="p">.</span><span class="nf">times</span> <span class="k">do</span>
    <span class="no">ArrayFire</span><span class="o">::</span><span class="no">BLAS</span><span class="p">.</span><span class="nf">matmul</span><span class="p">(</span><span class="n">gpu_matrix1</span><span class="p">,</span> <span class="n">gpu_matrix2</span><span class="p">,</span> <span class="ss">:AF_MAT_NONE</span><span class="p">,</span> <span class="ss">:AF_MAT_NONE</span><span class="p">)</span> <span class="c1"># warmup</span>
  <span class="k">end</span>

  <span class="n">result</span><span class="p">[</span><span class="ss">:mat_mult_cpu</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="p">[</span> <span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">*</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="no">Benchmark</span><span class="p">.</span><span class="nf">measure</span><span class="p">{</span><span class="n">cpu_matrix1</span><span class="p">.</span><span class="nf">dot</span><span class="p">(</span><span class="n">cpu_matrix2</span><span class="p">)}.</span><span class="nf">to_s</span><span class="p">.</span><span class="nf">tr</span><span class="p">(</span><span class="s1">'()'</span><span class="p">,</span> <span class="s1">''</span><span class="p">).</span><span class="nf">split</span><span class="p">(</span><span class="s2">" "</span><span class="p">)[</span><span class="mi">3</span><span class="p">].</span><span class="nf">to_f</span> <span class="p">]</span>
  <span class="n">result</span><span class="p">[</span><span class="ss">:mat_mult_gpu</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="p">[</span> <span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">*</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="no">Benchmark</span><span class="p">.</span><span class="nf">measure</span><span class="p">{</span><span class="no">ArrayFire</span><span class="o">::</span><span class="no">BLAS</span><span class="p">.</span><span class="nf">matmul</span><span class="p">(</span><span class="n">gpu_matrix1</span><span class="p">,</span> <span class="n">gpu_matrix2</span><span class="p">,</span> <span class="ss">:AF_MAT_NONE</span><span class="p">,</span> <span class="ss">:AF_MAT_NONE</span><span class="p">)}.</span><span class="nf">to_s</span><span class="p">.</span><span class="nf">tr</span><span class="p">(</span><span class="s1">'()'</span><span class="p">,</span> <span class="s1">''</span><span class="p">).</span><span class="nf">split</span><span class="p">(</span><span class="s2">" "</span><span class="p">)[</span><span class="mi">3</span><span class="p">].</span><span class="nf">to_f</span> <span class="p">]</span>

<span class="k">end</span>

</code></pre></div></div>

<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>

<script type="text/javascript" src="https://code.highcharts.com/4.2.2/highcharts.js"></script>

<script type="text/javascript" src="https://code.highcharts.com/4.2.2/modules/exporting.js"></script>

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>

<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/4.1.1/normalize.min.css" />

<div ng-app="resultApp">
    <div ng-controller="MainCtrl">
      <div class="block">
        <div id="chart_interface" class="chart"></div>
      </div>
    </div>
  <script type="text/javascript" src="/assets/js/chart.js"></script>
</div>
<p>(Note: The above benchmarks have been done on an AMD FX 8350 octacore processor
and Nvidia GTX 750Ti GPU. CUDA backend of ArrayFire was used with double floating points.)</p>

<p>As the matrix size increases, we can see the difference is huge.</p>

<p>Using ArrayFire can speed up the calculation by 7 e +5 times.</p>

<p>There may be overheads in copying data from CPU to GPU and vice-versa. But overall,
for large matrices(Big Data), we can gain massive speedups when we use the right optimization.
I would be discussing more about such optimizations in another blog post.</p>

<p>However, ArrayFire being significantly faster than NMatrix can easily help Rubyists by adding small
chunk of code and speeding up the critical/slower steps.</p>

<p>Power to Ruby!</p>

<div id="disqus_thread"></div>
<script>
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');

s.src = '//prasunanandblog.disqus.com/embed.js';

s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>]]></content><author><name>Prasun Anand</name></author><category term="arrayfire" /><summary type="html"><![CDATA[ArrayFire-rb has been interfaced to NMatrix so that they can work together. Sometimes, copying data from GPU memory to CPU memory and vice versa can be slower than the computation time. Hence, a lot of developers prefer to use GPU computing for the most time consuming task. The interface between ArrayFire-rb and NMatrix helps in providing maximum freedom to the developers to use the libraries of their choice.]]></summary></entry><entry><title type="html">ArrayFire Ruby Bindings (Part VI : Device and Util)</title><link href="https://prasunanand.github.io/arrayfire/2017/08/22/gsoc17-arrayfire-ruby-bindings-part-6-device.html" rel="alternate" type="text/html" title="ArrayFire Ruby Bindings (Part VI : Device and Util)" /><published>2017-08-22T08:30:00+00:00</published><updated>2017-08-22T08:30:00+00:00</updated><id>https://prasunanand.github.io/arrayfire/2017/08/22/gsoc17-arrayfire-ruby-bindings-part-6-device</id><content type="html" xml:base="https://prasunanand.github.io/arrayfire/2017/08/22/gsoc17-arrayfire-ruby-bindings-part-6-device.html"><![CDATA[<p>ArrayFire has Device and Util class that contains of methods which can be used to manage the CPU and GPU
devices and various utility functions like printing and storing the arrays.
This blog will explain my work regarding the bindings I have created and how to use them.</p>

<h1 id="device">Device</h1>

<p><code class="language-plaintext highlighter-rouge">Device</code> class contains of singleton methods like <code class="language-plaintext highlighter-rouge">info</code>, <code class="language-plaintext highlighter-rouge">device_gc</code>, <code class="language-plaintext highlighter-rouge">lock_device_ptr</code> that can
be used to get info about the GPU devices used for calculation, explicitly call the garbage collector
and locking the pointers on GPU device.</p>

<p>The implementation is as follows:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">Init_arrayfire</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">ArrayFire</span> <span class="o">=</span> <span class="n">rb_define_module</span><span class="p">(</span><span class="s">"ArrayFire"</span><span class="p">);</span>

  <span class="n">Device</span> <span class="o">=</span> <span class="n">rb_define_class_under</span><span class="p">(</span><span class="n">ArrayFire</span><span class="p">,</span> <span class="s">"Device"</span><span class="p">,</span> <span class="n">rb_cObject</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"info"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_info</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"init"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_init2</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"info_string"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_info_string</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"device_info"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_device_info</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"get_device_count"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_get_device_count</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"get_dbl_support"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_get_dbl_support</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"set_device"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_set_device</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"get_device"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_get_device</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"sync"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_sync</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"device_mem_info"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_device_mem_info</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"print_mem_info"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_print_mem_info</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"device_gc"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_device_gc</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"set_mem_step_size"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_set_mem_step_size</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"get_mem_step_size"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_get_mem_step_size</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"lock_device_ptr"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_lock_device_ptr</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"unlock_device_ptr"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_unlock_device_ptr</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"lock_array"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_lock_array</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"unlock_array"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_unlock_array</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"is_locked_array"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_is_locked_array</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Device</span><span class="p">,</span> <span class="s">"get_device_ptr"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_get_device_ptr</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The implementation of device_info is interesting as it has 4 return values in the form of strings.
<code class="language-plaintext highlighter-rouge">ArrayFire::Device.device_info</code> passes the variables to be returned to  <code class="language-plaintext highlighter-rouge">ArrayFire::Device.device_info_func</code>
which modifies the contents of the variables passed.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nn">ArrayFire</span>
  <span class="k">class</span> <span class="nc">Device</span>
    <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">device_info</span>
      <span class="n">d_name</span>     <span class="o">=</span> <span class="s2">""</span>
      <span class="n">d_platform</span> <span class="o">=</span> <span class="s2">""</span>
      <span class="n">d_toolkit</span>  <span class="o">=</span> <span class="s2">""</span>
      <span class="n">d_compute</span>  <span class="o">=</span> <span class="s2">""</span>
      <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Device</span><span class="p">.</span><span class="nf">device_info_func</span><span class="p">(</span><span class="n">d_name</span><span class="p">,</span> <span class="n">d_platform</span><span class="p">,</span> <span class="n">d_toolkit</span><span class="p">,</span> <span class="n">d_compute</span><span class="p">);</span>
      <span class="k">return</span> <span class="n">d_name</span><span class="p">,</span> <span class="n">d_platform</span><span class="p">,</span> <span class="n">d_toolkit</span><span class="p">,</span> <span class="n">d_compute</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>The point to note here is that <code class="language-plaintext highlighter-rouge">ArrayFire::Device.device_info</code> uses <code class="language-plaintext highlighter-rouge">rb_str_cat2()</code> to concatenate the <code class="language-plaintext highlighter-rouge">char*</code>
to the <code class="language-plaintext highlighter-rouge">VALUE</code> containing empty string.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_device_info</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">name_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">platform_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">toolkit_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">compute_val</span><span class="p">){</span>
  <span class="kt">char</span><span class="o">*</span> <span class="n">d_name</span>     <span class="o">=</span> <span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">char</span><span class="p">)</span> <span class="o">*</span> <span class="mi">64</span><span class="p">);</span>
  <span class="kt">char</span><span class="o">*</span> <span class="n">d_platform</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">char</span><span class="p">)</span> <span class="o">*</span> <span class="mi">10</span><span class="p">);</span>
  <span class="kt">char</span><span class="o">*</span> <span class="n">d_toolkit</span>  <span class="o">=</span> <span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">char</span><span class="p">)</span> <span class="o">*</span> <span class="mi">64</span><span class="p">);</span>
  <span class="kt">char</span><span class="o">*</span> <span class="n">d_compute</span>  <span class="o">=</span> <span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">char</span><span class="p">)</span> <span class="o">*</span> <span class="mi">10</span><span class="p">);</span>

  <span class="n">af_device_info</span><span class="p">(</span><span class="n">d_name</span><span class="p">,</span> <span class="n">d_platform</span><span class="p">,</span> <span class="n">d_toolkit</span><span class="p">,</span> <span class="n">d_compute</span><span class="p">);</span>

  <span class="n">rb_str_cat2</span><span class="p">(</span><span class="n">name_val</span><span class="p">,</span>     <span class="n">d_name</span><span class="p">);</span>
  <span class="n">rb_str_cat2</span><span class="p">(</span><span class="n">platform_val</span><span class="p">,</span> <span class="n">d_platform</span><span class="p">);</span>
  <span class="n">rb_str_cat2</span><span class="p">(</span><span class="n">toolkit_val</span><span class="p">,</span>  <span class="n">d_toolkit</span><span class="p">);</span>
  <span class="n">rb_str_cat2</span><span class="p">(</span><span class="n">compute_val</span><span class="p">,</span>  <span class="n">d_compute</span><span class="p">);</span>

  <span class="k">return</span> <span class="n">Qnil</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_device_mem_info</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">){</span>
  <span class="kt">size_t</span> <span class="n">alloc_bytes</span><span class="p">,</span> <span class="n">alloc_buffers</span><span class="p">,</span> <span class="n">lock_bytes</span><span class="p">,</span> <span class="n">lock_buffers</span><span class="p">;</span>
  <span class="n">af_device_mem_info</span><span class="p">(</span> <span class="o">&amp;</span><span class="n">alloc_bytes</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">alloc_buffers</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">lock_bytes</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">lock_buffers</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"Allocated Bytes: %d</span><span class="se">\n</span><span class="s">Allocated buffers: %d</span><span class="se">\n</span><span class="s">Lock Bytes: %d</span><span class="se">\n</span><span class="s">Lock Buffers: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span>
          <span class="n">alloc_bytes</span><span class="p">,</span> <span class="n">alloc_buffers</span><span class="p">,</span> <span class="n">lock_bytes</span><span class="p">,</span> <span class="n">lock_buffers</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">Qnil</span><span class="p">;</span>
<span class="p">}</span>

</code></pre></div></div>

<p>Running <code class="language-plaintext highlighter-rouge">pry</code> to check the bindings:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">rake</span> <span class="n">pry</span>
<span class="n">pry</span> <span class="o">-</span><span class="n">r</span> <span class="s1">'./lib/arrayfire.rb'</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Device</span><span class="p">.</span><span class="nf">info</span>
<span class="no">ArrayFire</span> <span class="n">v3</span><span class="o">.</span><span class="mf">4.0</span> <span class="p">(</span><span class="no">CUDA</span><span class="p">,</span> <span class="mi">64</span><span class="o">-</span><span class="n">bit</span> <span class="no">Linux</span><span class="p">,</span> <span class="n">build</span> <span class="mi">75</span><span class="n">cad40</span><span class="p">)</span>
<span class="no">Platform</span><span class="p">:</span> <span class="no">CUDA</span> <span class="no">Toolkit</span> <span class="mf">7.5</span><span class="p">,</span> <span class="no">Driver</span><span class="p">:</span> <span class="mf">375.66</span>
<span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="no">GeForce</span> <span class="no">GTX</span> <span class="mi">750</span> <span class="no">Ti</span><span class="p">,</span> <span class="mi">4042</span> <span class="no">MB</span><span class="p">,</span> <span class="no">CUDA</span> <span class="no">Compute</span> <span class="mf">5.0</span>
<span class="o">=&gt;</span> <span class="kp">nil</span>
<span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Device</span><span class="p">.</span><span class="nf">device_info</span>
<span class="o">=&gt;</span> <span class="p">[</span><span class="s2">"GeForce_GTX_750_Ti"</span><span class="p">,</span> <span class="s2">"CUDA"</span><span class="p">,</span> <span class="s2">"v7.5"</span><span class="p">,</span> <span class="s2">"5.0"</span><span class="p">]</span>
<span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Device</span><span class="p">.</span><span class="nf">get_device_count</span>
<span class="o">=&gt;</span> <span class="mi">1</span>
<span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Device</span><span class="p">.</span><span class="nf">get_dbl_support</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="kp">true</span>
<span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Device</span><span class="p">.</span><span class="nf">device_mem_info</span>
<span class="no">Allocated</span> <span class="no">Bytes</span><span class="p">:</span> <span class="mi">0</span>
<span class="no">Allocated</span> <span class="ss">buffers: </span><span class="mi">0</span>
<span class="no">Lock</span> <span class="no">Bytes</span><span class="p">:</span> <span class="mi">0</span>
<span class="no">Lock</span> <span class="no">Buffers</span><span class="p">:</span> <span class="mi">0</span>
<span class="o">=&gt;</span> <span class="kp">nil</span>
<span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">arr</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span><span class="mi">4</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span> <span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">3</span> <span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">9</span><span class="p">]</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">4</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">1.0000</span>    <span class="o">-</span><span class="mf">2.0000</span>     <span class="mf">1.0000</span>     <span class="mf">0.0000</span>
    <span class="mf">2.0000</span>     <span class="mf">2.0000</span>     <span class="mf">4.0000</span>    <span class="o">-</span><span class="mf">3.0000</span>
    <span class="mf">2.0000</span>     <span class="mf">1.0000</span>     <span class="mf">3.0000</span>     <span class="mf">2.0000</span>
    <span class="mf">0.0000</span>     <span class="mf">3.0000</span>     <span class="mf">1.0000</span>     <span class="mf">9.0000</span>

<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x000000023800c0&gt;</span>
<span class="p">[</span><span class="mi">7</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Device</span><span class="p">.</span><span class="nf">print_mem_info</span><span class="p">(</span><span class="s2">"mem info"</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">mem</span> <span class="n">info</span>
<span class="o">---------------------------------------------------------</span>
<span class="o">|</span>     <span class="no">POINTER</span>      <span class="o">|</span>    <span class="no">SIZE</span>    <span class="o">|</span>  <span class="no">AF</span> <span class="no">LOCK</span>  <span class="o">|</span> <span class="no">USER</span> <span class="no">LOCK</span> <span class="o">|</span>
<span class="o">---------------------------------------------------------</span>
<span class="o">|</span>     <span class="mh">0x702f80000</span>  <span class="o">|</span>       <span class="mi">1</span> <span class="no">KB</span> <span class="o">|</span>       <span class="no">Yes</span> <span class="o">|</span>        <span class="no">No</span> <span class="o">|</span>
<span class="o">|</span>     <span class="mh">0x702f80400</span>  <span class="o">|</span>       <span class="mi">1</span> <span class="no">KB</span> <span class="o">|</span>        <span class="no">No</span> <span class="o">|</span>        <span class="no">No</span> <span class="o">|</span>
<span class="o">---------------------------------------------------------</span>
<span class="o">=&gt;</span> <span class="kp">nil</span>
<span class="p">[</span><span class="mi">8</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Device</span><span class="p">.</span><span class="nf">device_mem_info</span>
<span class="no">Allocated</span> <span class="no">Bytes</span><span class="p">:</span> <span class="mi">2048</span>
<span class="no">Allocated</span> <span class="ss">buffers: </span><span class="mi">2</span>
<span class="no">Lock</span> <span class="no">Bytes</span><span class="p">:</span> <span class="mi">1024</span>
<span class="no">Lock</span> <span class="no">Buffers</span><span class="p">:</span> <span class="mi">1</span>
<span class="o">=&gt;</span> <span class="kp">nil</span>
<span class="p">[</span><span class="mi">9</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Device</span><span class="p">.</span><span class="nf">get_mem_step_size</span>
<span class="o">=&gt;</span> <span class="mi">1024</span>
<span class="p">[</span><span class="mi">10</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Device</span><span class="p">.</span><span class="nf">is_locked_array</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="kp">false</span>
<span class="p">[</span><span class="mi">11</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Device</span><span class="p">.</span><span class="nf">lock_array</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="kp">true</span>
<span class="p">[</span><span class="mi">12</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Device</span><span class="p">.</span><span class="nf">is_locked_array</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="kp">true</span>
</code></pre></div></div>

<h1 id="util">Util</h1>

<p>Util class contains of methods responsible for printing an Af_Array, saving it in a file
or converting it to string and other utility methods.</p>

<p>The implementation is as follows:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">Init_arrayfire</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">ArrayFire</span> <span class="o">=</span> <span class="n">rb_define_module</span><span class="p">(</span><span class="s">"ArrayFire"</span><span class="p">);</span>

  <span class="n">Util</span> <span class="o">=</span> <span class="n">rb_define_class_under</span><span class="p">(</span><span class="n">ArrayFire</span><span class="p">,</span> <span class="s">"Util"</span><span class="p">,</span> <span class="n">rb_cObject</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Util</span><span class="p">,</span> <span class="s">"print_array"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_print_array</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Util</span><span class="p">,</span> <span class="s">"print_array_gen"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_print_array_gen</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Util</span><span class="p">,</span> <span class="s">"save_array"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_save_array</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Util</span><span class="p">,</span> <span class="s">"read_array_index"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_read_array_index</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Util</span><span class="p">,</span> <span class="s">"read_array_key"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_read_array_key</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Util</span><span class="p">,</span> <span class="s">"read_array_key_check"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_read_array_key_check</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Util</span><span class="p">,</span> <span class="s">"array_to_string"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_array_to_string</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Util</span><span class="p">,</span> <span class="s">"get_version"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_get_version</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Util</span><span class="p">,</span> <span class="s">"get_revision"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_get_revision</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Util</span><span class="p">,</span> <span class="s">"get_size_of"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_get_size_of</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>

</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">af_array_to_string</code> API has also been used to implement <code class="language-plaintext highlighter-rouge">ArrayFire::Af_Array#to_s</code>.</p>

<p>The implementation of <code class="language-plaintext highlighter-rouge">arf_get_version</code> is interesting as it returns a hash value that represents
the version of <code class="language-plaintext highlighter-rouge">ArrayFire</code> C library installed using the keys as <code class="language-plaintext highlighter-rouge">major</code>, <code class="language-plaintext highlighter-rouge">minor</code> and <code class="language-plaintext highlighter-rouge">patch</code>.</p>

<p><code class="language-plaintext highlighter-rouge">rb_hash_new</code> and <code class="language-plaintext highlighter-rouge">rb_hash_aset</code> has been used to create a hash.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_print_array</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">input_val</span><span class="p">){</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">input</span><span class="p">;</span>

  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">input_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span>

  <span class="n">af_print_array</span><span class="p">(</span><span class="n">input</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">Qtrue</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_save_array</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">key_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">array_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">fn_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">append</span><span class="p">){</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">input</span><span class="p">;</span>

  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">array_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span>
  <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">key</span> <span class="o">=</span> <span class="n">StringValueCStr</span><span class="p">(</span><span class="n">key_val</span><span class="p">);</span>
  <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">filename</span> <span class="o">=</span> <span class="n">StringValueCStr</span><span class="p">(</span><span class="n">fn_val</span><span class="p">);</span>
  <span class="kt">int</span> <span class="n">index</span><span class="p">;</span>
  <span class="n">af_save_array</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">index</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">input</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="n">RTEST</span><span class="p">(</span><span class="n">append</span><span class="p">));</span>
  <span class="k">return</span> <span class="n">INT2NUM</span><span class="p">(</span><span class="n">index</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_array_to_string</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">exp_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">array_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">precision</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">transpose</span><span class="p">){</span>
  <span class="kt">char</span><span class="o">*</span> <span class="n">output</span><span class="p">;</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">input</span><span class="p">;</span>

  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">array_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span>
  <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">exp</span> <span class="o">=</span> <span class="n">StringValueCStr</span><span class="p">(</span><span class="n">exp_val</span><span class="p">);</span>
  <span class="n">af_array_to_string</span><span class="p">(</span><span class="o">&amp;</span><span class="n">output</span><span class="p">,</span> <span class="n">exp</span><span class="p">,</span> <span class="n">input</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">NUM2INT</span><span class="p">(</span><span class="n">precision</span><span class="p">),</span> <span class="n">RTEST</span><span class="p">(</span><span class="n">transpose</span><span class="p">));</span>

  <span class="k">return</span> <span class="n">rb_str_new_cstr</span><span class="p">(</span><span class="n">output</span><span class="p">);</span>
<span class="p">}</span>


<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_get_version</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">){</span>
  <span class="kt">int</span> <span class="n">major</span><span class="p">,</span> <span class="n">minor</span><span class="p">,</span> <span class="n">patch</span><span class="p">;</span>
  <span class="n">af_get_version</span><span class="p">(</span><span class="o">&amp;</span><span class="n">major</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">minor</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">patch</span><span class="p">);</span>

  <span class="n">VALUE</span> <span class="n">hash</span> <span class="o">=</span> <span class="n">rb_hash_new</span><span class="p">();</span>
  <span class="n">rb_hash_aset</span><span class="p">(</span><span class="n">hash</span><span class="p">,</span> <span class="n">rb_str_new_cstr</span><span class="p">(</span><span class="s">"major"</span><span class="p">),</span> <span class="n">INT2NUM</span><span class="p">(</span><span class="n">major</span><span class="p">));</span>
  <span class="n">rb_hash_aset</span><span class="p">(</span><span class="n">hash</span><span class="p">,</span> <span class="n">rb_str_new_cstr</span><span class="p">(</span><span class="s">"minor"</span><span class="p">),</span> <span class="n">INT2NUM</span><span class="p">(</span><span class="n">minor</span><span class="p">));</span>
  <span class="n">rb_hash_aset</span><span class="p">(</span><span class="n">hash</span><span class="p">,</span> <span class="n">rb_str_new_cstr</span><span class="p">(</span><span class="s">"patch"</span><span class="p">),</span> <span class="n">INT2NUM</span><span class="p">(</span><span class="n">patch</span><span class="p">));</span>
  <span class="k">return</span> <span class="n">hash</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Lets use pry to check the bindings:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">rake</span> <span class="n">pry</span>
<span class="n">pry</span> <span class="o">-</span><span class="n">r</span> <span class="s1">'./lib/arrayfire.rb'</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">arr</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span><span class="mi">4</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>  <span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span> <span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">3</span> <span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">9</span><span class="p">]</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">4</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">1.0000</span>    <span class="o">-</span><span class="mf">2.0000</span>     <span class="mf">1.0000</span>     <span class="mf">0.0000</span>
    <span class="mf">2.0000</span>     <span class="mf">2.0000</span>     <span class="mf">4.0000</span>    <span class="o">-</span><span class="mf">3.0000</span>
    <span class="mf">2.0000</span>     <span class="mf">1.0000</span>     <span class="mf">3.0000</span>     <span class="mf">2.0000</span>
    <span class="mf">0.0000</span>     <span class="mf">3.0000</span>     <span class="mf">1.0000</span>     <span class="mf">9.0000</span>

<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x000000026bde18&gt;</span>
<span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Util</span><span class="p">.</span><span class="nf">print_array</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">4</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">1.0000</span>    <span class="o">-</span><span class="mf">2.0000</span>     <span class="mf">1.0000</span>     <span class="mf">0.0000</span>
    <span class="mf">2.0000</span>     <span class="mf">2.0000</span>     <span class="mf">4.0000</span>    <span class="o">-</span><span class="mf">3.0000</span>
    <span class="mf">2.0000</span>     <span class="mf">1.0000</span>     <span class="mf">3.0000</span>     <span class="mf">2.0000</span>
    <span class="mf">0.0000</span>     <span class="mf">3.0000</span>     <span class="mf">1.0000</span>     <span class="mf">9.0000</span>

<span class="o">=&gt;</span> <span class="kp">true</span>
<span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Util</span><span class="p">.</span><span class="nf">array_to_string</span><span class="p">(</span><span class="s2">"GPU Array"</span><span class="p">,</span> <span class="n">arr</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="kp">false</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="s2">"GPU Array</span><span class="se">\n</span><span class="s2">[4 4 1 1]</span><span class="se">\n</span><span class="s2">    1.00000     2.00000     2.00000     0.00000 </span><span class="se">\n</span><span class="s2">   -2.00000     2.00000     1.00000     3.00000 </span><span class="se">\n</span><span class="s2">    1.00000     4.00000     3.00000     1.00000 </span><span class="se">\n</span><span class="s2">    0.00000    -3.00000     2.00000     9.00000 </span><span class="se">\n\n</span><span class="s2">"</span>
<span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="nb">puts</span> <span class="n">x</span>
<span class="no">GPU</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">4</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">1.00000</span>     <span class="mf">2.00000</span>     <span class="mf">2.00000</span>     <span class="mf">0.00000</span>
   <span class="o">-</span><span class="mf">2.00000</span>     <span class="mf">2.00000</span>     <span class="mf">1.00000</span>     <span class="mf">3.00000</span>
    <span class="mf">1.00000</span>     <span class="mf">4.00000</span>     <span class="mf">3.00000</span>     <span class="mf">1.00000</span>
    <span class="mf">0.00000</span>    <span class="o">-</span><span class="mf">3.00000</span>     <span class="mf">2.00000</span>     <span class="mf">9.00000</span>

<span class="o">=&gt;</span> <span class="kp">nil</span>
<span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Util</span><span class="p">.</span><span class="nf">get_version</span>
<span class="o">=&gt;</span> <span class="p">{</span><span class="s2">"major"</span><span class="o">=&gt;</span><span class="mi">3</span><span class="p">,</span> <span class="s2">"minor"</span><span class="o">=&gt;</span><span class="mi">4</span><span class="p">,</span> <span class="s2">"patch"</span><span class="o">=&gt;</span><span class="mi">0</span><span class="p">}</span>
<span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Util</span><span class="p">.</span><span class="nf">get_revision</span>
<span class="o">=&gt;</span> <span class="s2">"75cad40"</span>
<span class="p">[</span><span class="mi">7</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Util</span><span class="p">.</span><span class="nf">get_size_of</span><span class="p">(</span><span class="ss">:f64</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="mi">8</span>
</code></pre></div></div>

<p>The bindings work!.</p>

<h1 id="conclusion">Conclusion</h1>

<p>We can easily manage the available GPU devices and manage the memory. Also, we can save the <code class="language-plaintext highlighter-rouge">Af_Array</code>
output to a file among other utilities.</p>

<p>In the next blog post, I will explain about using multiple backends using <code class="language-plaintext highlighter-rouge">ArrayFire</code> , i.e. OpenCL, CUDA
and even use CPUs.</p>

<div id="disqus_thread"></div>
<script>
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');

s.src = '//prasunanandblog.disqus.com/embed.js';

s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>]]></content><author><name>Prasun Anand</name></author><category term="arrayfire" /><summary type="html"><![CDATA[ArrayFire has Device and Util class that contains of methods which can be used to manage the CPU and GPU devices and various utility functions like printing and storing the arrays. This blog will explain my work regarding the bindings I have created and how to use them.]]></summary></entry><entry><title type="html">ArrayFire Ruby Bindings (Part V : Statistics and Random Engine routines)</title><link href="https://prasunanand.github.io/arrayfire/2017/08/17/gsoc17-arrayfire-ruby-bindings-part-4-statistics-and-random-engine.html" rel="alternate" type="text/html" title="ArrayFire Ruby Bindings (Part V : Statistics and Random Engine routines)" /><published>2017-08-17T08:30:00+00:00</published><updated>2017-08-17T08:30:00+00:00</updated><id>https://prasunanand.github.io/arrayfire/2017/08/17/gsoc17-arrayfire-ruby-bindings-part-4-statistics-and-random-engine</id><content type="html" xml:base="https://prasunanand.github.io/arrayfire/2017/08/17/gsoc17-arrayfire-ruby-bindings-part-4-statistics-and-random-engine.html"><![CDATA[<p>This post explains about the <code class="language-plaintext highlighter-rouge">Statistics</code> and <code class="language-plaintext highlighter-rouge">Random</code> class of <code class="language-plaintext highlighter-rouge">arrayfire</code> gem.
<code class="language-plaintext highlighter-rouge">ArrayFire::Statistics</code> class consists of  methods that can be used to operate on <code class="language-plaintext highlighter-rouge">Af_Array</code> for statistical analysis. <code class="language-plaintext highlighter-rouge">ArrayFire::Random</code> class contains of methods to generate Random numbers and array of Random numbers
on the GPU.</p>

<h1 id="statistics-class">Statistics Class</h1>

<p>The <code class="language-plaintext highlighter-rouge">Statistics</code> class contains of singleton methods like <code class="language-plaintext highlighter-rouge">mean</code>, <code class="language-plaintext highlighter-rouge">var</code>, <code class="language-plaintext highlighter-rouge">median</code>, <code class="language-plaintext highlighter-rouge">stddev</code>, etc.
Let us take a look at the implementation.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">Init_arrayfire</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">ArrayFire</span> <span class="o">=</span> <span class="n">rb_define_module</span><span class="p">(</span><span class="s">"ArrayFire"</span><span class="p">);</span>

  <span class="n">Statistics</span> <span class="o">=</span> <span class="n">rb_define_class_under</span><span class="p">(</span><span class="n">ArrayFire</span><span class="p">,</span> <span class="s">"Statistics"</span><span class="p">,</span> <span class="n">rb_cObject</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Statistics</span><span class="p">,</span> <span class="s">"mean"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_mean</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Statistics</span><span class="p">,</span> <span class="s">"mean_weighted"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_mean_weighted</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Statistics</span><span class="p">,</span> <span class="s">"var"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_var</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Statistics</span><span class="p">,</span> <span class="s">"var_weighted"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_var_weighted</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Statistics</span><span class="p">,</span> <span class="s">"stdev"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_stdev</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Statistics</span><span class="p">,</span> <span class="s">"cov"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_cov</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Statistics</span><span class="p">,</span> <span class="s">"median"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_median</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Statistics</span><span class="p">,</span> <span class="s">"mean_all"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_mean_all</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Statistics</span><span class="p">,</span> <span class="s">"mean_all_weighted"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_mean_all_weighted</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Statistics</span><span class="p">,</span> <span class="s">"var_all"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_var_all</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Statistics</span><span class="p">,</span> <span class="s">"var_all_weighted"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_var_all_weighted</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Statistics</span><span class="p">,</span> <span class="s">"stdev_all"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_stdev_all</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Statistics</span><span class="p">,</span> <span class="s">"median_all"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_median_all</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Statistics</span><span class="p">,</span> <span class="s">"corrcoef"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_corrcoef</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>

<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">ArrayFire</code> provides four different methods to calculate the means namely,
<code class="language-plaintext highlighter-rouge">mean</code>, <code class="language-plaintext highlighter-rouge">mean_weighted</code>, <code class="language-plaintext highlighter-rouge">mean_all</code>, <code class="language-plaintext highlighter-rouge">mean_all_weighted</code>. The implementation
is given below.</p>

<p><code class="language-plaintext highlighter-rouge">mean</code> and <code class="language-plaintext highlighter-rouge">mean_weighted</code> calculate the mean and weighted mean along the dimnension
specified. However, <code class="language-plaintext highlighter-rouge">mean_all</code> and <code class="language-plaintext highlighter-rouge">mean_weighted_all</code> calculate the mean and weighted
mean over all the elements in an array.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_mean</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">array_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">dim_val</span><span class="p">){</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">input</span><span class="p">;</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">output</span> <span class="o">=</span> <span class="n">ALLOC</span><span class="p">(</span><span class="n">afstruct</span><span class="p">);</span>

  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">array_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span>

  <span class="n">af_mean</span><span class="p">(</span><span class="o">&amp;</span><span class="n">output</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">input</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">NUM2UINT</span><span class="p">(</span><span class="n">dim_val</span><span class="p">));</span>
  <span class="n">af_print_array</span><span class="p">(</span><span class="n">output</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="k">return</span> <span class="n">Data_Wrap_Struct</span><span class="p">(</span><span class="n">Af_Array</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">arf_free</span><span class="p">,</span> <span class="n">output</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_mean_weighted</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">array_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">weighted_array_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">dim_val</span><span class="p">){</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">input</span><span class="p">;</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">weighted_array</span><span class="p">;</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">output</span> <span class="o">=</span> <span class="n">ALLOC</span><span class="p">(</span><span class="n">afstruct</span><span class="p">);</span>

  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">array_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span>
  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">weighted_array_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">weighted_array</span><span class="p">);</span>

  <span class="n">af_mean_weighted</span><span class="p">(</span><span class="o">&amp;</span><span class="n">output</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">input</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">weighted_array</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">NUM2UINT</span><span class="p">(</span><span class="n">dim_val</span><span class="p">));</span>
  <span class="n">af_print_array</span><span class="p">(</span><span class="n">output</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="k">return</span> <span class="n">Data_Wrap_Struct</span><span class="p">(</span><span class="n">Af_Array</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">arf_free</span><span class="p">,</span> <span class="n">output</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_mean_all</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">array_val</span><span class="p">){</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">input</span><span class="p">;</span>
  <span class="kt">double</span> <span class="n">real_part</span><span class="p">,</span> <span class="n">imag_part</span><span class="p">;</span>

  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">array_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span>

  <span class="n">af_mean_all</span><span class="p">(</span><span class="o">&amp;</span><span class="n">real_part</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">imag_part</span><span class="p">,</span> <span class="n">input</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="k">return</span> <span class="n">DBL2NUM</span><span class="p">(</span><span class="n">real_part</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_mean_all_weighted</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">array_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">weighted_array_val</span><span class="p">){</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">input</span><span class="p">;</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">weighted_array</span><span class="p">;</span>
  <span class="kt">double</span> <span class="n">real_part</span><span class="p">,</span> <span class="n">imag_part</span><span class="p">;</span>

  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">array_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span>
  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">weighted_array_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">weighted_array</span><span class="p">);</span>

  <span class="n">af_mean_all_weighted</span><span class="p">(</span><span class="o">&amp;</span><span class="n">real_part</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">imag_part</span><span class="p">,</span> <span class="n">input</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">weighted_array</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="k">return</span> <span class="n">DBL2NUM</span><span class="p">(</span><span class="n">real_part</span><span class="p">);</span>
<span class="p">}</span>

</code></pre></div></div>
<p>I check the bindings using <code class="language-plaintext highlighter-rouge">pry</code>.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">rake</span> <span class="n">pry</span>
<span class="n">pry</span> <span class="o">-</span><span class="n">r</span> <span class="s1">'./lib/arrayfire.rb'</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">arr</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Random</span><span class="p">.</span><span class="nf">randu</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">])</span><span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x0000000308fb08&gt;</span>
<span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Util</span><span class="p">.</span><span class="nf">print_array</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span><span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">4</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">0.3990</span>     <span class="mf">0.7353</span>     <span class="mf">0.9455</span>     <span class="mf">0.7089</span>
    <span class="mf">0.6720</span>     <span class="mf">0.5160</span>     <span class="mf">0.1587</span>     <span class="mf">0.9434</span>
    <span class="mf">0.5339</span>     <span class="mf">0.3932</span>     <span class="mf">0.8831</span>     <span class="mf">0.1227</span>
    <span class="mf">0.1386</span>     <span class="mf">0.2706</span>     <span class="mf">0.0621</span>     <span class="mf">0.9107</span>

<span class="o">=&gt;</span> <span class="kp">true</span>
<span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">weighted_array</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span><span class="mi">4</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>  <span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span> <span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">3</span> <span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">9</span><span class="p">]</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">4</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">1.0000</span>    <span class="o">-</span><span class="mf">2.0000</span>     <span class="mf">1.0000</span>     <span class="mf">0.0000</span>
    <span class="mf">2.0000</span>     <span class="mf">2.0000</span>     <span class="mf">4.0000</span>    <span class="o">-</span><span class="mf">3.0000</span>
    <span class="mf">2.0000</span>     <span class="mf">1.0000</span>     <span class="mf">3.0000</span>     <span class="mf">2.0000</span>
    <span class="mf">0.0000</span>     <span class="mf">3.0000</span>     <span class="mf">1.0000</span>     <span class="mf">9.0000</span>

<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x0000000316c008&gt;</span>
<span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">mean</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Statistics</span><span class="p">.</span><span class="nf">mean</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">0.6972</span>
    <span class="mf">0.5725</span>
    <span class="mf">0.4832</span>
    <span class="mf">0.3455</span>

<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x00000003212138&gt;</span>
<span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">mean_weighted</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Statistics</span><span class="p">.</span><span class="nf">mean_weighted</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">weighted_array</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">4</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">0.3990</span>     <span class="mf">0.7353</span>     <span class="mf">0.9455</span>        <span class="n">nan</span>
    <span class="mf">0.6720</span>     <span class="mf">0.5160</span>     <span class="mf">0.1587</span>     <span class="mf">0.9434</span>
    <span class="mf">0.5339</span>     <span class="mf">0.3932</span>     <span class="mf">0.8831</span>     <span class="mf">0.1227</span>
       <span class="n">nan</span>     <span class="mf">0.2706</span>     <span class="mf">0.0621</span>     <span class="mf">0.9107</span>

<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x000000031d2588&gt;</span>
<span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">mean_all</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Statistics</span><span class="p">.</span><span class="nf">mean_all</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span><span class="o">=&gt;</span> <span class="mf">0.5246008634567261</span>
<span class="p">[</span><span class="mi">7</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">mean_all_weighted</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Statistics</span><span class="p">.</span><span class="nf">mean_all_weighted</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">weighted_array</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="mf">0.5184718370437622</span>
</code></pre></div></div>

<h1 id="random-class">Random Class</h1>

<p>ArrayFire supports three types of random engines: <code class="language-plaintext highlighter-rouge">:AF_RANDOM_ENGINE_PHILOX_4X32_10</code>,
<code class="language-plaintext highlighter-rouge">:AF_RANDOM_ENGINE_THREEFRY_2X32_16</code> and <code class="language-plaintext highlighter-rouge">:AF_RANDOM_ENGINE_MERSENNE_GP11213</code> which can be
passed as a type.</p>

<p>The default randon engine is <code class="language-plaintext highlighter-rouge">:AF_RANDOM_ENGINE_PHILOX_4X32_10</code>. Random class helps  in creating
an engine by specifying the type and seed. A programmer can set the seed on the fly and also create
arrays with randomly generated values.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">Init_arrayfire</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">ArrayFire</span> <span class="o">=</span> <span class="n">rb_define_module</span><span class="p">(</span><span class="s">"ArrayFire"</span><span class="p">);</span>

  <span class="n">Random</span> <span class="o">=</span> <span class="n">rb_define_class_under</span><span class="p">(</span><span class="n">ArrayFire</span><span class="p">,</span> <span class="s">"Random"</span><span class="p">,</span> <span class="n">rb_cObject</span><span class="p">);</span>
  <span class="n">rb_define_alloc_func</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="n">arf_engine_alloc</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="s">"create_random_engine"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_create_random_engine</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="s">"retain_random_engine"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_retain_random_engine</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="s">"random_engine_set_type"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_random_engine_set_type</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="s">"random_engine_get_type"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_random_engine_get_type</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="s">"random_uniform"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_random_uniform</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="s">"random_normal"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_random_normal</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="s">"random_engine_set_seed"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_random_engine_set_seed</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="s">"get_default_random_engine"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_get_default_random_engine</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="s">"set_default_random_engine_type"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_set_default_random_engine_type</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="s">"random_engine_get_seed"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_random_engine_get_seed</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="s">"release_random_engine"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_release_random_engine</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="s">"randu"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_randu</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="s">"randn"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_randn</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="s">"set_seed"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_set_seed</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="s">"get_seed"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_get_seed</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>A Random enigne must be created so I write the ruby bindings to alloc memory
and dealloc memory to a <code class="language-plaintext highlighter-rouge">af_random_engine</code> using <code class="language-plaintext highlighter-rouge">arf_engine_alloc</code> and <code class="language-plaintext highlighter-rouge">arf_engine_free</code>
respectively. The rest is similar to how I created bindings in previous blog posts.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">typedef</span> <span class="k">struct</span> <span class="n">RANDOM_ENGINE_STRUCT</span>
<span class="p">{</span>
  <span class="n">af_random_engine</span> <span class="n">cengine</span><span class="p">;</span>
<span class="p">}</span><span class="n">afrandomenginestruct</span><span class="p">;</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_engine_alloc</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">klass</span><span class="p">)</span>
<span class="p">{</span>
  <span class="cm">/* allocate */</span>
  <span class="n">afrandomenginestruct</span><span class="o">*</span> <span class="n">afrandomengine</span> <span class="o">=</span> <span class="n">ALLOC</span><span class="p">(</span><span class="n">afrandomenginestruct</span><span class="p">);</span>
  <span class="cm">/* wrap */</span>
  <span class="k">return</span> <span class="n">Data_Wrap_Struct</span><span class="p">(</span><span class="n">klass</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">arf_engine_free</span><span class="p">,</span> <span class="n">afrandomengine</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">void</span> <span class="nf">arf_engine_free</span><span class="p">(</span><span class="n">afrandomenginestruct</span><span class="o">*</span> <span class="n">afrandomengine</span><span class="p">)</span>
<span class="p">{</span>
  <span class="n">free</span><span class="p">(</span><span class="n">afrandomengine</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_create_random_engine</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">type_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">seed_val</span><span class="p">){</span>
  <span class="n">afrandomenginestruct</span><span class="o">*</span> <span class="n">output</span> <span class="o">=</span> <span class="n">ALLOC</span><span class="p">(</span><span class="n">afrandomenginestruct</span><span class="p">);</span>
  <span class="n">af_random_engine_type</span> <span class="n">rtype</span> <span class="o">=</span> <span class="n">arf_randome_engine_type_from_rbsymbol</span><span class="p">(</span><span class="n">type_val</span><span class="p">);</span>

  <span class="n">af_create_random_engine</span><span class="p">(</span><span class="o">&amp;</span><span class="n">output</span><span class="o">-&gt;</span><span class="n">cengine</span><span class="p">,</span> <span class="n">AF_RANDOM_ENGINE_DEFAULT</span><span class="p">,</span> <span class="n">NUM2ULL</span><span class="p">(</span><span class="n">seed_val</span><span class="p">)</span> <span class="p">)</span> <span class="p">;</span>

  <span class="k">return</span> <span class="n">Data_Wrap_Struct</span><span class="p">(</span><span class="n">Random</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">arf_engine_free</span><span class="p">,</span> <span class="n">output</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_randu</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">ndims_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">dim_val</span><span class="p">){</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">out_array</span> <span class="o">=</span> <span class="n">ALLOC</span><span class="p">(</span><span class="n">afstruct</span><span class="p">);</span>

  <span class="n">dim_t</span> <span class="n">ndims</span> <span class="o">=</span> <span class="p">(</span><span class="n">dim_t</span><span class="p">)</span><span class="n">FIX2LONG</span><span class="p">(</span><span class="n">ndims_val</span><span class="p">);</span>
  <span class="n">dim_t</span><span class="o">*</span> <span class="n">dimensions</span> <span class="o">=</span> <span class="p">(</span><span class="n">dim_t</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">ndims</span> <span class="o">*</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">dim_t</span><span class="p">));</span>
  <span class="n">dim_t</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
  <span class="k">for</span> <span class="p">(</span><span class="n">dim_t</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">index</span> <span class="o">&lt;</span> <span class="n">ndims</span><span class="p">;</span> <span class="n">index</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">dimensions</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">dim_t</span><span class="p">)</span><span class="n">FIX2LONG</span><span class="p">(</span><span class="n">RARRAY_AREF</span><span class="p">(</span><span class="n">dim_val</span><span class="p">,</span> <span class="n">index</span><span class="p">));</span>
    <span class="n">count</span> <span class="o">*=</span> <span class="n">dimensions</span><span class="p">[</span><span class="n">index</span><span class="p">];</span>
  <span class="p">}</span>
  <span class="n">af_randu</span><span class="p">(</span><span class="o">&amp;</span><span class="n">out_array</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">ndims</span><span class="p">,</span> <span class="n">dimensions</span><span class="p">,</span><span class="n">f64</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">Data_Wrap_Struct</span><span class="p">(</span><span class="n">Af_Array</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">arf_free</span><span class="p">,</span> <span class="n">out_array</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now, we have the bindings ready, we can check it using <code class="language-plaintext highlighter-rouge">pry</code>.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">rake</span> <span class="n">pry</span>
<span class="n">pry</span> <span class="o">-</span><span class="n">r</span> <span class="s1">'./lib/arrayfire.rb'</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">engine</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Random</span><span class="p">.</span><span class="nf">create_random_engine</span><span class="p">(</span><span class="ss">:AF_RANDOM_ENGINE_PHILOX_4X32_10</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Random:0x00000002a41350&gt;</span>
<span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Random</span><span class="p">.</span><span class="nf">random_engine_get_seed</span><span class="p">(</span><span class="n">engine</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="mi">100</span>
<span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Random</span><span class="p">.</span><span class="nf">random_engine_set_seed</span><span class="p">(</span><span class="n">engine</span><span class="p">,</span> <span class="mi">123</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Random:0x00000002cfbd98&gt;</span>
<span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Random</span><span class="p">.</span><span class="nf">random_engine_get_seed</span><span class="p">(</span><span class="n">engine</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="mi">123</span>
<span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Random</span><span class="p">.</span><span class="nf">random_engine_get_type</span> <span class="n">engine</span>
<span class="o">=&gt;</span> <span class="s2">"AF_RANDOM_ENGINE_PHILOX_4X32_10"</span>
<span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">arr</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Random</span><span class="p">.</span><span class="nf">randu</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">])</span>
<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x00000002b185f8&gt;</span>
<span class="p">[</span><span class="mi">7</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Util</span><span class="p">.</span><span class="nf">print_array</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">4</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">0.3990</span>     <span class="mf">0.7353</span>     <span class="mf">0.9455</span>     <span class="mf">0.7089</span>
    <span class="mf">0.6720</span>     <span class="mf">0.5160</span>     <span class="mf">0.1587</span>     <span class="mf">0.9434</span>
    <span class="mf">0.5339</span>     <span class="mf">0.3932</span>     <span class="mf">0.8831</span>     <span class="mf">0.1227</span>
    <span class="mf">0.1386</span>     <span class="mf">0.2706</span>     <span class="mf">0.0621</span>     <span class="mf">0.9107</span>

<span class="o">=&gt;</span> <span class="kp">true</span>
<span class="p">[</span><span class="mi">8</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">arr2</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Random</span><span class="p">.</span><span class="nf">randn</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">])</span>
<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x000000029fd4c0&gt;</span>
<span class="p">[</span><span class="mi">9</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Util</span><span class="p">.</span><span class="nf">print_array</span><span class="p">(</span><span class="n">arr2</span><span class="p">)</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">4</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">0.2985</span>    <span class="o">-</span><span class="mf">0.8873</span>    <span class="o">-</span><span class="mf">1.0309</span>     <span class="mf">0.5312</span>
   <span class="o">-</span><span class="mf">2.7126</span>    <span class="o">-</span><span class="mf">0.3550</span>    <span class="o">-</span><span class="mf">1.4627</span>    <span class="o">-</span><span class="mf">1.7783</span>
    <span class="mf">0.4584</span>     <span class="mf">1.9841</span>     <span class="mf">0.0075</span>    <span class="o">-</span><span class="mf">0.5459</span>
    <span class="mf">1.5579</span>    <span class="o">-</span><span class="mf">0.9308</span>    <span class="o">-</span><span class="mf">1.0512</span>     <span class="mf">0.4640</span>

<span class="o">=&gt;</span> <span class="kp">true</span>
</code></pre></div></div>

<p>we have the <code class="language-plaintext highlighter-rouge">Random</code> support ready for <code class="language-plaintext highlighter-rouge">ArrayFire-rb</code></p>

<p>Hence, Ruby bindings for Statistics and Random methods have been successfully implemented.</p>

<h1 id="conclusion">Conclusion</h1>

<p>We can now use <code class="language-plaintext highlighter-rouge">ArrayFire-rb</code> for statistical analysis on data. Since, the calculations would be
on GPU, we can feed it large amount of data from real world.</p>

<p>Random engine can help in creating large arrays with randomly generated values in seconds.</p>

<p>In the next blog, I will explain about using the <code class="language-plaintext highlighter-rouge">Device</code> and <code class="language-plaintext highlighter-rouge">Util</code> class to manage GPU devices
and device memory and other utilities like saving an <code class="language-plaintext highlighter-rouge">Af_Array</code> to file.</p>

<div id="disqus_thread"></div>
<script>
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');

s.src = '//prasunanandblog.disqus.com/embed.js';

s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>]]></content><author><name>Prasun Anand</name></author><category term="arrayfire" /><summary type="html"><![CDATA[This post explains about the Statistics and Random class of arrayfire gem. ArrayFire::Statistics class consists of methods that can be used to operate on Af_Array for statistical analysis. ArrayFire::Random class contains of methods to generate Random numbers and array of Random numbers on the GPU.]]></summary></entry><entry><title type="html">ArrayFire Ruby Bindings (Part IV : BLAS and LAPACK routines)</title><link href="https://prasunanand.github.io/arrayfire/2017/08/16/gsoc17-arrayfire-ruby-bindings-part-4-blas-lapack.html" rel="alternate" type="text/html" title="ArrayFire Ruby Bindings (Part IV : BLAS and LAPACK routines)" /><published>2017-08-16T10:31:00+00:00</published><updated>2017-08-16T10:31:00+00:00</updated><id>https://prasunanand.github.io/arrayfire/2017/08/16/gsoc17-arrayfire-ruby-bindings-part-4-blas-lapack</id><content type="html" xml:base="https://prasunanand.github.io/arrayfire/2017/08/16/gsoc17-arrayfire-ruby-bindings-part-4-blas-lapack.html"><![CDATA[<p>This post covers how to use <code class="language-plaintext highlighter-rouge">BLAS</code> and <code class="language-plaintext highlighter-rouge">LAPACK</code> routines with <code class="language-plaintext highlighter-rouge">ArrayFire-rb</code>, and how these functions
have been implemented by creating Ruby bindings to ArrayFire C API.</p>

<p>The performance benchmarks for ArrayFire against NMatrix can be represented by the following figures.
The code used for benchmarking and generating the plots can be found <a href="https://github.com/prasunanand/arrayfire-rb-benchmark-suite">here</a>
and be used to reproduce similar plots.</p>

<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>

<script type="text/javascript" src="https://code.highcharts.com/4.2.2/highcharts.js"></script>

<script type="text/javascript" src="https://code.highcharts.com/4.2.2/modules/exporting.js"></script>

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>

<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/4.1.1/normalize.min.css" />

<h1 id="performance-metrics">Performance metrics</h1>
<div ng-app="resultApp">
    <div ng-controller="MainCtrl">
      <div class="block">
        <strong>BLAS Routines</strong>
        <div id="chartmat_mult" class="chart"></div>
      </div>
      <div class="block">
        <strong>LAPACK Routines</strong>
          <div id="chartdeterminant" class="chart"></div><br />
          <div id="chartlu_factorization" class="chart"></div><br />
      </div>
    </div>
  <script type="text/javascript" src="/assets/js/chart.js"></script>
</div>

<p>(Note: The above benchmarks have been done on an AMD FX 8350 octacore processor
and Nvidia GTX 750Ti GPU. CUDA backend of ArrayFire was used with double floating points.)</p>

<p>The figure shows that ArrayFire takes the least computation time of all.
ArrayFire is 3 e +6 times faster than NMatrix for JRuby and NMatrix for Ruby(not BLAS)
whereas 7 e +5 times faster than NMatrix for Ruby(using BLAS).</p>

<p>For LAPACK routines, like calculating determinant and lower-upper factorization,
ArrayFire is 100 times faster than NMatrix for JRuby
whereas 6 times faster than NMatrix for Ruby(using LAPACKE).</p>

<p>Lets take a look at the implementation.</p>

<h1 id="blas-routines">BLAS Routines</h1>

<p>All the BLAS methods are <code class="language-plaintext highlighter-rouge">singleton_methods</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">Init_arrayfire</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">ArrayFire</span> <span class="o">=</span> <span class="n">rb_define_module</span><span class="p">(</span><span class="s">"ArrayFire"</span><span class="p">);</span>

  <span class="n">Blas</span> <span class="o">=</span> <span class="n">rb_define_class_under</span><span class="p">(</span><span class="n">ArrayFire</span><span class="p">,</span> <span class="s">"BLAS"</span><span class="p">,</span> <span class="n">rb_cObject</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Blas</span><span class="p">,</span> <span class="s">"matmul"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_matmul</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Blas</span><span class="p">,</span> <span class="s">"dot"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_dot</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Blas</span><span class="p">,</span> <span class="s">"transpose"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_transpose</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>

<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">arf_matmul</code> and <code class="language-plaintext highlighter-rouge">arf_transpose</code> call <code class="language-plaintext highlighter-rouge">af_matmul</code> and <code class="language-plaintext highlighter-rouge">af_transpose</code> respectively.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_matmul</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">left_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">right_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">left_prop_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">right_prop_val</span><span class="p">){</span>

  <span class="n">afstruct</span><span class="o">*</span> <span class="n">left</span><span class="p">;</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">right</span><span class="p">;</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">result</span> <span class="o">=</span> <span class="n">ALLOC</span><span class="p">(</span><span class="n">afstruct</span><span class="p">);</span>

  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">left_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">left</span><span class="p">);</span>
  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">right_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">right</span><span class="p">);</span>

  <span class="n">af_mat_prop</span> <span class="n">left_mat_prop</span> <span class="o">=</span> <span class="n">arf_mat_type_from_rbsymbol</span><span class="p">(</span><span class="n">left_prop_val</span><span class="p">);</span>
  <span class="n">af_mat_prop</span> <span class="n">right_mat_prop</span> <span class="o">=</span> <span class="n">arf_mat_type_from_rbsymbol</span><span class="p">(</span><span class="n">right_prop_val</span><span class="p">);</span>

  <span class="n">af_matmul</span><span class="p">(</span><span class="o">&amp;</span><span class="n">result</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">left</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">right</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">left_mat_prop</span><span class="p">,</span> <span class="n">right_mat_prop</span><span class="p">);</span>

  <span class="n">af_print_array</span><span class="p">(</span><span class="n">result</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="k">return</span> <span class="n">Data_Wrap_Struct</span><span class="p">(</span><span class="n">CLASS_OF</span><span class="p">(</span><span class="n">left_val</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">arf_free</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_transpose</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">input</span><span class="p">){</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">obj</span><span class="p">;</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">result</span> <span class="o">=</span> <span class="n">ALLOC</span><span class="p">(</span><span class="n">afstruct</span><span class="p">);</span>

  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">obj</span><span class="p">);</span>

  <span class="n">af_transpose</span><span class="p">(</span><span class="o">&amp;</span><span class="n">result</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">obj</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="nb">false</span><span class="p">);</span>

  <span class="n">af_print_array</span><span class="p">(</span><span class="n">result</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="k">return</span> <span class="n">Data_Wrap_Struct</span><span class="p">(</span><span class="n">CLASS_OF</span><span class="p">(</span><span class="n">input</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">arf_free</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span>
<span class="p">}</span>

</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">af_matmul</code> expects the property of matrices passed to it. For example, <code class="language-plaintext highlighter-rouge">af_mat_prop AF_MAT_TRANS</code>
signifies that the matrix is transposed. So, to pass the symbols to Ruby C function arf_matmul, I
have used the code given below. I have creared a list of values <code class="language-plaintext highlighter-rouge">MAT_PROPERTIES</code> and a function
<code class="language-plaintext highlighter-rouge">arf_mat_type_from_symbol</code> which is responsible for figuring out <code class="language-plaintext highlighter-rouge">af_mat_prop</code> from the symbol.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">*</span><span class="p">,</span> <span class="kt">size_t</span><span class="o">&gt;</span> <span class="n">MAT_PROPERTIES</span> <span class="o">=</span> <span class="p">{</span>
  <span class="p">{</span><span class="s">"AF_MAT_NONE"</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span>
  <span class="p">{</span><span class="s">"AF_MAT_TRANS"</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span>
  <span class="p">{</span><span class="s">"AF_MAT_CTRANS"</span><span class="p">,</span> <span class="mi">2</span><span class="p">},</span>
  <span class="p">{</span><span class="s">"AF_MAT_CONJ"</span><span class="p">,</span> <span class="mi">4</span><span class="p">},</span>
  <span class="p">{</span><span class="s">"AF_MAT_UPPER"</span><span class="p">,</span> <span class="mi">32</span><span class="p">},</span>
  <span class="p">{</span><span class="s">"AF_MAT_LOWER"</span><span class="p">,</span> <span class="mi">64</span><span class="p">},</span>
  <span class="p">{</span><span class="s">"AF_MAT_DIAG_UNIT"</span><span class="p">,</span> <span class="mi">128</span><span class="p">},</span>
  <span class="p">{</span><span class="s">"AF_MAT_SYM"</span><span class="p">,</span> <span class="mi">512</span><span class="p">},</span>
  <span class="p">{</span><span class="s">"AF_MAT_POSDEF"</span><span class="p">,</span> <span class="mi">1024</span><span class="p">},</span>
  <span class="p">{</span><span class="s">"AF_MAT_ORTHOG"</span><span class="p">,</span> <span class="mi">2048</span><span class="p">},</span>
  <span class="p">{</span><span class="s">"AF_MAT_TRI_DIAG"</span><span class="p">,</span> <span class="mi">4096</span><span class="p">},</span>
  <span class="p">{</span><span class="s">"AF_MAT_BLOCK_DIAG"</span><span class="p">,</span> <span class="mi">8192</span><span class="p">}</span>
<span class="p">};</span>


<span class="n">af_mat_prop</span> <span class="nf">arf_mat_type_from_rbsymbol</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">sym</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">ID</span> <span class="n">sym_id</span> <span class="o">=</span> <span class="n">SYM2ID</span><span class="p">(</span><span class="n">sym</span><span class="p">);</span>

  <span class="k">for</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">*</span><span class="p">,</span> <span class="kt">size_t</span><span class="o">&gt;::</span><span class="n">value_type</span><span class="o">&amp;</span> <span class="n">entry</span> <span class="o">:</span> <span class="n">MAT_PROPERTIES</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">sym_id</span> <span class="o">==</span> <span class="n">rb_intern</span><span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">first</span><span class="p">))</span> <span class="p">{</span>
      <span class="k">return</span> <span class="n">static_cast</span><span class="o">&lt;</span><span class="n">af_mat_prop</span><span class="o">&gt;</span><span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">second</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="n">VALUE</span> <span class="n">str</span> <span class="o">=</span> <span class="n">rb_any_to_s</span><span class="p">(</span><span class="n">sym</span><span class="p">);</span>
  <span class="n">rb_raise</span><span class="p">(</span><span class="n">rb_eArgError</span><span class="p">,</span> <span class="s">"invalid matrix type symbol (:%s) specified"</span><span class="p">,</span>
   <span class="n">RSTRING_PTR</span><span class="p">(</span><span class="n">str</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<p>So, now I can check if the bindings work successfully.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">rake</span> <span class="n">pry</span>
<span class="n">pry</span> <span class="o">-</span><span class="n">r</span> <span class="s1">'./lib/arrayfire.rb'</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">left</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span> <span class="p">,</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">]</span> <span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">11</span> <span class="p">,</span> <span class="mi">2</span> <span class="p">,</span><span class="o">-</span><span class="mi">5</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">10</span><span class="p">]</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">3</span> <span class="mi">3</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">1.0000</span>     <span class="mf">4.0000</span>    <span class="o">-</span><span class="mf">5.0000</span>
    <span class="mf">4.0000</span>    <span class="mf">11.0000</span>     <span class="mf">8.0000</span>
    <span class="mf">6.0000</span>     <span class="mf">2.0000</span>    <span class="mf">10.0000</span>

<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x000000014e56c8&gt;</span>
<span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">right</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span> <span class="p">,</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span><span class="mi">2</span><span class="p">]</span> <span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="o">-</span><span class="mi">11</span><span class="p">,</span> <span class="mi">8</span><span class="p">]</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">3</span> <span class="mi">2</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">1.0000</span>    <span class="mf">10.0000</span>
    <span class="mf">0.0000</span>   <span class="o">-</span><span class="mf">11.0000</span>
    <span class="mf">8.0000</span>     <span class="mf">8.0000</span>

<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x00000001591db0&gt;</span>
<span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">result</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">BLAS</span><span class="p">.</span><span class="nf">matmul</span><span class="p">(</span><span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="p">,</span> <span class="ss">:AF_MAT_NONE</span><span class="p">,</span> <span class="ss">:AF_MAT_NONE</span><span class="p">)</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">3</span> <span class="mi">2</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
  <span class="o">-</span><span class="mf">39.0000</span>   <span class="o">-</span><span class="mf">74.0000</span>
   <span class="mf">68.0000</span>   <span class="o">-</span><span class="mf">17.0000</span>
   <span class="mf">86.0000</span>   <span class="mf">118.0000</span>

<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x000000016136f8&gt;</span>
<span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">transposed</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">BLAS</span><span class="p">.</span><span class="nf">transpose</span><span class="p">(</span><span class="n">left</span><span class="p">)</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">3</span> <span class="mi">3</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">1.0000</span>     <span class="mf">4.0000</span>     <span class="mf">6.0000</span>
    <span class="mf">4.0000</span>    <span class="mf">11.0000</span>     <span class="mf">2.0000</span>
   <span class="o">-</span><span class="mf">5.0000</span>     <span class="mf">8.0000</span>    <span class="mf">10.0000</span>

<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x00000001762f68&gt;</span>

</code></pre></div></div>
<p>It works!.</p>

<h1 id="lapack-routines">LAPACK Routines</h1>

<p>LAPACK routines similar to BLAS ones are singleton methods.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Lapack</span> <span class="o">=</span> <span class="n">rb_define_class_under</span><span class="p">(</span><span class="n">ArrayFire</span><span class="p">,</span> <span class="s">"LAPACK"</span><span class="p">,</span> <span class="n">rb_cObject</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Lapack</span><span class="p">,</span> <span class="s">"svd_func"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_svd_func</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Lapack</span><span class="p">,</span> <span class="s">"svd_inplace_func"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_svd_inplace_func</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Lapack</span><span class="p">,</span> <span class="s">"lu_func"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_lu_func</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Lapack</span><span class="p">,</span> <span class="s">"lu_inplace_func"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_lu_inplace_func</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Lapack</span><span class="p">,</span> <span class="s">"qr_func"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_qr_func</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Lapack</span><span class="p">,</span> <span class="s">"qr_inplace_func"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_qr_inplace_func</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Lapack</span><span class="p">,</span> <span class="s">"cholesky_func"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_cholesky_func</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Lapack</span><span class="p">,</span> <span class="s">"cholesky_inplace_func"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_cholesky_inplace_func</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Lapack</span><span class="p">,</span> <span class="s">"solve_func"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_solve_func</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Lapack</span><span class="p">,</span> <span class="s">"solve_lu_func"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_solve_lu_func</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Lapack</span><span class="p">,</span> <span class="s">"inverse"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_inverse</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Lapack</span><span class="p">,</span> <span class="s">"rank"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_rank</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Lapack</span><span class="p">,</span> <span class="s">"det"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_det</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Lapack</span><span class="p">,</span> <span class="s">"norm"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_norm</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Lapack</span><span class="p">,</span> <span class="s">"is_lapack_available"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_is_lapack_available</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">LAPACK.svd</code> must return multiple objects and hence calls <code class="language-plaintext highlighter-rouge">LAPACK.arf_svd_func</code>. The implementation
is as follows.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_svd_func</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">u_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">s_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">vt_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">val</span><span class="p">){</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">input</span><span class="p">;</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">u</span><span class="p">;</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">s</span><span class="p">;</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">vt</span><span class="p">;</span>

  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span>
  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">u_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">u</span><span class="p">);</span>
  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">s_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">s</span><span class="p">);</span>
  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">vt_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">vt</span><span class="p">);</span>

  <span class="n">af_svd</span><span class="p">(</span><span class="o">&amp;</span><span class="n">u</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">s</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">vt</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">input</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="k">return</span> <span class="n">Qtrue</span><span class="p">;</span>
<span class="p">}</span>

</code></pre></div></div>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nn">ArrayFire</span>
  <span class="k">class</span> <span class="nc">LAPACK</span>

    <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">svd</span><span class="p">(</span><span class="n">af_array</span><span class="p">)</span>
      <span class="n">u</span> <span class="o">=</span>  <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span>
      <span class="n">s</span> <span class="o">=</span>  <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span>
      <span class="n">vt</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span>
      <span class="no">ArrayFire</span><span class="o">::</span><span class="no">LAPACK</span><span class="p">.</span><span class="nf">svd_func</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">vt</span><span class="p">,</span> <span class="n">af_array</span><span class="p">)</span>
      <span class="k">return</span> <span class="n">u</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">vt</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">LAPACK.det</code> calls <code class="language-plaintext highlighter-rouge">af_det</code> to calculate the determinant. Currently, I haven’t
created support for complex dtype. So, I have ignored the imaginary part of
the result if it is not a real number.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_det</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">val</span><span class="p">){</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">matrix</span><span class="p">;</span>
  <span class="kt">double</span> <span class="n">det_real</span><span class="p">,</span> <span class="n">det_imag</span><span class="p">;</span>

  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">matrix</span><span class="p">);</span>

  <span class="n">af_det</span><span class="p">(</span><span class="o">&amp;</span><span class="n">det_real</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">det_imag</span><span class="p">,</span> <span class="n">matrix</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">DBL2NUM</span><span class="p">(</span><span class="n">det_real</span><span class="p">);</span>
<span class="p">}</span>


</code></pre></div></div>

<p>Now, we can check the elementwise operations using <code class="language-plaintext highlighter-rouge">pry</code>.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">rake</span> <span class="n">pry</span>
<span class="n">pry</span> <span class="o">-</span><span class="n">r</span> <span class="s1">'./lib/arrayfire.rb'</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">matrix</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span><span class="mi">2</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">8</span><span class="p">]</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">4</span> <span class="mi">2</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">1.0000</span>     <span class="mf">2.0000</span>
    <span class="mf">3.0000</span>     <span class="mf">4.0000</span>
    <span class="mf">5.0000</span>     <span class="mf">6.0000</span>
    <span class="mf">7.0000</span>     <span class="mf">8.0000</span>

<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x0000000265cbe0&gt;</span>
<span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">u</span> <span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">vt</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">LAPACK</span><span class="p">.</span><span class="nf">svd</span><span class="p">(</span><span class="n">matrix</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="p">[</span><span class="c1">#&lt;ArrayFire::Af_Array:0x000000026ff070&gt;, #&lt;ArrayFire::Af_Array:0x000000026ff048&gt;, #&lt;ArrayFire::Af_Array:0x000000026ff020&gt;]</span>
<span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Util</span><span class="p">.</span><span class="nf">print_array</span><span class="p">(</span><span class="n">u</span><span class="p">)</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">4</span> <span class="mi">4</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
   <span class="o">-</span><span class="mf">0.1525</span>    <span class="o">-</span><span class="mf">0.8226</span>    <span class="o">-</span><span class="mf">0.3945</span>    <span class="o">-</span><span class="mf">0.3800</span>
   <span class="o">-</span><span class="mf">0.3499</span>    <span class="o">-</span><span class="mf">0.4214</span>     <span class="mf">0.2428</span>     <span class="mf">0.8007</span>
   <span class="o">-</span><span class="mf">0.5474</span>    <span class="o">-</span><span class="mf">0.0201</span>     <span class="mf">0.6979</span>    <span class="o">-</span><span class="mf">0.4614</span>
   <span class="o">-</span><span class="mf">0.7448</span>     <span class="mf">0.3812</span>    <span class="o">-</span><span class="mf">0.5462</span>     <span class="mf">0.0407</span>

<span class="o">=&gt;</span> <span class="kp">true</span>
<span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Util</span><span class="p">.</span><span class="nf">print_array</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">2</span> <span class="mi">1</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
   <span class="mf">14.2691</span>
    <span class="mf">0.6268</span>

<span class="o">=&gt;</span> <span class="kp">true</span>
<span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Util</span><span class="p">.</span><span class="nf">print_array</span><span class="p">(</span><span class="n">vt</span><span class="p">)</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">2</span> <span class="mi">2</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
   <span class="o">-</span><span class="mf">0.6414</span>    <span class="o">-</span><span class="mf">0.7672</span>
    <span class="mf">0.7672</span>    <span class="o">-</span><span class="mf">0.6414</span>

<span class="o">=&gt;</span> <span class="kp">true</span>
<span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">left</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span> <span class="p">,</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">]</span> <span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">11</span> <span class="p">,</span> <span class="mi">2</span> <span class="p">,</span><span class="o">-</span><span class="mi">5</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">10</span><span class="p">]</span>
<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">3</span> <span class="mi">3</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">1.0000</span>     <span class="mf">4.0000</span>    <span class="o">-</span><span class="mf">5.0000</span>
    <span class="mf">4.0000</span>    <span class="mf">11.0000</span>     <span class="mf">8.0000</span>
    <span class="mf">6.0000</span>     <span class="mf">2.0000</span>    <span class="mf">10.0000</span>

<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x00000002984c78&gt;</span>
<span class="p">[</span><span class="mi">7</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">det</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">LAPACK</span><span class="p">.</span><span class="nf">det</span><span class="p">(</span><span class="n">left</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="mf">415.9999694824219</span>

</code></pre></div></div>

<p>It works!</p>

<h1 id="conclusion">Conclusion</h1>

<p>We can now use <code class="language-plaintext highlighter-rouge">ArrayFire-rb</code> for linear algebra since the BLAS and LAPACK routines are in
place. Also, the performance is outstanding.</p>

<p>In the next blog, I will explain about using the Random Engine generator and Statistics methods for ArrayFire.</p>

<div id="disqus_thread"></div>
<script>
/**
* RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
* LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
*/
/*
var disqus_config = function () {
this.page.url = PAGE_URL; // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};
*/
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');

s.src = '//prasunanandblog.disqus.com/embed.js';

s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>]]></content><author><name>Prasun Anand</name></author><category term="arrayfire" /><summary type="html"><![CDATA[This post covers how to use BLAS and LAPACK routines with ArrayFire-rb, and how these functions have been implemented by creating Ruby bindings to ArrayFire C API.]]></summary></entry><entry><title type="html">Calling D from Ruby for GPU computing</title><link href="https://prasunanand.github.io/gpu-computing/2017/07/25/gsoc17-calling-d-from-ruby-for-gpu-computing.html" rel="alternate" type="text/html" title="Calling D from Ruby for GPU computing" /><published>2017-07-25T04:31:00+00:00</published><updated>2017-07-25T04:31:00+00:00</updated><id>https://prasunanand.github.io/gpu-computing/2017/07/25/gsoc17-calling-d-from-ruby-for-gpu-computing</id><content type="html" xml:base="https://prasunanand.github.io/gpu-computing/2017/07/25/gsoc17-calling-d-from-ruby-for-gpu-computing.html"><![CDATA[<p>Language bindings are interfaces that allow code written in one programming language to interact with or use functionalities provided by libraries or code written in another programming language. They serve as a bridge between different programming environments, making it possible for developers to leverage existing libraries or systems without needing to rewrite them in the language they are working in.</p>

<p>As <a href="https://github.com/prasunanand/arrayfire-rb"><code class="language-plaintext highlighter-rouge">ArrayFire-rb</code></a>, a GPGPU libray has started taking shape,
the next goal is to interface it with <a href="https://github.com/sciruby/nmatrix"><code class="language-plaintext highlighter-rouge">NMatrix</code></a> library, so we can
run Linear Mixed Models(<a href="https://github.com/agisga/mixed_models/"><code class="language-plaintext highlighter-rouge">mixed_models</code></a>).</p>

<p>I have also written an LMM(Linear Mixed Models) solver in D for Genome Wide Association studies
called <a href="https://github.com/prasunanand/faster_lmm_d">faster_lmm_d</a> which has two GPU backends:</p>
<ol>
  <li>
    <p>CUDA backend which helps it directly interact with CUBLAS libraries and runs only on Nvidia Hardware.
For CUDA backend, <code class="language-plaintext highlighter-rouge">Faster_LMM_D</code> uses <a href="https://github.com/prasunanand/cuda_d"><code class="language-plaintext highlighter-rouge">cuda_d</code></a>(The D bindings I wrote for CUDA libraries).</p>
  </li>
  <li>
    <p>ArrayFire backend which helps it run on all major GPU vendors(Nvidia, Intel, AMD) by calling CUDA, CuBLAS,
OpenCL, clBLAS libraries using the ArrayFire library. For ArrayFire backend, <code class="language-plaintext highlighter-rouge">Faster_LMM_D</code> uses
<a href="https://github.com/arrayfire/arrayfire-d"><code class="language-plaintext highlighter-rouge">arrayfire-d</code></a>(The D bindings I wrote for ArrayFire library).</p>
  </li>
</ol>

<p>So, I found that it would be really great if we could port <code class="language-plaintext highlighter-rouge">faster_lmm_d</code> to Ruby by calling D from Ruby. <code class="language-plaintext highlighter-rouge">faster_lmm_d</code>
uses some cool tricks to efficiently use GPUs for computing like minimizing the warmup time, minimal copying
of CPU memory to GPU memory. It logs CPU memory and GPU memory before and after every significant computation.
So, it would be an ideal exercise for GPU computing on Ruby by calling D functions under the hood.</p>

<p>Although, this is still a work in progress, I would like to share about my experiences.</p>

<h1 id="previous-attempts">Previous Attempts</h1>

<p>There has been previous attempts at Calling D from Ruby. In my search for the existing attempts at
“Calling D from Ruby”, I stumbled upon these resources.</p>

<ol>
  <li><a href="https://wiki.dlang.org/Call_D_from_Ruby_using_FFI">FFI</a>: Use the Ruby-FFI gem to call a D function from C.</li>
  <li><a href="https://github.com/tomash/rudy">RuDy</a>: An effort / library / gem to enable
and ease writing Ruby native extensions in D programming language. It depends on creatind D bindings for the API calls in <code class="language-plaintext highlighter-rouge">ruby.h</code> header
file.</li>
  <li><a href="https://github.com/llaine/ruby-dlang">Ruby-Dlang</a>: Similar approach as Rudy.</li>
  <li><a href="https://github.com/jacob-carlborg/orbit">Orbit</a>: Similar approach as Rudy.</li>
</ol>

<p>I have been intereseted in the first two methods, i.e. FFI and Rudy.</p>

<h1 id="exploring-ffi">Exploring FFI</h1>

<p>The idea here is to create a shared object <code class="language-plaintext highlighter-rouge">.so</code> and call it with Ruby by loading the shared object using FFI gem.</p>

<p>Dlang has three compilers namely <code class="language-plaintext highlighter-rouge">DMD</code>, <code class="language-plaintext highlighter-rouge">GDC</code> and <code class="language-plaintext highlighter-rouge">LDC</code>. The post on Dlang wiki makes use of <code class="language-plaintext highlighter-rouge">DMD</code>, I could easily
run the example on my machine using <code class="language-plaintext highlighter-rouge">DMD</code>, however I could not run it with <code class="language-plaintext highlighter-rouge">LDC</code>. I need to compile the d files
with LDC because <code class="language-plaintext highlighter-rouge">faster_lmm_d</code> makes use of <code class="language-plaintext highlighter-rouge">LDC</code> compiler switches and it would take a lot of effort to be able to
run it with <code class="language-plaintext highlighter-rouge">DMD</code>.</p>

<p>The error I encountered is:</p>

<ol>
  <li>Error with ld :
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ldc2 <span class="nt">-shared</span> <span class="nt">-m64</span> <span class="nt">-relocation-model</span><span class="o">=</span>pic i.d
/usr/bin/ld: /home/prasun/ldclatest/ldc-1.1.0-pk9rkm4zvdp6pglam7s2/lib/libdruntime-ldc.a<span class="o">(</span>errno.c.o<span class="o">)</span>: relocation R_X86_64_PC32 against undefined symbol <span class="sb">`</span>__errno_location@@GLIBC_2.2.5<span class="s1">' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
Error: /usr/lib/nvidia-cuda-toolkit/bin/gcc failed with status: 1
</span></code></pre></div>    </div>
  </li>
</ol>

<p>I have also tried some hit and trial and yet I was unable to properly compile the file.</p>

<h1 id="exploring-rudy">Exploring RuDy</h1>

<p>I find Rudy as a more suitable way to create Ruby native extensions.</p>

<p>When creating a Ruby native extension in C, we have a set of APIs provided by <code class="language-plaintext highlighter-rouge">ruby.h</code> that helps in creating a
<code class="language-plaintext highlighter-rouge">Module</code> or a <code class="language-plaintext highlighter-rouge">Class</code> and the <code class="language-plaintext highlighter-rouge">methods</code> are nested to it.</p>

<p>For example, <code class="language-plaintext highlighter-rouge">rb_define_module</code> helps in creating a module and <code class="language-plaintext highlighter-rouge">rb_define_class_under</code> is used to create a class
nested in a module. <code class="language-plaintext highlighter-rouge">rb_define_method</code> and <code class="language-plaintext highlighter-rouge">rb_define_singleton_method</code> are used to create methods. The variables
are used as <code class="language-plaintext highlighter-rouge">VALUE</code> which are passed around between Ruby frontend and C backend.</p>

<p>A simple code snippet.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// calculater.c</span>
<span class="kt">void</span> <span class="nf">Init_extension</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">Calculator</span> <span class="o">=</span> <span class="n">rb_define_module</span><span class="p">(</span><span class="s">"Calculator"</span><span class="p">);</span>              <span class="c1">// Calculator module</span>
  <span class="n">IO</span> <span class="o">=</span> <span class="n">rb_define_class_under</span><span class="p">(</span><span class="n">Calculator</span><span class="p">,</span> <span class="s">"IO"</span><span class="p">,</span> <span class="n">rb_cObject</span><span class="p">);</span> <span class="c1">// Calculator::IO class</span>
  <span class="n">rb_define_alloc_func</span><span class="p">(</span><span class="n">IO</span><span class="p">,</span> <span class="n">io_alloc</span><span class="p">);</span>                       <span class="c1">// memory allocator for C structs</span>
  <span class="n">rb_define_method</span><span class="p">(</span><span class="n">IO</span><span class="p">,</span> <span class="s">"initialize"</span><span class="p">,</span> <span class="n">io_init</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">);</span>          <span class="c1">// Calculator::IO#new constructor</span>
  <span class="n">rb_define_method</span><span class="p">(</span><span class="n">IO</span><span class="p">,</span> <span class="s">"get_stream"</span><span class="p">,</span><span class="n">io_get_stream</span><span class="p">,</span><span class="mi">1</span> <span class="p">);</span>      <span class="c1">// Calculator::IO#get_stream method</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">io_init</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="n">VALUE</span><span class="o">*</span> <span class="n">argv</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">self</span><span class="p">){</span>
  <span class="c1">// code...</span>
  <span class="k">return</span> <span class="n">self</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">io_get_stream</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">some_val</span><span class="p">){</span>
  <span class="k">return</span> <span class="n">Qtrue</span><span class="p">;</span>
<span class="p">}</span>

</code></pre></div></div>

<p>After the C code with the module, classes and methods are in place, we compile it to get a shared object <code class="language-plaintext highlighter-rouge">extension.so</code>. Then a Ruby
file <code class="language-plaintext highlighter-rouge">calculater.rb</code> can just load that <code class="language-plaintext highlighter-rouge">extension.so</code> as:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># calculater.rb</span>
<span class="nb">require</span> <span class="s1">'calculater.so'</span>

</code></pre></div></div>

<p>This seems simple but as the size of application grows, the extension becomes tough to manage.</p>

<p>I believe D to be a superior C and provides modern programming paradigm and the LDC compiler is very promising. So, it would be great if we could write the
native extension in D and get a shared library. Also, LDC has an incredible garbage collecter that would be very helpful for scientific computing Ruby libraries.</p>

<p>To write the extension in D, the <code class="language-plaintext highlighter-rouge">ruby.h</code> bindings could be created in D using <a href="http://www.dsource.org/projects/dstep"><code class="language-plaintext highlighter-rouge">dstep</code></a> or <a href="http://www.dsource.org/projects/bcd"><code class="language-plaintext highlighter-rouge">bcd</code></a>.</p>

<p>RuDy <a href="https://github.com/tomash/rudy#limitations-and-areas-for-development">doesn’t have complete support</a>
for <code class="language-plaintext highlighter-rouge">LDC</code> and I am still getting my head around using RuDy to create Ruby native extensions. <a href="http://tomash.wrug.eu/blog/2009/03/03/rudy-ruby-native-extensions-in-d-programming-language/">Here</a> is a nice blog post about RuDy project.</p>

<h1 id="conclusion">Conclusion</h1>

<p>Calling D from Ruby would for sure prove to be an efficient way of writing Ruby native extensions and use D as a
better choice over C. In the meanwhile, porting faster-lmm-d is a work in progress and I will share further updates
when it is ready.</p>

<p>The progress of Ruby port of <code class="language-plaintext highlighter-rouge">faster-lmm-d</code> can be tracked at <a href="https://github.com/prasunanand/bio-faster_lmm_d"><code class="language-plaintext highlighter-rouge">Bio-faster_lmm_d</code></a>
and would become a part of <a href="http://bioruby.org/">BioRuby</a> project. The latest progress can be tracked here.</p>

<div id="disqus_thread"></div>
<script>
/**
* RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
* LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
*/
/*
var disqus_config = function () {
this.page.url = PAGE_URL; // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};
*/
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');

s.src = '//prasunanandblog.disqus.com/embed.js';

s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>]]></content><author><name>Prasun Anand</name></author><category term="gpu-computing" /><summary type="html"><![CDATA[Language bindings are interfaces that allow code written in one programming language to interact with or use functionalities provided by libraries or code written in another programming language. They serve as a bridge between different programming environments, making it possible for developers to leverage existing libraries or systems without needing to rewrite them in the language they are working in.]]></summary></entry><entry><title type="html">ArrayFire Ruby Bindings (Part III : Test-suite and Algorithm class)</title><link href="https://prasunanand.github.io/arrayfire/2017/07/22/gsoc17-arrayfire-ruby-bindings-part-3-minitest-algorithm.html" rel="alternate" type="text/html" title="ArrayFire Ruby Bindings (Part III : Test-suite and Algorithm class)" /><published>2017-07-22T04:31:00+00:00</published><updated>2017-07-22T04:31:00+00:00</updated><id>https://prasunanand.github.io/arrayfire/2017/07/22/gsoc17-arrayfire-ruby-bindings-part-3-minitest-algorithm</id><content type="html" xml:base="https://prasunanand.github.io/arrayfire/2017/07/22/gsoc17-arrayfire-ruby-bindings-part-3-minitest-algorithm.html"><![CDATA[<p>This post covers how I implemented the test-suite and <code class="language-plaintext highlighter-rouge">Algorithm</code> class for <code class="language-plaintext highlighter-rouge">ArrayFire-rb</code> using  ArrayFire C API, and
how to use <code class="language-plaintext highlighter-rouge">Algorithm</code> class methods with <code class="language-plaintext highlighter-rouge">Af_Array</code>.</p>

<h1 id="test-suite">Test suite</h1>

<p>I have used <code class="language-plaintext highlighter-rouge">minitest</code> for writing the tests for <code class="language-plaintext highlighter-rouge">ArrayFire-rb</code>.</p>

<p>To assert if two arrays are equal, I implemented <code class="language-plaintext highlighter-rouge">Af_Array#==</code> method. I used <code class="language-plaintext highlighter-rouge">af_eq</code> api for implementing <code class="language-plaintext highlighter-rouge">==</code>.
However <code class="language-plaintext highlighter-rouge">af_eq</code> method checks for exact matches and thus
doesn’t work if the values are correct upto a certain number of decimal places. So, I can’t use <code class="language-plaintext highlighter-rouge">==</code> to test the output
of Trigonometric methods , for-example, <code class="language-plaintext highlighter-rouge">Af_Array#sin</code>. I implemented <code class="language-plaintext highlighter-rouge">Af_Array#approx_equal</code> that checks if the values are
correct upto three decimal places.</p>

<p>This is how <code class="language-plaintext highlighter-rouge">arith_test.rb</code> looks like:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">class</span> <span class="nc">ArrayFire::ArithTest</span> <span class="o">&lt;</span> <span class="no">Minitest</span><span class="o">::</span><span class="no">Test</span>

  <span class="k">def</span> <span class="nf">setup</span>
    <span class="vi">@a</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">],[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">]</span>
    <span class="vi">@b</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">],[</span><span class="mi">2</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">8</span><span class="p">]</span>
    <span class="vi">@elements</span> <span class="o">=</span> <span class="p">[</span><span class="mi">10</span><span class="p">,</span> <span class="o">-</span><span class="mi">11</span><span class="p">,</span> <span class="mi">48</span><span class="p">,</span> <span class="mi">21</span><span class="p">,</span> <span class="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">7</span><span class="p">,</span> <span class="mi">112</span><span class="p">]</span>
    <span class="vi">@af_array</span> <span class="o">=</span>  <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">],</span> <span class="vi">@elements</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">test_addition</span>
    <span class="n">c</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">],[</span><span class="mi">3</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">9</span><span class="p">,</span><span class="mi">12</span><span class="p">]</span>
    <span class="n">assert_equal</span> <span class="n">c</span><span class="p">,</span> <span class="vi">@a</span> <span class="o">+</span> <span class="vi">@b</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">test_subtraction</span>
    <span class="n">assert_equal</span> <span class="vi">@a</span><span class="p">,</span> <span class="vi">@b</span> <span class="o">-</span> <span class="vi">@a</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">test_multiplication</span>
    <span class="n">c</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">],[</span><span class="mi">2</span><span class="p">,</span><span class="mi">8</span><span class="p">,</span><span class="mi">18</span><span class="p">,</span><span class="mi">32</span><span class="p">]</span>
    <span class="n">assert_equal</span> <span class="n">c</span><span class="p">,</span> <span class="vi">@b</span> <span class="o">*</span> <span class="vi">@a</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">test_division</span>
    <span class="n">c</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">],[</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">]</span>
    <span class="n">assert_equal</span> <span class="n">c</span><span class="p">,</span> <span class="vi">@b</span> <span class="o">/</span> <span class="vi">@a</span>
  <span class="k">end</span>

  <span class="p">[</span><span class="ss">:sin</span><span class="p">,</span> <span class="ss">:cos</span><span class="p">,</span> <span class="ss">:tan</span><span class="p">,</span> <span class="ss">:sinh</span><span class="p">,</span> <span class="ss">:cosh</span><span class="p">,</span> <span class="ss">:tanh</span><span class="p">].</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="nb">method</span><span class="o">|</span>
    <span class="n">define_method</span><span class="p">(</span><span class="s2">"test_</span><span class="si">#{</span><span class="nb">method</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="k">do</span>
      <span class="n">x</span> <span class="o">=</span> <span class="vi">@elements</span><span class="p">.</span><span class="nf">map</span><span class="p">{</span> <span class="o">|</span><span class="n">e</span><span class="o">|</span> <span class="no">Math</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="nb">method</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span> <span class="p">}</span>
      <span class="n">res_arr</span> <span class="o">=</span>  <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">],</span> <span class="n">x</span>
      <span class="n">assert</span> <span class="n">res_arr</span><span class="p">.</span><span class="nf">approx_equal</span> <span class="vi">@af_array</span><span class="p">.</span><span class="nf">send</span> <span class="nb">method</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>

</code></pre></div></div>

<p>The implementation of <code class="language-plaintext highlighter-rouge">==</code> and <code class="language-plaintext highlighter-rouge">approx_equal</code> are as follows:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">rb_define_method</span><span class="p">(</span><span class="n">Af_Array</span><span class="p">,</span> <span class="s">"=="</span><span class="p">,(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_eqeq</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span>
<span class="n">rb_define_method</span><span class="p">(</span><span class="n">Af_Array</span><span class="p">,</span> <span class="s">"approx_equal"</span><span class="p">,(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_eqeq_approx</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_eqeq</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">left_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">right_val</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">left</span><span class="p">;</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">right</span><span class="p">;</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">result</span> <span class="o">=</span> <span class="n">ALLOC</span><span class="p">(</span><span class="n">afstruct</span><span class="p">);</span>
  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">left_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">left</span><span class="p">);</span>
  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">right_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">right</span><span class="p">);</span>
  <span class="n">af_eq</span><span class="p">(</span><span class="o">&amp;</span><span class="n">result</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span>  <span class="n">left</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">right</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span>

  <span class="n">dim_t</span> <span class="n">count</span><span class="p">;</span>
  <span class="n">af_get_elements</span><span class="p">(</span><span class="o">&amp;</span><span class="n">count</span><span class="p">,</span> <span class="n">result</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>
  <span class="n">bool</span><span class="o">*</span> <span class="n">data</span> <span class="o">=</span> <span class="p">(</span><span class="n">bool</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">count</span> <span class="o">*</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">bool</span><span class="p">));</span>
  <span class="n">af_get_data_ptr</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">result</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="k">for</span> <span class="p">(</span><span class="n">dim_t</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">index</span> <span class="o">&lt;</span> <span class="n">count</span><span class="p">;</span> <span class="n">index</span><span class="o">++</span><span class="p">){</span>
    <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">data</span><span class="p">[</span><span class="n">index</span><span class="p">]){</span>
      <span class="k">return</span> <span class="n">Qfalse</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="n">Qtrue</span><span class="p">;</span>
<span class="p">}</span>


<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_eqeq_approx</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">left_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">right_val</span><span class="p">)</span> <span class="p">{</span>

  <span class="n">afstruct</span><span class="o">*</span> <span class="n">left</span><span class="p">;</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">right</span><span class="p">;</span>

  <span class="n">dim_t</span> <span class="n">left_count</span><span class="p">;</span>
  <span class="n">dim_t</span> <span class="n">right_count</span><span class="p">;</span>

  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">left_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">left</span><span class="p">);</span>
  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">right_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">right</span><span class="p">);</span>

  <span class="n">af_get_elements</span><span class="p">(</span><span class="o">&amp;</span><span class="n">left_count</span><span class="p">,</span> <span class="n">left</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>
  <span class="n">af_get_elements</span><span class="p">(</span><span class="o">&amp;</span><span class="n">right_count</span><span class="p">,</span> <span class="n">right</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="k">if</span><span class="p">(</span><span class="n">left_count</span> <span class="o">!=</span> <span class="n">right_count</span><span class="p">){</span><span class="k">return</span> <span class="n">Qfalse</span><span class="p">;}</span>

  <span class="kt">float</span><span class="o">*</span> <span class="n">left_arr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">float</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">left_count</span> <span class="o">*</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">float</span><span class="p">));</span>
  <span class="n">af_get_data_ptr</span><span class="p">(</span><span class="n">left_arr</span><span class="p">,</span> <span class="n">left</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="kt">float</span><span class="o">*</span> <span class="n">right_arr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">float</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">left_count</span> <span class="o">*</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">float</span><span class="p">));</span>
  <span class="n">af_get_data_ptr</span><span class="p">(</span><span class="n">right_arr</span><span class="p">,</span> <span class="n">right</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="k">for</span> <span class="p">(</span><span class="n">dim_t</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">index</span> <span class="o">&lt;</span> <span class="n">left_count</span><span class="p">;</span> <span class="n">index</span><span class="o">++</span><span class="p">){</span>
    <span class="kt">float</span> <span class="n">diff</span> <span class="o">=</span> <span class="n">left_arr</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">-</span> <span class="n">right_arr</span><span class="p">[</span><span class="n">index</span><span class="p">];</span>
    <span class="k">if</span><span class="p">(</span><span class="n">diff</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">){</span><span class="n">diff</span> <span class="o">*=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;}</span>
    <span class="k">if</span><span class="p">(</span><span class="n">diff</span> <span class="o">&gt;</span> <span class="mf">1e-3</span><span class="p">){</span>
      <span class="k">return</span> <span class="n">Qfalse</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="n">Qtrue</span><span class="p">;</span>
<span class="p">}</span>

</code></pre></div></div>

<h1 id="algorithm-class">Algorithm class</h1>

<p>The Algorithm class contains of reduction methods like <code class="language-plaintext highlighter-rouge">sum</code>, <code class="language-plaintext highlighter-rouge">product</code>, <code class="language-plaintext highlighter-rouge">max</code>.
It contains singleton methods that takes an <code class="language-plaintext highlighter-rouge">Af_Array</code> as a parameter.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">Init_arrayfire</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">ArrayFire</span> <span class="o">=</span> <span class="n">rb_define_module</span><span class="p">(</span><span class="s">"ArrayFire"</span><span class="p">);</span>

  <span class="n">Algorithm</span> <span class="o">=</span> <span class="n">rb_define_class_under</span><span class="p">(</span><span class="n">ArrayFire</span><span class="p">,</span> <span class="s">"Algorithm"</span><span class="p">,</span> <span class="n">rb_cObject</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Algorithm</span><span class="p">,</span> <span class="s">"sum"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_sum</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Algorithm</span><span class="p">,</span> <span class="s">"sum_nan"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_sum_nan</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Algorithm</span><span class="p">,</span> <span class="s">"product"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_product</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Algorithm</span><span class="p">,</span> <span class="s">"product_nan"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_product_nan</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Algorithm</span><span class="p">,</span> <span class="s">"min"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_min</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Algorithm</span><span class="p">,</span> <span class="s">"max"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_max</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Algorithm</span><span class="p">,</span> <span class="s">"all_true"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_all_true</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Algorithm</span><span class="p">,</span> <span class="s">"any_true"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_any_true</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Algorithm</span><span class="p">,</span> <span class="s">"count"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_count</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Algorithm</span><span class="p">,</span> <span class="s">"sum_all"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_sum_all</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Algorithm</span><span class="p">,</span> <span class="s">"sum_nan_all"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_sum_nan_all</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Algorithm</span><span class="p">,</span> <span class="s">"product_all"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_product_all</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Algorithm</span><span class="p">,</span> <span class="s">"product_nan_all"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_product_nan_all</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Algorithm</span><span class="p">,</span> <span class="s">"min_all"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_min_all</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">Algorithm</span><span class="p">,</span> <span class="s">"max_all"</span><span class="p">,</span> <span class="p">(</span><span class="n">METHOD</span><span class="p">)</span><span class="n">arf_max_all</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">Algorithm#sum</code> expects an <code class="language-plaintext highlighter-rouge">Af_Array</code> and <code class="language-plaintext highlighter-rouge">dimension</code> as a prameter. It finds the sum of
all elements in the <code class="language-plaintext highlighter-rouge">Af_Array</code> along the specified <code class="language-plaintext highlighter-rouge">dimension</code>. However, <code class="language-plaintext highlighter-rouge">sum_all</code> finds the overall
sum of elements in an <code class="language-plaintext highlighter-rouge">Af_Array</code>.</p>

<p>If <code class="language-plaintext highlighter-rouge">NaN</code> is one of the element, we use <code class="language-plaintext highlighter-rouge">Af_Array#sum_nan</code> or <code class="language-plaintext highlighter-rouge">Af_Array#sum_nan_all</code> that just takes
an additional value as an input which replaces <code class="language-plaintext highlighter-rouge">NaN</code>.</p>

<p>So, now I can check if the bindings work successfully.</p>

<p>The implementation of <code class="language-plaintext highlighter-rouge">Algorithm#sum</code> and <code class="language-plaintext highlighter-rouge">Algorith#sum_all</code> is as follows:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_sum</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">array_val</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">dim_val</span><span class="p">){</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">input</span><span class="p">;</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">output</span> <span class="o">=</span> <span class="n">ALLOC</span><span class="p">(</span><span class="n">afstruct</span><span class="p">);</span>

  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">array_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span>

  <span class="n">af_sum</span><span class="p">(</span><span class="o">&amp;</span><span class="n">output</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">input</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">,</span> <span class="n">FIX2INT</span><span class="p">(</span><span class="n">dim_val</span><span class="p">));</span>

  <span class="k">return</span> <span class="n">Data_Wrap_Struct</span><span class="p">(</span><span class="n">CLASS_OF</span><span class="p">(</span><span class="n">array_val</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">arf_free</span><span class="p">,</span> <span class="n">output</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">arf_sum_all</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">array_val</span><span class="p">){</span>
  <span class="n">afstruct</span><span class="o">*</span> <span class="n">input</span><span class="p">;</span>
  <span class="kt">double</span> <span class="n">real_part</span><span class="p">,</span> <span class="n">imag_part</span><span class="p">;</span>

  <span class="n">Data_Get_Struct</span><span class="p">(</span><span class="n">array_val</span><span class="p">,</span> <span class="n">afstruct</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span>

  <span class="n">af_sum_all</span><span class="p">(</span><span class="o">&amp;</span><span class="n">real_part</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">imag_part</span><span class="p">,</span> <span class="n">input</span><span class="o">-&gt;</span><span class="n">carray</span><span class="p">);</span>

  <span class="k">return</span> <span class="n">DBL2NUM</span><span class="p">(</span><span class="n">real_part</span><span class="p">);</span>
<span class="p">}</span>

</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">Data_Get_Struct</code> takes an <code class="language-plaintext highlighter-rouge">Af_Array</code> value and unwraps it to a <code class="language-plaintext highlighter-rouge">af_array</code> struct.
Next, the ArrayFire C API <code class="language-plaintext highlighter-rouge">af_sum</code> or <code class="language-plaintext highlighter-rouge">af_sum_all</code> is called on the parameters. The
result is returned by converting it into a Ruby <code class="language-plaintext highlighter-rouge">VALUE</code>.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">rake</span> <span class="n">pry</span>
<span class="n">pry</span> <span class="o">-</span><span class="n">r</span> <span class="s1">'./lib/arrayfire.rb'</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">input</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Af_Array</span><span class="p">.</span><span class="nf">new</span> <span class="mi">2</span><span class="p">,</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">],</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="o">-</span><span class="mi">11</span><span class="p">,</span> <span class="mi">9</span> <span class="p">,</span> <span class="o">-</span><span class="mi">22</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span>

<span class="no">No</span> <span class="no">Name</span> <span class="no">Array</span>
<span class="p">[</span><span class="mi">3</span> <span class="mi">3</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">]</span>
    <span class="mf">4.0000</span>     <span class="mf">6.0000</span>   <span class="o">-</span><span class="mf">22.0000</span>
    <span class="mf">1.0000</span>   <span class="o">-</span><span class="mf">11.0000</span>    <span class="mf">11.0000</span>
    <span class="mf">5.0000</span>     <span class="mf">9.0000</span>     <span class="mf">1.0000</span>

<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x0000000176b938&gt;</span>
<span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">result</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Algorithm</span><span class="p">.</span><span class="nf">sum</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="c1">#&lt;ArrayFire::Af_Array:0x00000001810f50&gt;</span>
<span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">result</span><span class="p">.</span><span class="nf">elements</span>
<span class="o">=&gt;</span> <span class="p">[</span><span class="o">-</span><span class="mf">12.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">15.0</span><span class="p">]</span>
<span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="n">pry</span><span class="p">(</span><span class="n">main</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">result</span> <span class="o">=</span> <span class="no">ArrayFire</span><span class="o">::</span><span class="no">Algorithm</span><span class="p">.</span><span class="nf">sum_all</span><span class="p">(</span><span class="n">input</span><span class="p">)</span>
<span class="o">=&gt;</span> <span class="mf">4.0</span>

</code></pre></div></div>

<p>Voila! It works.</p>

<h1 id="conclusion">Conclusion</h1>

<p><strong>ArrayFire-rb</strong> has a test-suite and the Algorithm class. Some of the methods of <code class="language-plaintext highlighter-rouge">Algorithm</code> class
are missing and will be added soon.</p>

<p>In the next blog post, I will explain about the BLAS and LAPACK routines.</p>

<div id="disqus_thread"></div>
<script>
/**
* RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
* LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
*/
/*
var disqus_config = function () {
this.page.url = PAGE_URL; // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};
*/
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');

s.src = '//prasunanandblog.disqus.com/embed.js';

s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>]]></content><author><name>Prasun Anand</name></author><category term="arrayfire" /><summary type="html"><![CDATA[This post covers how I implemented the test-suite and Algorithm class for ArrayFire-rb using ArrayFire C API, and how to use Algorithm class methods with Af_Array.]]></summary></entry></feed>