<p>
As some of you may be aware, ArrayFire uses <a href="http://sandbox.arrayfire.com/performance-of-arrayfire-jit-code-generation/">Just In Time</a> compilation to combine many light weight functions into a single kernel launch.
This along with our <a href="http://arrayfire.org/docs/group__arrayfire__func.htm">easy-to-use API</a> allows users to not only quickly prototype their algorithms, but also get the best out of the underlying hardware.
</p>

<p>
This feature has been a old favorite among our users in the domains of finance and scientific simulation.
</p>

<p>
That said, ArrayFire v3.3 and earlier had a few limitations. Namely:
</p>
<ul class="org-ul">
<li>Multiple outputs with inter-dependent variables were generating multiple kernels.
</li>
<li>The number of operations per kernel was fairly limited by default.
</li>
</ul>

<p>
In the latest release of ArrayFire, we addressed these issues to get some pretty impressive numbers.
</p>

<p>
In the rest of the post, we use our <a href="https://github.com/arrayfire/arrayfire/blob/devel/examples/financial/black_scholes_options.cpp">BlackScholes example</a>, a commonly used mathematical model in finance, to show case the improvements.
</p>

<div id="outline-container-sec-1" class="outline-2">
<h2 id="sec-1">Performance Comparison to v3.3</h2>
<div class="outline-text-2" id="text-1">
<p>
BlackScholes model takes the following 5 inputs
</p>

<p>
Inputs:
</p>

<ul class="org-ul">
<li><code>S</code>: Stock price
</li>
<li><code>X</code>: Strike price
</li>
<li><code>R</code>: Risk free rate of interest
</li>
<li><code>V</code>: Volatility
</li>
<li><code>T</code>: Time to maturity
</li>
</ul>

<p>
and performs a long chain of element wise mathematical operations to generate the following 2 outputs.
</p>

<p>
Outputs:
</p>

<ul class="org-ul">
<li><code>C</code>: Call option
</li>
<li><code>P</code>: Put option
</li>
</ul>

<div class="org-src-container">

<pre class="src src-C++">array cnd(array x)
{
    // constants
    const float a1 =  0.254829592;
    const float a2 = -0.284496736;
    const float a3 =  1.421413741;
    const float a4 = -1.453152027;
    const float a5 =  1.061405429;
    const float p  =  0.3275911;
    const float sqrt2 = sqrt(2.0);

    // Save the sign of x
    array xSign = sign(x);

    x = abs(x) / sqrt2;

    // A&amp;S formula 7.1.26
    array t = 1.0f / (1.0f + p*x);
    array y = 1.0f + 0.5f * (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*exp(-x*x);

    return xSign * y + !xSign * (1 - y); // equivalent of (x &gt;= 0) ? y : (1 - y);
}

static void black_scholes(array&amp; C, array&amp; P,
                          const array&amp; S, const array&amp; X,
                          const array&amp; R, const array&amp; V,
                          const array&amp; T)
{
    // This function computes the call and put option prices based on
    // Black-Scholes Model

    // S = Underlying stock price
    // X = Strike Price
    // R = Risk free rate of interest
    // V = Volatility
    // T = Time to maturity

    array d1 = log(S / X);
    d1 = d1 + (R + (V*V)*0.5) * T;
    d1 = d1 / (V*sqrt(T));

    array d2 = d1 - (V*sqrt(T));

    array cnd_d1 = cnd(d1);
    array cnd_d2 = cnd(d2);

    C = S * cnd_d1  - (X * exp((-R)*T) * cnd_d2);
    P = X * exp((-R)*T) * (1 - cnd_d2) - (S * (1 - cnd_d1));
}
</pre>
</div>

<p>
Due to the nature of the model (both long chain of operations and multiple outputs), older versions of arrayfire were splitting up this single function call to multiple kernels.
</p>

<p>
To solve this issue, in the latest we
</p>
<ul class="org-ul">
<li>Enabled <code>af::eval</code> to hint ArrayFire's JIT compiler to combine inputs
</li>
<li>Changed the heuristics to increase the number of operations per kernel
</li>
</ul>

<div class="org-src-container">

<pre class="src src-C++">black_scholes(C, P, S, X, R, V, T);
eval(C, P); // Only change required for v3.4
</pre>
</div>

<p>
These changes resulted in dramatic performance improvements seen below.
</p>

<iframe width="574.52125" height="355.25250000000005" seamless frameborder="0" scrolling="no"
src="https://docs.google.com/spreadsheets/d/1o4C5KZ4B5he3Ac8mJ9Z6Z_N-hlATeJwhP-j6XJtbEPA/pubchart?oid=927257953&amp;format=interactive">
</iframe>
</div>
</div>
</div>