(8722,18673,'2015-12-03 19:49:54','2015-12-03 19:49:54','<title>Forge Visualizations!</title>\r\n<p>Arrayfire as a library aims to provide a robust and easy to use platform for high-performance, parallel and GPU computing.\r\nThe goal of <a href=\"https://github.com/arrayfire/forge\">Forge</a>, an OpenGL visualization library, is to provide equally robust visualizations that are interoperable between Arrayfire data-structures and an OpenGL context.</p>\r\n<p>Arrayfire provides wrapper functions that are designed to be a simple interface to visualize af::arrays. These functions perform various interoperability tasks. One in particular is that instead of wasting time copying and reformatting data from the GPU to the host and back to the GPU, we can draw directly from GPU-data to GPU-framebuffers, saving two memory copies!</p>\r\n<p>Let’s see exactly what visuals we can illuminate with forge and how Arrayfire anneals the data between the two libraries.</p>\r\n<h2><a id=\"Setup_17\"></a>Setup</h2>\r\n<p>Before we can call Forge functions, we need to set up the related “canvas” classes.\r\nForge functions are tied to the af::Window class. First let’s create a window:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int width = 512, height = 512;\r\naf::Window window(width, height, \"2D plot example title\");\r\n\r\ndo{\r\n\r\n//drawing functions here\r\n\r\n} while( !window.close() );</code></pre>\r\n<p>We also added a drawing loop, so now we can use Forge’s drawing functions to draw to the window. The drawing functions present in Forge are listed below.</p>\r\n<h2><a id=\"Rendering_Functions_35\"></a>Rendering Functions</h2>\r\n<p>Documentation for the rendering functions can be found <a href=\"http://sandbox.arrayfire.com/docs/group__gfx__func__draw.htm\">here</a> .</p>\r\n<h3><a id=\"Image_38\"></a>Image</h3>\r\n<p>The af::Window::image() function can be used to plot grayscale or color images. To plot a grayscale image a 2d array should be passed into the function.\r\nLet’s see this on a static noise example:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = constant(0, width, height);   //make a black image\r\narray random = randu(width, height);      //make random [0,1] distribution\r\n\r\nwindow.image(img);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise-262x300.png\" alt=\"Forge image plot of noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8710\" /></a></p>\r\n<p>Tweaking the previous example by giving our image a depth of 3 for the RGB values allows us to generate colorful noise:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = 255 * randu(width, height, 3);      //make random [0, 255] distribution\r\nwindow.image( img.as(u8) );</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise-262x300.png\" alt=\"Forge image plot of color noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8708\" /></a></p>\r\n<p>Note that Forge automatically handles any af::array type passed from Arrayfire. In the first example we passed in an image of floats in the range [0, 1]. In the last example we cast our array to an unsigned byte array with the range\r\n[0, 255]. The type-handling properties are consistent for all Forge drawing functions.</p>\r\n<h3><a id=\"Plot_63\"></a>Plot</h3>\r\n<p>The af::Window::plot() function visualizes an array as a 2d-line plot. Let’s see a simple example:</p>\r\n<pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray Y = sin(X);\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot-296x300.png\" alt=\"Forge 2d line plot of sin() function\" width=\"296\" height=\"300\" class=\"aligncenter size-medium wp-image-8714\" /></a>\r\nThe plot function has the signature:</p>\r\n<blockquote>\r\n<p><strong>void plot( const array &amp;X, const array &amp;Y, const char * const title = NULL );</strong></p>\r\n</blockquote>\r\n<p>Both the x and y coordinates of the points are required to plot. This allows for non-uniform, or parametric plots:</p>\r\n<pre><code class=\"language-{.cpp}\">array t = seq(0, 100, 0.01);\r\narray X = sin(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\narray Y = cos(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot-290x300.png\" alt=\"\" width=\"290\" height=\"300\" class=\"aligncenter size-medium wp-image-8707\" /></a></p>\r\n<h3><a id=\"Scatter_88\"></a>Scatter</h3>\r\n<p>The scatter() function visualizes an array as a 2d-scatter plot. Let’s see a example:</p><pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray noise = randn(X.dims(0)) /3.0f;\r\narray Y = sin(X) + noise;\r\nwindow.scatter(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter-300x228.png\" alt=\"Forge 2d scatter plot\" width=\"300\" height=\"228\" class=\"aligncenter size-medium wp-image-8715\" /></a></p>\r\n<p>The scatter function has the signature:</p>\r\n<blockquote>\r\n<p><strong>void scatter( const array &amp;X, const array &amp;Y, af::markerType marker=AF_MARKER_POINT, const char * const title = NULL);</strong></p>\r\n</blockquote>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point.\r\nIt can take on the values of:</p><pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Plot3_118\"></a>Plot3</h3>\r\n<p>The af::Window::plot3() function will plot a curve in 3d-space.\r\nIts signature is:</p>\r\n<blockquote>\r\n<p><strong>void plot3 (const array &amp;in, const char * title = NULL);</strong></p>\r\n</blockquote>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = seq(0.1f, 10.f, 0.01);\r\narray Y = sin(10 * Z) / Z;\r\narray X = cos(10 * Z) / Z;\r\n\r\narray Pts = join(1, X, Y, Z);\r\n//Pts can be passed in as a matrix in the from n x 3, 3 x n\r\n//or in the flattened xyz-triplet array with size 3n x 1\r\nwindow.plot3(Pts);\r\n//both of the following are equally valid\r\n//window.plot3(transpose(Pts));\r\n//window.plot3(flat(Pts));</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3-300x211.png\" alt=\"Forge 3d line plot\" width=\"300\" height=\"211\" class=\"aligncenter size-medium wp-image-8716\" /></a></p>\r\n<h3><a id=\"Histogram_140\"></a>Histogram</h3>\r\n<p>The af::Window::hist() function renders an input array as a histogram. In our example, the input array will be created with Arrayfire’s histogram() function, which actually counts and bins each sample. The output from histogram() can directly be fed into the af::Window::hist() rendering function.</p>\r\n<pre><code class=\"language-{.cpp}\">const int BINS = 128; SAMPLES = 9162;\r\narray norm = randn(SAMPLES);\r\narray hist_arr = histogram(norm, BINS);\r\n\r\nwin.hist(hist_arr, 0, BINS);</code></pre>\r\n<p>In addition to the histogram array with the number of samples in each bin, the af::Window::hist() function takes two additional parameters – the minimum and maximum values of all datapoints in the histogram array. This effectively sets the range of the binned data. The full signature of af::Window::hist() is:</p>\r\n<blockquote>\r\n<p><strong>void hist(const array &amp; X, const double minval, const double maxval, const char * const title = NULL);</strong></p>\r\n</blockquote>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram-300x256.png\" alt=\"Forge histogram plot\" width=\"300\" height=\"256\" class=\"aligncenter size-medium wp-image-8711\" /></a></p>\r\n<h3><a id=\"Scatter3_162\"></a>Scatter3</h3>\r\n<p>The scatter3() function visualizes an array as a 3d-scatter plot.\r\nIts signature is:</p>\r\n<blockquote>\r\n<p><strong>void scatter3 (const array &amp;in, af::markerType marker=AF_MARKER_POINT, const char * title = NULL);</strong></p>\r\n</blockquote>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3-300x208.png\" alt=\"Forge 3d scatter plot\" width=\"300\" height=\"208\" class=\"aligncenter size-medium wp-image-8712\" /></a></p>\r\n<pre><code class=\"language-{.cpp}\">array X = randn(300);\r\narray Y = randn(300);\r\narray Z = randn(300);\r\n\r\narray Pts = join(1, X, Y, Z);\r\nwindow.scatter3(Pts);</code></pre>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point. It can take on the values of:</p>\r\n<pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Surface_195\"></a>Surface</h3>\r\n<p>The af::Window::surface() function will plot af::arrays as a 3d surface.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = randu(21, 21);\r\nwindow.surface(Z, \"Random Surface\");    //equal to next function call\r\n//window.surface( seq(-1, 1, 0.1), seq(-1, 1, 0.1), Z, \"Random Surface\");</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface-300x269.png\" alt=\"Forge 3d surface() plot\" width=\"300\" height=\"269\" class=\"aligncenter size-medium wp-image-8713\" /></a>\r\nThere are two overloads for the af::Window::surface() function:</p>\r\n<blockquote>\r\n<p><strong>void surface (const array &amp; S, const char * const title )</strong>\r\n// Accepts a 2d matrix with the z values of the surface</p>\r\n</blockquote>\r\n<blockquote>\r\n<p><strong>void surface (const array &amp;xVals, const array &amp;yVals, const array &amp;S, const char * const title)</strong>\r\n// accepts additional vectors that define the x,y coordinates for the surface points.</p>\r\n</blockquote>\r\n<p>The second overload has two options for the x, y coordinate vectors. Assuming a surface grid of size <strong>m x n</strong>:</p>\r\n<ol>\r\n<li>Short vectors defining the spacing along each axis. Vectors will have sizes <strong>m x 1</strong> and <strong>n x 1</strong>.</li>\r\n<li>Vectors containing the coordinates of each and every point. Each of the vectors will have length <strong>mn x 1</strong>. This can be used for completely non-uniform or parametric surfaces.</li>\r\n</ol>\r\n<h2><a id=\"Conclusion_216\"></a>Conclusion</h2>\r\n<p>There is a fairly comprehensive collection of methods to visualize data in Arrayfire. Thanks to the high-performance gpu plotting library Forge, the provided Arrayfire functions not only make visualizations as simple as possible, but keep them as robust as the rest of the Arrayfire library.</p>\r\n','Visualizing af::array with Forge','','inherit','open','closed','','8698-revision-v1','','','2015-12-03 19:49:54','2015-12-03 19:49:54','',8698,'http://sandbox.arrayfire.com/8698-revision-v1/',0,'revision','',0),(8723,18673,'2015-12-03 19:50:15','2015-12-03 19:50:15','<p>Arrayfire as a library aims to provide a robust and easy to use platform for high-performance, parallel and GPU computing.\r\nThe goal of <a href=\"https://github.com/arrayfire/forge\">Forge</a>, an OpenGL visualization library, is to provide equally robust visualizations that are interoperable between Arrayfire data-structures and an OpenGL context.</p>\r\n<p>Arrayfire provides wrapper functions that are designed to be a simple interface to visualize af::arrays. These functions perform various interoperability tasks. One in particular is that instead of wasting time copying and reformatting data from the GPU to the host and back to the GPU, we can draw directly from GPU-data to GPU-framebuffers, saving two memory copies!</p>\r\n<p>Let’s see exactly what visuals we can illuminate with forge and how Arrayfire anneals the data between the two libraries.</p>\r\n<h2><a id=\"Setup_17\"></a>Setup</h2>\r\n<p>Before we can call Forge functions, we need to set up the related “canvas” classes.\r\nForge functions are tied to the af::Window class. First let’s create a window:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int width = 512, height = 512;\r\naf::Window window(width, height, \"2D plot example title\");\r\n\r\ndo{\r\n\r\n//drawing functions here\r\n\r\n} while( !window.close() );</code></pre>\r\n<p>We also added a drawing loop, so now we can use Forge’s drawing functions to draw to the window. The drawing functions present in Forge are listed below.</p>\r\n<h2><a id=\"Rendering_Functions_35\"></a>Rendering Functions</h2>\r\n<p>Documentation for the rendering functions can be found <a href=\"http://sandbox.arrayfire.com/docs/group__gfx__func__draw.htm\">here</a> .</p>\r\n<h3><a id=\"Image_38\"></a>Image</h3>\r\n<p>The af::Window::image() function can be used to plot grayscale or color images. To plot a grayscale image a 2d array should be passed into the function.\r\nLet’s see this on a static noise example:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = constant(0, width, height);   //make a black image\r\narray random = randu(width, height);      //make random [0,1] distribution\r\n\r\nwindow.image(img);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise-262x300.png\" alt=\"Forge image plot of noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8710\" /></a></p>\r\n<p>Tweaking the previous example by giving our image a depth of 3 for the RGB values allows us to generate colorful noise:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = 255 * randu(width, height, 3);      //make random [0, 255] distribution\r\nwindow.image( img.as(u8) );</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise-262x300.png\" alt=\"Forge image plot of color noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8708\" /></a></p>\r\n<p>Note that Forge automatically handles any af::array type passed from Arrayfire. In the first example we passed in an image of floats in the range [0, 1]. In the last example we cast our array to an unsigned byte array with the range\r\n[0, 255]. The type-handling properties are consistent for all Forge drawing functions.</p>\r\n<h3><a id=\"Plot_63\"></a>Plot</h3>\r\n<p>The af::Window::plot() function visualizes an array as a 2d-line plot. Let’s see a simple example:</p>\r\n<pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray Y = sin(X);\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot-296x300.png\" alt=\"Forge 2d line plot of sin() function\" width=\"296\" height=\"300\" class=\"aligncenter size-medium wp-image-8714\" /></a>\r\nThe plot function has the signature:</p>\r\n<blockquote>\r\n<p><strong>void plot( const array &amp;X, const array &amp;Y, const char * const title = NULL );</strong></p>\r\n</blockquote>\r\n<p>Both the x and y coordinates of the points are required to plot. This allows for non-uniform, or parametric plots:</p>\r\n<pre><code class=\"language-{.cpp}\">array t = seq(0, 100, 0.01);\r\narray X = sin(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\narray Y = cos(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot-290x300.png\" alt=\"\" width=\"290\" height=\"300\" class=\"aligncenter size-medium wp-image-8707\" /></a></p>\r\n<h3><a id=\"Scatter_88\"></a>Scatter</h3>\r\n<p>The scatter() function visualizes an array as a 2d-scatter plot. Let’s see a example:</p><pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray noise = randn(X.dims(0)) /3.0f;\r\narray Y = sin(X) + noise;\r\nwindow.scatter(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter-300x228.png\" alt=\"Forge 2d scatter plot\" width=\"300\" height=\"228\" class=\"aligncenter size-medium wp-image-8715\" /></a></p>\r\n<p>The scatter function has the signature:</p>\r\n<blockquote>\r\n<p><strong>void scatter( const array &amp;X, const array &amp;Y, af::markerType marker=AF_MARKER_POINT, const char * const title = NULL);</strong></p>\r\n</blockquote>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point.\r\nIt can take on the values of:</p><pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Plot3_118\"></a>Plot3</h3>\r\n<p>The af::Window::plot3() function will plot a curve in 3d-space.\r\nIts signature is:</p>\r\n<blockquote>\r\n<p><strong>void plot3 (const array &amp;in, const char * title = NULL);</strong></p>\r\n</blockquote>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = seq(0.1f, 10.f, 0.01);\r\narray Y = sin(10 * Z) / Z;\r\narray X = cos(10 * Z) / Z;\r\n\r\narray Pts = join(1, X, Y, Z);\r\n//Pts can be passed in as a matrix in the from n x 3, 3 x n\r\n//or in the flattened xyz-triplet array with size 3n x 1\r\nwindow.plot3(Pts);\r\n//both of the following are equally valid\r\n//window.plot3(transpose(Pts));\r\n//window.plot3(flat(Pts));</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3-300x211.png\" alt=\"Forge 3d line plot\" width=\"300\" height=\"211\" class=\"aligncenter size-medium wp-image-8716\" /></a></p>\r\n<h3><a id=\"Histogram_140\"></a>Histogram</h3>\r\n<p>The af::Window::hist() function renders an input array as a histogram. In our example, the input array will be created with Arrayfire’s histogram() function, which actually counts and bins each sample. The output from histogram() can directly be fed into the af::Window::hist() rendering function.</p>\r\n<pre><code class=\"language-{.cpp}\">const int BINS = 128; SAMPLES = 9162;\r\narray norm = randn(SAMPLES);\r\narray hist_arr = histogram(norm, BINS);\r\n\r\nwin.hist(hist_arr, 0, BINS);</code></pre>\r\n<p>In addition to the histogram array with the number of samples in each bin, the af::Window::hist() function takes two additional parameters – the minimum and maximum values of all datapoints in the histogram array. This effectively sets the range of the binned data. The full signature of af::Window::hist() is:</p>\r\n<blockquote>\r\n<p><strong>void hist(const array &amp; X, const double minval, const double maxval, const char * const title = NULL);</strong></p>\r\n</blockquote>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram-300x256.png\" alt=\"Forge histogram plot\" width=\"300\" height=\"256\" class=\"aligncenter size-medium wp-image-8711\" /></a></p>\r\n<h3><a id=\"Scatter3_162\"></a>Scatter3</h3>\r\n<p>The scatter3() function visualizes an array as a 3d-scatter plot.\r\nIts signature is:</p>\r\n<blockquote>\r\n<p><strong>void scatter3 (const array &amp;in, af::markerType marker=AF_MARKER_POINT, const char * title = NULL);</strong></p>\r\n</blockquote>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3-300x208.png\" alt=\"Forge 3d scatter plot\" width=\"300\" height=\"208\" class=\"aligncenter size-medium wp-image-8712\" /></a></p>\r\n<pre><code class=\"language-{.cpp}\">array X = randn(300);\r\narray Y = randn(300);\r\narray Z = randn(300);\r\n\r\narray Pts = join(1, X, Y, Z);\r\nwindow.scatter3(Pts);</code></pre>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point. It can take on the values of:</p>\r\n<pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Surface_195\"></a>Surface</h3>\r\n<p>The af::Window::surface() function will plot af::arrays as a 3d surface.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = randu(21, 21);\r\nwindow.surface(Z, \"Random Surface\");    //equal to next function call\r\n//window.surface( seq(-1, 1, 0.1), seq(-1, 1, 0.1), Z, \"Random Surface\");</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface-300x269.png\" alt=\"Forge 3d surface() plot\" width=\"300\" height=\"269\" class=\"aligncenter size-medium wp-image-8713\" /></a>\r\nThere are two overloads for the af::Window::surface() function:</p>\r\n<blockquote>\r\n<p><strong>void surface (const array &amp; S, const char * const title )</strong>\r\n// Accepts a 2d matrix with the z values of the surface</p>\r\n</blockquote>\r\n<blockquote>\r\n<p><strong>void surface (const array &amp;xVals, const array &amp;yVals, const array &amp;S, const char * const title)</strong>\r\n// accepts additional vectors that define the x,y coordinates for the surface points.</p>\r\n</blockquote>\r\n<p>The second overload has two options for the x, y coordinate vectors. Assuming a surface grid of size <strong>m x n</strong>:</p>\r\n<ol>\r\n<li>Short vectors defining the spacing along each axis. Vectors will have sizes <strong>m x 1</strong> and <strong>n x 1</strong>.</li>\r\n<li>Vectors containing the coordinates of each and every point. Each of the vectors will have length <strong>mn x 1</strong>. This can be used for completely non-uniform or parametric surfaces.</li>\r\n</ol>\r\n<h2><a id=\"Conclusion_216\"></a>Conclusion</h2>\r\n<p>There is a fairly comprehensive collection of methods to visualize data in Arrayfire. Thanks to the high-performance gpu plotting library Forge, the provided Arrayfire functions not only make visualizations as simple as possible, but keep them as robust as the rest of the Arrayfire library.</p>\r\n','Visualizing af::array with Forge','','inherit','open','closed','','8698-revision-v1','','','2015-12-03 19:50:15','2015-12-03 19:50:15','',8698,'http://sandbox.arrayfire.com/8698-revision-v1/',0,'revision','',0),(8724,18673,'2015-12-03 19:54:59','2015-12-03 19:54:59','<p>Arrayfire as a library aims to provide a robust and easy to use platform for high-performance, parallel and GPU computing.\r\nThe goal of <a href=\"https://github.com/arrayfire/forge\">Forge</a>, an OpenGL visualization library, is to provide equally robust visualizations that are interoperable between Arrayfire data-structures and an OpenGL context.</p>\r\n<p>Arrayfire provides wrapper functions that are designed to be a simple interface to visualize af::arrays. These functions perform various interoperability tasks. One in particular is that instead of wasting time copying and reformatting data from the GPU to the host and back to the GPU, we can draw directly from GPU-data to GPU-framebuffers, saving two memory copies!</p>\r\n<p>Let’s see exactly what visuals we can illuminate with forge and how Arrayfire anneals the data between the two libraries.</p>\r\n<h2><a id=\"Setup_17\"></a>Setup</h2>\r\n<p>Before we can call Forge functions, we need to set up the related “canvas” classes.\r\nForge functions are tied to the af::Window class. First let’s create a window:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int width = 512, height = 512;\r\naf::Window window(width, height, \"2D plot example title\");\r\n\r\ndo{\r\n\r\n//drawing functions here\r\n\r\n} while( !window.close() );</code></pre>\r\n<p>We also added a drawing loop, so now we can use Forge’s drawing functions to draw to the window. The drawing functions present in Forge are listed below.</p>\r\n<h2><a id=\"Rendering_Functions_35\"></a>Rendering Functions</h2>\r\n<p>Documentation for the rendering functions can be found <a href=\"http://sandbox.arrayfire.com/docs/group__gfx__func__draw.htm\">here</a> .</p>\r\n<h3><a id=\"Image_38\"></a>Image</h3>\r\n<p>The af::Window::image() function can be used to plot grayscale or color images. To plot a grayscale image a 2d array should be passed into the function.\r\nLet’s see this on a static noise example:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = constant(0, width, height);   //make a black image\r\narray random = randu(width, height);      //make random [0,1] distribution\r\n\r\nwindow.image(img);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise-262x300.png\" alt=\"Forge image plot of noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8710\" /></a></p>\r\n<p>Tweaking the previous example by giving our image a depth of 3 for the RGB values allows us to generate colorful noise:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = 255 * randu(width, height, 3);      //make random [0, 255] distribution\r\nwindow.image( img.as(u8) );</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise-262x300.png\" alt=\"Forge image plot of color noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8708\" /></a></p>\r\n<p>Note that Forge automatically handles any af::array type passed from Arrayfire. In the first example we passed in an image of floats in the range [0, 1]. In the last example we cast our array to an unsigned byte array with the range\r\n[0, 255]. The type-handling properties are consistent for all Forge drawing functions.</p>\r\n<h3><a id=\"Plot_63\"></a>Plot</h3>\r\n<p>The af::Window::plot() function visualizes an array as a 2d-line plot. Let’s see a simple example:</p>\r\n<pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray Y = sin(X);\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot-296x300.png\" alt=\"Forge 2d line plot of sin() function\" width=\"296\" height=\"300\" class=\"aligncenter size-medium wp-image-8714\" /></a>\r\nThe plot function has the signature:</p>\r\n<blockquote>\r\n<p><code>void plot( const array &amp;X, const array &amp;Y, const char * const title = NULL );</code></p>\r\n</blockquote>\r\n<p>Both the x and y coordinates of the points are required to plot. This allows for non-uniform, or parametric plots:</p>\r\n<pre><code class=\"language-{.cpp}\">array t = seq(0, 100, 0.01);\r\narray X = sin(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\narray Y = cos(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot-290x300.png\" alt=\"\" width=\"290\" height=\"300\" class=\"aligncenter size-medium wp-image-8707\" /></a></p>\r\n<h3><a id=\"Scatter_88\"></a>Scatter</h3>\r\n<p>The scatter() function visualizes an array as a 2d-scatter plot. Let’s see a example:</p><pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray noise = randn(X.dims(0)) /3.0f;\r\narray Y = sin(X) + noise;\r\nwindow.scatter(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter-300x228.png\" alt=\"Forge 2d scatter plot\" width=\"300\" height=\"228\" class=\"aligncenter size-medium wp-image-8715\" /></a></p>\r\n<p>The scatter function has the signature:</p>\r\n<blockquote>\r\n<p><strong>void scatter( const array &amp;X, const array &amp;Y, af::markerType marker=AF_MARKER_POINT, const char * const title = NULL);</strong></p>\r\n</blockquote>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point.\r\nIt can take on the values of:</p><pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Plot3_118\"></a>Plot3</h3>\r\n<p>The af::Window::plot3() function will plot a curve in 3d-space.\r\nIts signature is:</p>\r\n<blockquote>\r\n<p><strong>void plot3 (const array &amp;in, const char * title = NULL);</strong></p>\r\n</blockquote>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = seq(0.1f, 10.f, 0.01);\r\narray Y = sin(10 * Z) / Z;\r\narray X = cos(10 * Z) / Z;\r\n\r\narray Pts = join(1, X, Y, Z);\r\n//Pts can be passed in as a matrix in the from n x 3, 3 x n\r\n//or in the flattened xyz-triplet array with size 3n x 1\r\nwindow.plot3(Pts);\r\n//both of the following are equally valid\r\n//window.plot3(transpose(Pts));\r\n//window.plot3(flat(Pts));</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3-300x211.png\" alt=\"Forge 3d line plot\" width=\"300\" height=\"211\" class=\"aligncenter size-medium wp-image-8716\" /></a></p>\r\n<h3><a id=\"Histogram_140\"></a>Histogram</h3>\r\n<p>The af::Window::hist() function renders an input array as a histogram. In our example, the input array will be created with Arrayfire’s histogram() function, which actually counts and bins each sample. The output from histogram() can directly be fed into the af::Window::hist() rendering function.</p>\r\n<pre><code class=\"language-{.cpp}\">const int BINS = 128; SAMPLES = 9162;\r\narray norm = randn(SAMPLES);\r\narray hist_arr = histogram(norm, BINS);\r\n\r\nwin.hist(hist_arr, 0, BINS);</code></pre>\r\n<p>In addition to the histogram array with the number of samples in each bin, the af::Window::hist() function takes two additional parameters – the minimum and maximum values of all datapoints in the histogram array. This effectively sets the range of the binned data. The full signature of af::Window::hist() is:</p>\r\n<blockquote>\r\n<p><strong>void hist(const array &amp; X, const double minval, const double maxval, const char * const title = NULL);</strong></p>\r\n</blockquote>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram-300x256.png\" alt=\"Forge histogram plot\" width=\"300\" height=\"256\" class=\"aligncenter size-medium wp-image-8711\" /></a></p>\r\n<h3><a id=\"Scatter3_162\"></a>Scatter3</h3>\r\n<p>The scatter3() function visualizes an array as a 3d-scatter plot.\r\nIts signature is:</p>\r\n<blockquote>\r\n<p><strong>void scatter3 (const array &amp;in, af::markerType marker=AF_MARKER_POINT, const char * title = NULL);</strong></p>\r\n</blockquote>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3-300x208.png\" alt=\"Forge 3d scatter plot\" width=\"300\" height=\"208\" class=\"aligncenter size-medium wp-image-8712\" /></a></p>\r\n<pre><code class=\"language-{.cpp}\">array X = randn(300);\r\narray Y = randn(300);\r\narray Z = randn(300);\r\n\r\narray Pts = join(1, X, Y, Z);\r\nwindow.scatter3(Pts);</code></pre>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point. It can take on the values of:</p>\r\n<pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Surface_195\"></a>Surface</h3>\r\n<p>The af::Window::surface() function will plot af::arrays as a 3d surface.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = randu(21, 21);\r\nwindow.surface(Z, \"Random Surface\");    //equal to next function call\r\n//window.surface( seq(-1, 1, 0.1), seq(-1, 1, 0.1), Z, \"Random Surface\");</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface-300x269.png\" alt=\"Forge 3d surface() plot\" width=\"300\" height=\"269\" class=\"aligncenter size-medium wp-image-8713\" /></a>\r\nThere are two overloads for the af::Window::surface() function:</p>\r\n<blockquote>\r\n<p><strong>void surface (const array &amp; S, const char * const title )</strong>\r\n// Accepts a 2d matrix with the z values of the surface</p>\r\n</blockquote>\r\n<blockquote>\r\n<p><strong>void surface (const array &amp;xVals, const array &amp;yVals, const array &amp;S, const char * const title)</strong>\r\n// accepts additional vectors that define the x,y coordinates for the surface points.</p>\r\n</blockquote>\r\n<p>The second overload has two options for the x, y coordinate vectors. Assuming a surface grid of size <strong>m x n</strong>:</p>\r\n<ol>\r\n<li>Short vectors defining the spacing along each axis. Vectors will have sizes <strong>m x 1</strong> and <strong>n x 1</strong>.</li>\r\n<li>Vectors containing the coordinates of each and every point. Each of the vectors will have length <strong>mn x 1</strong>. This can be used for completely non-uniform or parametric surfaces.</li>\r\n</ol>\r\n<h2><a id=\"Conclusion_216\"></a>Conclusion</h2>\r\n<p>There is a fairly comprehensive collection of methods to visualize data in Arrayfire. Thanks to the high-performance gpu plotting library Forge, the provided Arrayfire functions not only make visualizations as simple as possible, but keep them as robust as the rest of the Arrayfire library.</p>\r\n','Visualizing af::array with Forge','','inherit','open','closed','','8698-revision-v1','','','2015-12-03 19:54:59','2015-12-03 19:54:59','',8698,'http://sandbox.arrayfire.com/8698-revision-v1/',0,'revision','',0),(8725,18673,'2015-12-03 19:55:43','2015-12-03 19:55:43','<p>Arrayfire as a library aims to provide a robust and easy to use platform for high-performance, parallel and GPU computing.\r\nThe goal of <a href=\"https://github.com/arrayfire/forge\">Forge</a>, an OpenGL visualization library, is to provide equally robust visualizations that are interoperable between Arrayfire data-structures and an OpenGL context.</p>\r\n<p>Arrayfire provides wrapper functions that are designed to be a simple interface to visualize af::arrays. These functions perform various interoperability tasks. One in particular is that instead of wasting time copying and reformatting data from the GPU to the host and back to the GPU, we can draw directly from GPU-data to GPU-framebuffers, saving two memory copies!</p>\r\n<p>Let’s see exactly what visuals we can illuminate with forge and how Arrayfire anneals the data between the two libraries.</p>\r\n<h2><a id=\"Setup_17\"></a>Setup</h2>\r\n<p>Before we can call Forge functions, we need to set up the related “canvas” classes.\r\nForge functions are tied to the af::Window class. First let’s create a window:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int width = 512, height = 512;\r\naf::Window window(width, height, \"2D plot example title\");\r\n\r\ndo{\r\n\r\n//drawing functions here\r\n\r\n} while( !window.close() );</code></pre>\r\n<p>We also added a drawing loop, so now we can use Forge’s drawing functions to draw to the window. The drawing functions present in Forge are listed below.</p>\r\n<h2><a id=\"Rendering_Functions_35\"></a>Rendering Functions</h2>\r\n<p>Documentation for the rendering functions can be found <a href=\"http://sandbox.arrayfire.com/docs/group__gfx__func__draw.htm\">here</a> .</p>\r\n<h3><a id=\"Image_38\"></a>Image</h3>\r\n<p>The af::Window::image() function can be used to plot grayscale or color images. To plot a grayscale image a 2d array should be passed into the function.\r\nLet’s see this on a static noise example:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = constant(0, width, height);   //make a black image\r\narray random = randu(width, height);      //make random [0,1] distribution\r\n\r\nwindow.image(img);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise-262x300.png\" alt=\"Forge image plot of noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8710\" /></a></p>\r\n<p>Tweaking the previous example by giving our image a depth of 3 for the RGB values allows us to generate colorful noise:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = 255 * randu(width, height, 3);      //make random [0, 255] distribution\r\nwindow.image( img.as(u8) );</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise-262x300.png\" alt=\"Forge image plot of color noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8708\" /></a></p>\r\n<p>Note that Forge automatically handles any af::array type passed from Arrayfire. In the first example we passed in an image of floats in the range [0, 1]. In the last example we cast our array to an unsigned byte array with the range\r\n[0, 255]. The type-handling properties are consistent for all Forge drawing functions.</p>\r\n<h3><a id=\"Plot_63\"></a>Plot</h3>\r\n<p>The af::Window::plot() function visualizes an array as a 2d-line plot. Let’s see a simple example:</p>\r\n<pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray Y = sin(X);\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot-296x300.png\" alt=\"Forge 2d line plot of sin() function\" width=\"296\" height=\"300\" class=\"aligncenter size-medium wp-image-8714\" /></a>\r\nThe plot function has the signature:</p>\r\n<p><strong>void plot( const array &amp;X, const array &amp;Y, const char * const title = NULL );</strong></p>\r\n<p>Both the x and y coordinates of the points are required to plot. This allows for non-uniform, or parametric plots:</p>\r\n<pre><code class=\"language-{.cpp}\">array t = seq(0, 100, 0.01);\r\narray X = sin(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\narray Y = cos(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot-290x300.png\" alt=\"\" width=\"290\" height=\"300\" class=\"aligncenter size-medium wp-image-8707\" /></a></p>\r\n<h3><a id=\"Scatter_88\"></a>Scatter</h3>\r\n<p>The scatter() function visualizes an array as a 2d-scatter plot. Let’s see a example:</p><pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray noise = randn(X.dims(0)) /3.0f;\r\narray Y = sin(X) + noise;\r\nwindow.scatter(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter-300x228.png\" alt=\"Forge 2d scatter plot\" width=\"300\" height=\"228\" class=\"aligncenter size-medium wp-image-8715\" /></a></p>\r\n<p>The scatter function has the signature:</p>\r\n<blockquote>\r\n<p><strong>void scatter( const array &amp;X, const array &amp;Y, af::markerType marker=AF_MARKER_POINT, const char * const title = NULL);</strong></p>\r\n</blockquote>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point.\r\nIt can take on the values of:</p><pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Plot3_118\"></a>Plot3</h3>\r\n<p>The af::Window::plot3() function will plot a curve in 3d-space.\r\nIts signature is:</p>\r\n<blockquote>\r\n<p><strong>void plot3 (const array &amp;in, const char * title = NULL);</strong></p>\r\n</blockquote>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = seq(0.1f, 10.f, 0.01);\r\narray Y = sin(10 * Z) / Z;\r\narray X = cos(10 * Z) / Z;\r\n\r\narray Pts = join(1, X, Y, Z);\r\n//Pts can be passed in as a matrix in the from n x 3, 3 x n\r\n//or in the flattened xyz-triplet array with size 3n x 1\r\nwindow.plot3(Pts);\r\n//both of the following are equally valid\r\n//window.plot3(transpose(Pts));\r\n//window.plot3(flat(Pts));</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3-300x211.png\" alt=\"Forge 3d line plot\" width=\"300\" height=\"211\" class=\"aligncenter size-medium wp-image-8716\" /></a></p>\r\n<h3><a id=\"Histogram_140\"></a>Histogram</h3>\r\n<p>The af::Window::hist() function renders an input array as a histogram. In our example, the input array will be created with Arrayfire’s histogram() function, which actually counts and bins each sample. The output from histogram() can directly be fed into the af::Window::hist() rendering function.</p>\r\n<pre><code class=\"language-{.cpp}\">const int BINS = 128; SAMPLES = 9162;\r\narray norm = randn(SAMPLES);\r\narray hist_arr = histogram(norm, BINS);\r\n\r\nwin.hist(hist_arr, 0, BINS);</code></pre>\r\n<p>In addition to the histogram array with the number of samples in each bin, the af::Window::hist() function takes two additional parameters – the minimum and maximum values of all datapoints in the histogram array. This effectively sets the range of the binned data. The full signature of af::Window::hist() is:</p>\r\n<blockquote>\r\n<p><strong>void hist(const array &amp; X, const double minval, const double maxval, const char * const title = NULL);</strong></p>\r\n</blockquote>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram-300x256.png\" alt=\"Forge histogram plot\" width=\"300\" height=\"256\" class=\"aligncenter size-medium wp-image-8711\" /></a></p>\r\n<h3><a id=\"Scatter3_162\"></a>Scatter3</h3>\r\n<p>The scatter3() function visualizes an array as a 3d-scatter plot.\r\nIts signature is:</p>\r\n<blockquote>\r\n<p><strong>void scatter3 (const array &amp;in, af::markerType marker=AF_MARKER_POINT, const char * title = NULL);</strong></p>\r\n</blockquote>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3-300x208.png\" alt=\"Forge 3d scatter plot\" width=\"300\" height=\"208\" class=\"aligncenter size-medium wp-image-8712\" /></a></p>\r\n<pre><code class=\"language-{.cpp}\">array X = randn(300);\r\narray Y = randn(300);\r\narray Z = randn(300);\r\n\r\narray Pts = join(1, X, Y, Z);\r\nwindow.scatter3(Pts);</code></pre>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point. It can take on the values of:</p>\r\n<pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Surface_195\"></a>Surface</h3>\r\n<p>The af::Window::surface() function will plot af::arrays as a 3d surface.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = randu(21, 21);\r\nwindow.surface(Z, \"Random Surface\");    //equal to next function call\r\n//window.surface( seq(-1, 1, 0.1), seq(-1, 1, 0.1), Z, \"Random Surface\");</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface-300x269.png\" alt=\"Forge 3d surface() plot\" width=\"300\" height=\"269\" class=\"aligncenter size-medium wp-image-8713\" /></a>\r\nThere are two overloads for the af::Window::surface() function:</p>\r\n<blockquote>\r\n<p><strong>void surface (const array &amp; S, const char * const title )</strong>\r\n// Accepts a 2d matrix with the z values of the surface</p>\r\n</blockquote>\r\n<blockquote>\r\n<p><strong>void surface (const array &amp;xVals, const array &amp;yVals, const array &amp;S, const char * const title)</strong>\r\n// accepts additional vectors that define the x,y coordinates for the surface points.</p>\r\n</blockquote>\r\n<p>The second overload has two options for the x, y coordinate vectors. Assuming a surface grid of size <strong>m x n</strong>:</p>\r\n<ol>\r\n<li>Short vectors defining the spacing along each axis. Vectors will have sizes <strong>m x 1</strong> and <strong>n x 1</strong>.</li>\r\n<li>Vectors containing the coordinates of each and every point. Each of the vectors will have length <strong>mn x 1</strong>. This can be used for completely non-uniform or parametric surfaces.</li>\r\n</ol>\r\n<h2><a id=\"Conclusion_216\"></a>Conclusion</h2>\r\n<p>There is a fairly comprehensive collection of methods to visualize data in Arrayfire. Thanks to the high-performance gpu plotting library Forge, the provided Arrayfire functions not only make visualizations as simple as possible, but keep them as robust as the rest of the Arrayfire library.</p>\r\n','Visualizing af::array with Forge','','inherit','open','closed','','8698-revision-v1','','','2015-12-03 19:55:43','2015-12-03 19:55:43','',8698,'http://sandbox.arrayfire.com/8698-revision-v1/',0,'revision','',0),(8726,18673,'2015-12-03 19:56:19','2015-12-03 19:56:19','<p>Arrayfire as a library aims to provide a robust and easy to use platform for high-performance, parallel and GPU computing.\r\nThe goal of <a href=\"https://github.com/arrayfire/forge\">Forge</a>, an OpenGL visualization library, is to provide equally robust visualizations that are interoperable between Arrayfire data-structures and an OpenGL context.</p>\r\n<p>Arrayfire provides wrapper functions that are designed to be a simple interface to visualize af::arrays. These functions perform various interoperability tasks. One in particular is that instead of wasting time copying and reformatting data from the GPU to the host and back to the GPU, we can draw directly from GPU-data to GPU-framebuffers, saving two memory copies!</p>\r\n<p>Let’s see exactly what visuals we can illuminate with forge and how Arrayfire anneals the data between the two libraries.</p>\r\n<h2><a id=\"Setup_17\"></a>Setup</h2>\r\n<p>Before we can call Forge functions, we need to set up the related “canvas” classes.\r\nForge functions are tied to the af::Window class. First let’s create a window:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int width = 512, height = 512;\r\naf::Window window(width, height, \"2D plot example title\");\r\n\r\ndo{\r\n\r\n//drawing functions here\r\n\r\n} while( !window.close() );</code></pre>\r\n<p>We also added a drawing loop, so now we can use Forge’s drawing functions to draw to the window. The drawing functions present in Forge are listed below.</p>\r\n<h2><a id=\"Rendering_Functions_35\"></a>Rendering Functions</h2>\r\n<p>Documentation for the rendering functions can be found <a href=\"http://sandbox.arrayfire.com/docs/group__gfx__func__draw.htm\">here</a> .</p>\r\n<h3><a id=\"Image_38\"></a>Image</h3>\r\n<p>The af::Window::image() function can be used to plot grayscale or color images. To plot a grayscale image a 2d array should be passed into the function.\r\nLet’s see this on a static noise example:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = constant(0, width, height);   //make a black image\r\narray random = randu(width, height);      //make random [0,1] distribution\r\n\r\nwindow.image(img);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise-262x300.png\" alt=\"Forge image plot of noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8710\" /></a></p>\r\n<p>Tweaking the previous example by giving our image a depth of 3 for the RGB values allows us to generate colorful noise:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = 255 * randu(width, height, 3);      //make random [0, 255] distribution\r\nwindow.image( img.as(u8) );</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise-262x300.png\" alt=\"Forge image plot of color noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8708\" /></a></p>\r\n<p>Note that Forge automatically handles any af::array type passed from Arrayfire. In the first example we passed in an image of floats in the range [0, 1]. In the last example we cast our array to an unsigned byte array with the range\r\n[0, 255]. The type-handling properties are consistent for all Forge drawing functions.</p>\r\n<h3><a id=\"Plot_63\"></a>Plot</h3>\r\n<p>The af::Window::plot() function visualizes an array as a 2d-line plot. Let’s see a simple example:</p>\r\n<pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray Y = sin(X);\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot-296x300.png\" alt=\"Forge 2d line plot of sin() function\" width=\"296\" height=\"300\" class=\"aligncenter size-medium wp-image-8714\" /></a>\r\nThe plot function has the signature:</p>\r\n<p><code>void plot( const array &amp;X, const array &amp;Y, const char * const title = NULL );</code></p>\r\n<p>Both the x and y coordinates of the points are required to plot. This allows for non-uniform, or parametric plots:</p>\r\n<pre><code class=\"language-{.cpp}\">array t = seq(0, 100, 0.01);\r\narray X = sin(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\narray Y = cos(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot-290x300.png\" alt=\"\" width=\"290\" height=\"300\" class=\"aligncenter size-medium wp-image-8707\" /></a></p>\r\n<h3><a id=\"Scatter_88\"></a>Scatter</h3>\r\n<p>The scatter() function visualizes an array as a 2d-scatter plot. Let’s see a example:</p><pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray noise = randn(X.dims(0)) /3.0f;\r\narray Y = sin(X) + noise;\r\nwindow.scatter(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter-300x228.png\" alt=\"Forge 2d scatter plot\" width=\"300\" height=\"228\" class=\"aligncenter size-medium wp-image-8715\" /></a></p>\r\n<p>The scatter function has the signature:</p>\r\n<blockquote>\r\n<p><strong>void scatter( const array &amp;X, const array &amp;Y, af::markerType marker=AF_MARKER_POINT, const char * const title = NULL);</strong></p>\r\n</blockquote>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point.\r\nIt can take on the values of:</p><pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Plot3_118\"></a>Plot3</h3>\r\n<p>The af::Window::plot3() function will plot a curve in 3d-space.\r\nIts signature is:</p>\r\n<blockquote>\r\n<p><strong>void plot3 (const array &amp;in, const char * title = NULL);</strong></p>\r\n</blockquote>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = seq(0.1f, 10.f, 0.01);\r\narray Y = sin(10 * Z) / Z;\r\narray X = cos(10 * Z) / Z;\r\n\r\narray Pts = join(1, X, Y, Z);\r\n//Pts can be passed in as a matrix in the from n x 3, 3 x n\r\n//or in the flattened xyz-triplet array with size 3n x 1\r\nwindow.plot3(Pts);\r\n//both of the following are equally valid\r\n//window.plot3(transpose(Pts));\r\n//window.plot3(flat(Pts));</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3-300x211.png\" alt=\"Forge 3d line plot\" width=\"300\" height=\"211\" class=\"aligncenter size-medium wp-image-8716\" /></a></p>\r\n<h3><a id=\"Histogram_140\"></a>Histogram</h3>\r\n<p>The af::Window::hist() function renders an input array as a histogram. In our example, the input array will be created with Arrayfire’s histogram() function, which actually counts and bins each sample. The output from histogram() can directly be fed into the af::Window::hist() rendering function.</p>\r\n<pre><code class=\"language-{.cpp}\">const int BINS = 128; SAMPLES = 9162;\r\narray norm = randn(SAMPLES);\r\narray hist_arr = histogram(norm, BINS);\r\n\r\nwin.hist(hist_arr, 0, BINS);</code></pre>\r\n<p>In addition to the histogram array with the number of samples in each bin, the af::Window::hist() function takes two additional parameters – the minimum and maximum values of all datapoints in the histogram array. This effectively sets the range of the binned data. The full signature of af::Window::hist() is:</p>\r\n<blockquote>\r\n<p><strong>void hist(const array &amp; X, const double minval, const double maxval, const char * const title = NULL);</strong></p>\r\n</blockquote>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram-300x256.png\" alt=\"Forge histogram plot\" width=\"300\" height=\"256\" class=\"aligncenter size-medium wp-image-8711\" /></a></p>\r\n<h3><a id=\"Scatter3_162\"></a>Scatter3</h3>\r\n<p>The scatter3() function visualizes an array as a 3d-scatter plot.\r\nIts signature is:</p>\r\n<blockquote>\r\n<p><strong>void scatter3 (const array &amp;in, af::markerType marker=AF_MARKER_POINT, const char * title = NULL);</strong></p>\r\n</blockquote>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3-300x208.png\" alt=\"Forge 3d scatter plot\" width=\"300\" height=\"208\" class=\"aligncenter size-medium wp-image-8712\" /></a></p>\r\n<pre><code class=\"language-{.cpp}\">array X = randn(300);\r\narray Y = randn(300);\r\narray Z = randn(300);\r\n\r\narray Pts = join(1, X, Y, Z);\r\nwindow.scatter3(Pts);</code></pre>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point. It can take on the values of:</p>\r\n<pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Surface_195\"></a>Surface</h3>\r\n<p>The af::Window::surface() function will plot af::arrays as a 3d surface.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = randu(21, 21);\r\nwindow.surface(Z, \"Random Surface\");    //equal to next function call\r\n//window.surface( seq(-1, 1, 0.1), seq(-1, 1, 0.1), Z, \"Random Surface\");</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface-300x269.png\" alt=\"Forge 3d surface() plot\" width=\"300\" height=\"269\" class=\"aligncenter size-medium wp-image-8713\" /></a>\r\nThere are two overloads for the af::Window::surface() function:</p>\r\n<blockquote>\r\n<p><strong>void surface (const array &amp; S, const char * const title )</strong>\r\n// Accepts a 2d matrix with the z values of the surface</p>\r\n</blockquote>\r\n<blockquote>\r\n<p><strong>void surface (const array &amp;xVals, const array &amp;yVals, const array &amp;S, const char * const title)</strong>\r\n// accepts additional vectors that define the x,y coordinates for the surface points.</p>\r\n</blockquote>\r\n<p>The second overload has two options for the x, y coordinate vectors. Assuming a surface grid of size <strong>m x n</strong>:</p>\r\n<ol>\r\n<li>Short vectors defining the spacing along each axis. Vectors will have sizes <strong>m x 1</strong> and <strong>n x 1</strong>.</li>\r\n<li>Vectors containing the coordinates of each and every point. Each of the vectors will have length <strong>mn x 1</strong>. This can be used for completely non-uniform or parametric surfaces.</li>\r\n</ol>\r\n<h2><a id=\"Conclusion_216\"></a>Conclusion</h2>\r\n<p>There is a fairly comprehensive collection of methods to visualize data in Arrayfire. Thanks to the high-performance gpu plotting library Forge, the provided Arrayfire functions not only make visualizations as simple as possible, but keep them as robust as the rest of the Arrayfire library.</p>\r\n','Visualizing af::array with Forge','','inherit','open','closed','','8698-revision-v1','','','2015-12-03 19:56:19','2015-12-03 19:56:19','',8698,'http://sandbox.arrayfire.com/8698-revision-v1/',0,'revision','',0),(8727,18673,'2015-12-03 19:59:52','2015-12-03 19:59:52','<p>Arrayfire as a library aims to provide a robust and easy to use platform for high-performance, parallel and GPU computing.\r\nThe goal of <a href=\"https://github.com/arrayfire/forge\">Forge</a>, an OpenGL visualization library, is to provide equally robust visualizations that are interoperable between Arrayfire data-structures and an OpenGL context.</p>\r\n<p>Arrayfire provides wrapper functions that are designed to be a simple interface to visualize af::arrays. These functions perform various interoperability tasks. One in particular is that instead of wasting time copying and reformatting data from the GPU to the host and back to the GPU, we can draw directly from GPU-data to GPU-framebuffers, saving two memory copies!</p>\r\n<p>Let’s see exactly what visuals we can illuminate with forge and how Arrayfire anneals the data between the two libraries.</p>\r\n<h2><a id=\"Setup_17\"></a>Setup</h2>\r\n<p>Before we can call Forge functions, we need to set up the related “canvas” classes.\r\nForge functions are tied to the af::Window class. First let’s create a window:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int width = 512, height = 512;\r\naf::Window window(width, height, \"2D plot example title\");\r\n\r\ndo{\r\n\r\n//drawing functions here\r\n\r\n} while( !window.close() );</code></pre>\r\n<p>We also added a drawing loop, so now we can use Forge’s drawing functions to draw to the window. The drawing functions present in Forge are listed below.</p>\r\n<h2><a id=\"Rendering_Functions_35\"></a>Rendering Functions</h2>\r\n<p>Documentation for the rendering functions can be found <a href=\"http://sandbox.arrayfire.com/docs/group__gfx__func__draw.htm\">here</a> .</p>\r\n<h3><a id=\"Image_38\"></a>Image</h3>\r\n<p>The af::Window::image() function can be used to plot grayscale or color images. To plot a grayscale image a 2d array should be passed into the function.\r\nLet’s see this on a static noise example:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = constant(0, width, height);   //make a black image\r\narray random = randu(width, height);      //make random [0,1] distribution\r\n\r\nwindow.image(img);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise-262x300.png\" alt=\"Forge image plot of noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8710\" /></a></p>\r\n<p>Tweaking the previous example by giving our image a depth of 3 for the RGB values allows us to generate colorful noise:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = 255 * randu(width, height, 3);      //make random [0, 255] distribution\r\nwindow.image( img.as(u8) );</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise-262x300.png\" alt=\"Forge image plot of color noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8708\" /></a></p>\r\n<p>Note that Forge automatically handles any af::array type passed from Arrayfire. In the first example we passed in an image of floats in the range [0, 1]. In the last example we cast our array to an unsigned byte array with the range\r\n[0, 255]. The type-handling properties are consistent for all Forge drawing functions.</p>\r\n<h3><a id=\"Plot_63\"></a>Plot</h3>\r\n<p>The af::Window::plot() function visualizes an array as a 2d-line plot. Let’s see a simple example:</p>\r\n<pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray Y = sin(X);\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot-296x300.png\" alt=\"Forge 2d line plot of sin() function\" width=\"296\" height=\"300\" class=\"aligncenter size-medium wp-image-8714\" /></a>\r\nThe plot function has the signature:</p>\r\n<p><code><strong>void plot( const array &amp;X, const array &amp;Y, const char * const title = NULL );</strong></code></p>\r\n<p>Both the x and y coordinates of the points are required to plot. This allows for non-uniform, or parametric plots:</p>\r\n<pre><code class=\"language-{.cpp}\">array t = seq(0, 100, 0.01);\r\narray X = sin(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\narray Y = cos(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot-290x300.png\" alt=\"\" width=\"290\" height=\"300\" class=\"aligncenter size-medium wp-image-8707\" /></a></p>\r\n<h3><a id=\"Scatter_88\"></a>Scatter</h3>\r\n<p>The scatter() function visualizes an array as a 2d-scatter plot. Let’s see a example:</p><pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray noise = randn(X.dims(0)) /3.0f;\r\narray Y = sin(X) + noise;\r\nwindow.scatter(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter-300x228.png\" alt=\"Forge 2d scatter plot\" width=\"300\" height=\"228\" class=\"aligncenter size-medium wp-image-8715\" /></a></p>\r\n<p>The scatter function has the signature:</p>\r\n<p><code><strong>void scatter( const array &amp;X, const array &amp;Y, af::markerType marker=AF_MARKER_POINT, const char * const title = NULL);</strong></code></p>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point.\r\nIt can take on the values of:</p><pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Plot3_118\"></a>Plot3</h3>\r\n<p>The af::Window::plot3() function will plot a curve in 3d-space.\r\nIts signature is:</p>\r\n<p><code><strong>void plot3 (const array &amp;in, const char * title = NULL);</strong></code></p>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = seq(0.1f, 10.f, 0.01);\r\narray Y = sin(10 * Z) / Z;\r\narray X = cos(10 * Z) / Z;\r\n\r\narray Pts = join(1, X, Y, Z);\r\n//Pts can be passed in as a matrix in the from n x 3, 3 x n\r\n//or in the flattened xyz-triplet array with size 3n x 1\r\nwindow.plot3(Pts);\r\n//both of the following are equally valid\r\n//window.plot3(transpose(Pts));\r\n//window.plot3(flat(Pts));</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3-300x211.png\" alt=\"Forge 3d line plot\" width=\"300\" height=\"211\" class=\"aligncenter size-medium wp-image-8716\" /></a></p>\r\n<h3><a id=\"Histogram_140\"></a>Histogram</h3>\r\n<p>The af::Window::hist() function renders an input array as a histogram. In our example, the input array will be created with Arrayfire’s histogram() function, which actually counts and bins each sample. The output from histogram() can directly be fed into the af::Window::hist() rendering function.</p>\r\n<pre><code class=\"language-{.cpp}\">const int BINS = 128; SAMPLES = 9162;\r\narray norm = randn(SAMPLES);\r\narray hist_arr = histogram(norm, BINS);\r\n\r\nwin.hist(hist_arr, 0, BINS);</code></pre>\r\n<p>In addition to the histogram array with the number of samples in each bin, the af::Window::hist() function takes two additional parameters – the minimum and maximum values of all datapoints in the histogram array. This effectively sets the range of the binned data. The full signature of af::Window::hist() is:</p>\r\n<p><code><strong>void hist(const array &amp; X, const double minval, const double maxval, const char * const title = NULL);</strong></code></p>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram-300x256.png\" alt=\"Forge histogram plot\" width=\"300\" height=\"256\" class=\"aligncenter size-medium wp-image-8711\" /></a></p>\r\n<h3><a id=\"Scatter3_162\"></a>Scatter3</h3>\r\n<p>The scatter3() function visualizes an array as a 3d-scatter plot.\r\nIts signature is:</p>\r\n<p><code><strong>void scatter3 (const array &amp;in, af::markerType marker=AF_MARKER_POINT, const char * title = NULL);</strong></code></p>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3-300x208.png\" alt=\"Forge 3d scatter plot\" width=\"300\" height=\"208\" class=\"aligncenter size-medium wp-image-8712\" /></a></p>\r\n<pre><code class=\"language-{.cpp}\">array X = randn(300);\r\narray Y = randn(300);\r\narray Z = randn(300);\r\n\r\narray Pts = join(1, X, Y, Z);\r\nwindow.scatter3(Pts);</code></pre>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point. It can take on the values of:</p>\r\n<pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Surface_195\"></a>Surface</h3>\r\n<p>The af::Window::surface() function will plot af::arrays as a 3d surface.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = randu(21, 21);\r\nwindow.surface(Z, \"Random Surface\");    //equal to next function call\r\n//window.surface( seq(-1, 1, 0.1), seq(-1, 1, 0.1), Z, \"Random Surface\");</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface-300x269.png\" alt=\"Forge 3d surface() plot\" width=\"300\" height=\"269\" class=\"aligncenter size-medium wp-image-8713\" /></a>\r\nThere are two overloads for the af::Window::surface() function:</p>\r\n<p><code><strong>void surface (const array &amp; S, const char * const title )</strong>\r\n// Accepts a 2d matrix with the z values of the surface</code></p>\r\n<p><code><strong>void surface (const array &amp;xVals, const array &amp;yVals, const array &amp;S, const char * const title)</strong>\r\n// accepts additional vectors that define the x,y coordinates for the surface points.</code></p>\r\n<p>The second overload has two options for the x, y coordinate vectors. Assuming a surface grid of size <strong>m x n</strong>:</p>\r\n<ol>\r\n<li>Short vectors defining the spacing along each axis. Vectors will have sizes <strong>m x 1</strong> and <strong>n x 1</strong>.</li>\r\n<li>Vectors containing the coordinates of each and every point. Each of the vectors will have length <strong>mn x 1</strong>. This can be used for completely non-uniform or parametric surfaces.</li>\r\n</ol>\r\n<h2><a id=\"Conclusion_216\"></a>Conclusion</h2>\r\n<p>There is a fairly comprehensive collection of methods to visualize data in Arrayfire. Thanks to the high-performance gpu plotting library Forge, the provided Arrayfire functions not only make visualizations as simple as possible, but keep them as robust as the rest of the Arrayfire library.</p>','Visualizing af::array with Forge','','inherit','open','closed','','8698-revision-v1','','','2015-12-03 19:59:52','2015-12-03 19:59:52','',8698,'http://sandbox.arrayfire.com/8698-revision-v1/',0,'revision','',0),(8728,18673,'2015-12-03 20:02:26','2015-12-03 20:02:26','<p>Arrayfire as a library aims to provide a robust and easy to use platform for high-performance, parallel and GPU computing.\r\nThe goal of <a href=\"https://github.com/arrayfire/forge\">Forge</a>, an OpenGL visualization library, is to provide equally robust visualizations that are interoperable between Arrayfire data-structures and an OpenGL context.</p>\r\n<p>Arrayfire provides wrapper functions that are designed to be a simple interface to visualize af::arrays. These functions perform various interoperability tasks. One in particular is that instead of wasting time copying and reformatting data from the GPU to the host and back to the GPU, we can draw directly from GPU-data to GPU-framebuffers, saving two memory copies!</p>\r\n<p>Let’s see exactly what visuals we can illuminate with forge and how Arrayfire anneals the data between the two libraries.</p>\r\n<h2><a id=\"Setup_17\"></a>Setup</h2>\r\n<p>Before we can call Forge functions, we need to set up the related “canvas” classes.\r\nForge functions are tied to the af::Window class. First let’s create a window:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int width = 512, height = 512;\r\naf::Window window(width, height, \"2D plot example title\");\r\n\r\ndo{\r\n\r\n//drawing functions here\r\n\r\n} while( !window.close() );</code></pre>\r\n<p>We also added a drawing loop, so now we can use Forge’s drawing functions to draw to the window. The drawing functions present in Forge are listed below.</p>\r\n<h2><a id=\"Rendering_Functions_35\"></a>Rendering Functions</h2>\r\n<p>Documentation for the rendering functions can be found <a href=\"http://sandbox.arrayfire.com/docs/group__gfx__func__draw.htm\">here</a> .</p>\r\n<h3><a id=\"Image_38\"></a>Image</h3>\r\n<p>The af::Window::image() function can be used to plot grayscale or color images. To plot a grayscale image a 2d array should be passed into the function.\r\nLet’s see this on a static noise example:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = constant(0, width, height);   //make a black image\r\narray random = randu(width, height);      //make random [0,1] distribution\r\n\r\nwindow.image(img);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise-262x300.png\" alt=\"Forge image plot of noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8710\" /></a></p>\r\n<p>Tweaking the previous example by giving our image a depth of 3 for the RGB values allows us to generate colorful noise:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = 255 * randu(width, height, 3);      //make random [0, 255] distribution\r\nwindow.image( img.as(u8) );</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise-262x300.png\" alt=\"Forge image plot of color noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8708\" /></a></p>\r\n<p>Note that Forge automatically handles any af::array type passed from Arrayfire. In the first example we passed in an image of floats in the range [0, 1]. In the last example we cast our array to an unsigned byte array with the range\r\n[0, 255]. The type-handling properties are consistent for all Forge drawing functions.</p>\r\n<h3><a id=\"Plot_63\"></a>Plot</h3>\r\n<p>The af::Window::plot() function visualizes an array as a 2d-line plot. Let’s see a simple example:</p>\r\n<pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray Y = sin(X);\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot-296x300.png\" alt=\"Forge 2d line plot of sin() function\" width=\"296\" height=\"300\" class=\"aligncenter size-medium wp-image-8714\" /></a>\r\nThe plot function has the signature:</p>\r\n<p><code><strong>void plot( const array &amp;X, const array &amp;Y, const char * const title = NULL );</strong></code></p>\r\n<p>Both the x and y coordinates of the points are required to plot. This allows for non-uniform, or parametric plots:</p>\r\n<pre><code class=\"language-{.cpp}\">array t = seq(0, 100, 0.01);\r\narray X = sin(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\narray Y = cos(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot-290x300.png\" alt=\"\" width=\"290\" height=\"300\" class=\"aligncenter size-medium wp-image-8707\" /></a></p>\r\n<h3><a id=\"Scatter_88\"></a>Scatter</h3>\r\n<p>The scatter() function visualizes an array as a 2d-scatter plot. Let’s see a example:</p><pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray noise = randn(X.dims(0)) /3.0f;\r\narray Y = sin(X) + noise;\r\nwindow.scatter(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter-300x228.png\" alt=\"Forge 2d scatter plot\" width=\"300\" height=\"228\" class=\"aligncenter size-medium wp-image-8715\" /></a></p>\r\n<p>The scatter function has the signature:</p>\r\n<p><code><strong>void scatter( const array &amp;X, const array &amp;Y, af::markerType marker=AF_MARKER_POINT,\r\n    const char * const title = NULL);</strong></code></p>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point.\r\nIt can take on the values of:</p><pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Plot3_118\"></a>Plot3</h3>\r\n<p>The af::Window::plot3() function will plot a curve in 3d-space.\r\nIts signature is:</p>\r\n<p><code><strong>void plot3 (const array &amp;in, const char * title = NULL);</strong></code></p>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = seq(0.1f, 10.f, 0.01);\r\narray Y = sin(10 * Z) / Z;\r\narray X = cos(10 * Z) / Z;\r\n\r\narray Pts = join(1, X, Y, Z);\r\n//Pts can be passed in as a matrix in the from n x 3, 3 x n\r\n//or in the flattened xyz-triplet array with size 3n x 1\r\nwindow.plot3(Pts);\r\n//both of the following are equally valid\r\n//window.plot3(transpose(Pts));\r\n//window.plot3(flat(Pts));</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3-300x211.png\" alt=\"Forge 3d line plot\" width=\"300\" height=\"211\" class=\"aligncenter size-medium wp-image-8716\" /></a></p>\r\n<h3><a id=\"Histogram_140\"></a>Histogram</h3>\r\n<p>The af::Window::hist() function renders an input array as a histogram. In our example, the input array will be created with Arrayfire’s histogram() function, which actually counts and bins each sample. The output from histogram() can directly be fed into the af::Window::hist() rendering function.</p>\r\n<pre><code class=\"language-{.cpp}\">const int BINS = 128; SAMPLES = 9162;\r\narray norm = randn(SAMPLES);\r\narray hist_arr = histogram(norm, BINS);\r\n\r\nwin.hist(hist_arr, 0, BINS);</code></pre>\r\n<p>In addition to the histogram array with the number of samples in each bin, the af::Window::hist() function takes two additional parameters – the minimum and maximum values of all datapoints in the histogram array. This effectively sets the range of the binned data. The full signature of af::Window::hist() is:</p>\r\n<p><code><strong>void hist(const array &amp; X, const double minval, const double maxval, const char * const title = NULL);</strong></code></p>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram-300x256.png\" alt=\"Forge histogram plot\" width=\"300\" height=\"256\" class=\"aligncenter size-medium wp-image-8711\" /></a></p>\r\n<h3><a id=\"Scatter3_162\"></a>Scatter3</h3>\r\n<p>The scatter3() function visualizes an array as a 3d-scatter plot.\r\nIts signature is:</p>\r\n<p><code><strong>void scatter3 (const array &amp;in, af::markerType marker=AF_MARKER_POINT, const char * title = NULL);</strong></code></p>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3-300x208.png\" alt=\"Forge 3d scatter plot\" width=\"300\" height=\"208\" class=\"aligncenter size-medium wp-image-8712\" /></a></p>\r\n<pre><code class=\"language-{.cpp}\">array X = randn(300);\r\narray Y = randn(300);\r\narray Z = randn(300);\r\n\r\narray Pts = join(1, X, Y, Z);\r\nwindow.scatter3(Pts);</code></pre>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point. It can take on the values of:</p>\r\n<pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Surface_195\"></a>Surface</h3>\r\n<p>The af::Window::surface() function will plot af::arrays as a 3d surface.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = randu(21, 21);\r\nwindow.surface(Z, \"Random Surface\");    //equal to next function call\r\n//window.surface( seq(-1, 1, 0.1), seq(-1, 1, 0.1), Z, \"Random Surface\");</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface-300x269.png\" alt=\"Forge 3d surface() plot\" width=\"300\" height=\"269\" class=\"aligncenter size-medium wp-image-8713\" /></a>\r\nThere are two overloads for the af::Window::surface() function:</p>\r\n<p><code><strong>void surface (const array &amp; S, const char * const title )</strong>\r\n// Accepts a 2d matrix with the z values of the surface</code></p>\r\n<p><code><strong>void surface (const array &amp;xVals, const array &amp;yVals, const array &amp;S, const char * const title)</strong>\r\n// accepts additional vectors that define the x,y coordinates for the surface points.</code></p>\r\n<p>The second overload has two options for the x, y coordinate vectors. Assuming a surface grid of size <strong>m x n</strong>:</p>\r\n<ol>\r\n<li>Short vectors defining the spacing along each axis. Vectors will have sizes <strong>m x 1</strong> and <strong>n x 1</strong>.</li>\r\n<li>Vectors containing the coordinates of each and every point. Each of the vectors will have length <strong>mn x 1</strong>. This can be used for completely non-uniform or parametric surfaces.</li>\r\n</ol>\r\n<h2><a id=\"Conclusion_216\"></a>Conclusion</h2>\r\n<p>There is a fairly comprehensive collection of methods to visualize data in Arrayfire. Thanks to the high-performance gpu plotting library Forge, the provided Arrayfire functions not only make visualizations as simple as possible, but keep them as robust as the rest of the Arrayfire library.</p>','Visualizing af::array with Forge','','inherit','open','closed','','8698-revision-v1','','','2015-12-03 20:02:26','2015-12-03 20:02:26','',8698,'http://sandbox.arrayfire.com/8698-revision-v1/',0,'revision','',0),(8729,18673,'2015-12-03 20:03:46','2015-12-03 20:03:46','<p>Arrayfire as a library aims to provide a robust and easy to use platform for high-performance, parallel and GPU computing.\r\nThe goal of <a href=\"https://github.com/arrayfire/forge\">Forge</a>, an OpenGL visualization library, is to provide equally robust visualizations that are interoperable between Arrayfire data-structures and an OpenGL context.</p>\r\n<p>Arrayfire provides wrapper functions that are designed to be a simple interface to visualize af::arrays. These functions perform various interoperability tasks. One in particular is that instead of wasting time copying and reformatting data from the GPU to the host and back to the GPU, we can draw directly from GPU-data to GPU-framebuffers, saving two memory copies!</p>\r\n<p>Let’s see exactly what visuals we can illuminate with forge and how Arrayfire anneals the data between the two libraries.</p>\r\n<h2><a id=\"Setup_17\"></a>Setup</h2>\r\n<p>Before we can call Forge functions, we need to set up the related “canvas” classes.\r\nForge functions are tied to the af::Window class. First let’s create a window:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int width = 512, height = 512;\r\naf::Window window(width, height, \"2D plot example title\");\r\n\r\ndo{\r\n\r\n//drawing functions here\r\n\r\n} while( !window.close() );</code></pre>\r\n<p>We also added a drawing loop, so now we can use Forge’s drawing functions to draw to the window. The drawing functions present in Forge are listed below.</p>\r\n<h2><a id=\"Rendering_Functions_35\"></a>Rendering Functions</h2>\r\n<p>Documentation for the rendering functions can be found <a href=\"http://sandbox.arrayfire.com/docs/group__gfx__func__draw.htm\">here</a> .</p>\r\n<h3><a id=\"Image_38\"></a>Image</h3>\r\n<p>The af::Window::image() function can be used to plot grayscale or color images. To plot a grayscale image a 2d array should be passed into the function.\r\nLet’s see this on a static noise example:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = constant(0, width, height);   //make a black image\r\narray random = randu(width, height);      //make random [0,1] distribution\r\n\r\nwindow.image(img);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/noise-262x300.png\" alt=\"Forge image plot of noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8710\" /></a></p>\r\n<p>Tweaking the previous example by giving our image a depth of 3 for the RGB values allows us to generate colorful noise:</p>\r\n<pre><code class=\"language-{.cpp}\">array img = 255 * randu(width, height, 3);      //make random [0, 255] distribution\r\nwindow.image( img.as(u8) );</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/color_noise-262x300.png\" alt=\"Forge image plot of color noise\" width=\"262\" height=\"300\" class=\"aligncenter size-medium wp-image-8708\" /></a></p>\r\n<p>Note that Forge automatically handles any af::array type passed from Arrayfire. In the first example we passed in an image of floats in the range [0, 1]. In the last example we cast our array to an unsigned byte array with the range\r\n[0, 255]. The type-handling properties are consistent for all Forge drawing functions.</p>\r\n<h3><a id=\"Plot_63\"></a>Plot</h3>\r\n<p>The af::Window::plot() function visualizes an array as a 2d-line plot. Let’s see a simple example:</p>\r\n<pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray Y = sin(X);\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_plot-296x300.png\" alt=\"Forge 2d line plot of sin() function\" width=\"296\" height=\"300\" class=\"aligncenter size-medium wp-image-8714\" /></a>\r\nThe plot function has the signature:</p>\r\n<p><code><strong>void plot( const array &amp;X, const array &amp;Y, const char * const title = NULL );</strong></code></p>\r\n<p>Both the x and y coordinates of the points are required to plot. This allows for non-uniform, or parametric plots:</p>\r\n<pre><code class=\"language-{.cpp}\">array t = seq(0, 100, 0.01);\r\narray X = sin(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\narray Y = cos(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5));\r\nwindow.plot(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/butterfly_plot-290x300.png\" alt=\"\" width=\"290\" height=\"300\" class=\"aligncenter size-medium wp-image-8707\" /></a></p>\r\n<h3><a id=\"Scatter_88\"></a>Scatter</h3>\r\n<p>The af::Window::scatter() function visualizes an array as a 2d-scatter plot. Let’s see a example:</p><pre><code class=\"language-{.cpp}\">array X = seq(-af::Pi, af::Pi, 0.01);\r\narray noise = randn(X.dims(0)) /3.0f;\r\narray Y = sin(X) + noise;\r\nwindow.scatter(X, Y);</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/sin_scatter-300x228.png\" alt=\"Forge 2d scatter plot\" width=\"300\" height=\"228\" class=\"aligncenter size-medium wp-image-8715\" /></a></p>\r\n<p>The scatter function has the signature:</p>\r\n<p><code><strong>void scatter( const array &amp;X, const array &amp;Y, af::markerType marker=AF_MARKER_POINT, const char * const title = NULL);</strong></code></p>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point.\r\nIt can take on the values of:</p><pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Plot3_118\"></a>Plot3</h3>\r\n<p>The af::Window::plot3() function will plot a curve in 3d-space.\r\nIts signature is:</p>\r\n<p><code><strong>void plot3 (const array &amp;in, const char * title = NULL);</strong></code></p>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = seq(0.1f, 10.f, 0.01);\r\narray Y = sin(10 * Z) / Z;\r\narray X = cos(10 * Z) / Z;\r\n\r\narray Pts = join(1, X, Y, Z);\r\n//Pts can be passed in as a matrix in the from n x 3, 3 x n\r\n//or in the flattened xyz-triplet array with size 3n x 1\r\nwindow.plot3(Pts);\r\n//both of the following are equally valid\r\n//window.plot3(transpose(Pts));\r\n//window.plot3(flat(Pts));</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/spiral_plot3-300x211.png\" alt=\"Forge 3d line plot\" width=\"300\" height=\"211\" class=\"aligncenter size-medium wp-image-8716\" /></a></p>\r\n<h3><a id=\"Histogram_140\"></a>Histogram</h3>\r\n<p>The af::Window::hist() function renders an input array as a histogram. In our example, the input array will be created with Arrayfire’s histogram() function, which actually counts and bins each sample. The output from histogram() can directly be fed into the af::Window::hist() rendering function.</p>\r\n<pre><code class=\"language-{.cpp}\">const int BINS = 128; SAMPLES = 9162;\r\narray norm = randn(SAMPLES);\r\narray hist_arr = histogram(norm, BINS);\r\n\r\nwin.hist(hist_arr, 0, BINS);</code></pre>\r\n<p>In addition to the histogram array with the number of samples in each bin, the af::Window::hist() function takes two additional parameters – the minimum and maximum values of all datapoints in the histogram array. This effectively sets the range of the binned data. The full signature of af::Window::hist() is:</p>\r\n<p><code><strong>void hist(const array &amp; X, const double minval, const double maxval, const char * const title = NULL);</strong></code></p>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_histogram-300x256.png\" alt=\"Forge histogram plot\" width=\"300\" height=\"256\" class=\"aligncenter size-medium wp-image-8711\" /></a></p>\r\n<h3><a id=\"Scatter3_162\"></a>Scatter3</h3>\r\n<p>The af::Window::scatter3() function visualizes an array as a 3d-scatter plot.\r\nIts signature is:</p>\r\n<p><code><strong>void scatter3 (const array &amp;in, af::markerType marker=AF_MARKER_POINT, const char * title = NULL);</strong></code></p>\r\n<p>The input array expects xyz-triplets in sequential order. The points can be in a flattened one dimensional (<em>3n x 1</em>) array, or in one of the (<em>3 x n</em>), (<em>n x 3</em>) matrix forms.</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/norm_scatter3-300x208.png\" alt=\"Forge 3d scatter plot\" width=\"300\" height=\"208\" class=\"aligncenter size-medium wp-image-8712\" /></a></p>\r\n<pre><code class=\"language-{.cpp}\">array X = randn(300);\r\narray Y = randn(300);\r\narray Z = randn(300);\r\n\r\narray Pts = join(1, X, Y, Z);\r\nwindow.scatter3(Pts);</code></pre>\r\n<p>The <strong>af::markerType</strong> enum determines which marker will be drawn at each point. It can take on the values of:</p>\r\n<pre><code class=\"language-{.cpp}\">enum af::markerType {\r\n    AF_MARKER_POINT\r\n    AF_MARKER_CIRCLE\r\n    AF_MARKER_SQUARE\r\n    AF_MARKER_TRIANGLE\r\n    AF_MARKER_CROSS\r\n    AF_MARKER_PLUS\r\n    AF_MARKER_STAR\r\n};</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/marker_types.png\" alt=\"Different types of markers in Forge.\" width=\"1846\" height=\"326\" class=\"aligncenter size-full wp-image-8709\" /></a></p>\r\n<h3><a id=\"Surface_195\"></a>Surface</h3>\r\n<p>The af::Window::surface() function will plot af::arrays as a 3d surface.</p>\r\n<pre><code class=\"language-{.cpp}\">array Z = randu(21, 21);\r\nwindow.surface(Z, \"Random Surface\");    //equal to next function call\r\n//window.surface( seq(-1, 1, 0.1), seq(-1, 1, 0.1), Z, \"Random Surface\");</code></pre>\r\n<p><a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface.png\"><img src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/12/rand_surface-300x269.png\" alt=\"Forge 3d surface() plot\" width=\"300\" height=\"269\" class=\"aligncenter size-medium wp-image-8713\" /></a>\r\nThere are two overloads for the af::Window::surface() function:</p>\r\n<p><code><strong>void surface (const array &amp; S, const char * const title )</strong>\r\n// Accepts a 2d matrix with the z values of the surface</code></p>\r\n<p><code><strong>void surface (const array &amp;xVals, const array &amp;yVals, const array &amp;S, const char * const title)</strong>\r\n// accepts additional vectors that define the x,y coordinates for the surface points.</code></p>\r\n<p>The second overload has two options for the x, y coordinate vectors. Assuming a surface grid of size <strong>m x n</strong>:</p>\r\n<ol>\r\n<li>Short vectors defining the spacing along each axis. Vectors will have sizes <strong>m x 1</strong> and <strong>n x 1</strong>.</li>\r\n<li>Vectors containing the coordinates of each and every point. Each of the vectors will have length <strong>mn x 1</strong>. This can be used for completely non-uniform or parametric surfaces.</li>\r\n</ol>\r\n<h2><a id=\"Conclusion_216\"></a>Conclusion</h2>\r\n<p>There is a fairly comprehensive collection of methods to visualize data in Arrayfire. Thanks to the high-performance gpu plotting library Forge, the provided Arrayfire functions not only make visualizations as simple as possible, but keep them as robust as the rest of the Arrayfire library.</p>','Visualizing af::array with Forge','','inherit','open','closed','','8698-revision-v1','','','2015-12-03 20:03:46','2015-12-03 20:03:46','',8698,'http://sandbox.arrayfire.com/8698-revision-v1/',0,'revision','',0),(8735,18673,'2016-05-19 10:00:02','2016-05-19 14:00:02','Programmers and Data Scientists want to take advantage of fast and parallel computational devices. One of the best ways of doing this is to write vectorized code; however, this is often easier said than done. In today\'s continuation of the blog series \"<a href=\"http://sandbox.arrayfire.com/tag/learning-arrayfire-from-scratch/\">Learning ArrayFire from scratch</a>\", we will discuss the various methods by which you can maximize the performance of your code by using ArrayFire\'s built-in vectorization features.\r\n\r\n<!--more-->\r\n\r\nArrayFire provides many ways to vectorize a given code segment. In this tutorial, we present several methods to vectorize code using ArrayFire and discuss the benefits and drawbacks associated with each method.\r\n<h4><a id=\"GenericDefault_vectorization_10\"></a>Generic/Default vectorization</h4>\r\nBy its very nature, ArrayFire is a vectorized library. Most functions operate on arrays as a whole – on all elements in parallel. Wherever possible, existing vectorized functions should be used opposed to manually indexing into arrays. For example consider the following code:\r\n<pre class=\"lang:default decode:true \">af::array a = af::range(10); // [0,  9]\r\nfor(int i = 0; i &lt; a.dims(0); ++i)\r\n{\r\n    a(i) = a(i) + 1;         // [1, 10]\r\n}</pre>\r\nAlthough completely valid, the code is very inefficient as it results in a kernel that operate on one datum. Instead, the developer should have used ArrayFire\'s overload of the + operator:\r\n<pre><code class=\"language-{.cpp}\">\r\naf::array a = af::range(10);  // [0,  9]\r\na = a + 1;                    // [1, 10]\r\n</code></pre>\r\nThis code will result in a single kernel that operates on all 10 elements of <code>a</code> in parallel.\r\n\r\nMost ArrayFire functions are vectorized. A small subset of these include:\r\n\r\n<strong>Arithmetic operations:</strong> +, -, *, / , %, &gt;&gt;, &lt;&lt;\r\n<strong>Logical operations:</strong> &amp;&amp;, ||, &lt;, &gt;, ==, !=\r\n<strong>Numeric functions:</strong> abs(), floor(), round(), min(), max()…\r\n<strong>Complex operations:</strong> real(), imag(), conj()…\r\n<strong>Exponential and logarithmic functions:</strong> exp(), log(), expm1(), log1p()…\r\n<strong>Trigonometric functions:</strong> sin(), cos(), tan()…\r\n<strong>Hyperbolic functions:</strong> sinh(), cosh(), tanh()…\r\n\r\nIn addition to element-wise operations, many other functions are also vectorized in ArrayFire.\r\n\r\nNotice that even that performs some form of aggregation (e.g. <code>sum()</code> or <code>min()</code>), signal processing (like <code>convolve()</code>), and even image processing functions (i.e. <code>rotate()</code>) all support vectorization on different columns or images. For example, if we have <code>NUM</code> images of size <code>WIDTH</code> by <code>HEIGHT</code>, one could convolve each image in a vector fashion as follows:\r\n<pre class=\"lang:default decode:true \">float g_coef[] = { 1, 2, 1,\r\n                   2, 4, 2,\r\n                   1, 2, 1 };\r\naf::array filter = 1.f/16 * af::array(3, 3, f_coef);\r\naf::array signal = randu(WIDTH, HEIGHT, NUM);\r\naf::array conv = convolve2(signal, filter);</pre>\r\nSimilarly, one can rotate 100 images by 45 degrees in a single call using code like the following:\r\n<div class=\"fragment\">\r\n<div class=\"line\">\r\n<pre class=\"lang:default decode:true \">// Construct an array of 100 WIDTH x HEIGHT images of random numbers\r\naf::array imgs = randu(WIDTH, HEIGHT, 100);\r\n// Rotate all of the images in a single command\r\naf::array rot_imgs = rotate(imgs, 45);</pre>\r\n</div>\r\n</div>\r\nAlthough <em>most</em> functions in ArrayFire do support vectorization, some do not. Most notably, all linear algebra functions. Even though they are not vectorized linear algebra operations still execute in parallel on your hardware.\r\n\r\nUsing the built in vectorized operations should be the first and preferred method of vectorizing any code written with ArrayFire.\r\n<h4><a id=\"GFOR_Parallel_forloops_76\"></a>GFOR: Parallel for-loops</h4>\r\nAnother novel method of vectorization present in ArrayFire is the GFOR loop replacement construct. GFOR allows launching all iterations of a loop in parallel on the GPU or device, as long as the iterations are independent. While the standard for-loop performs each iteration sequentially, ArrayFire\'s gfor-loop performs each iteration at the same time (in parallel). ArrayFire does this by tiling out the values of all loop iterations and then performing computation on those tiles in one pass. You can think of gfor as performing auto-vectorization of your code, e.g. you write a gfor-loop that increments every element of a vector but behind the scenes ArrayFire rewrites it to operate on the entire vector in parallel.\r\n\r\nThe original for-loop example at the beginning of this document could be rewritten using GFOR as follows:\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);\r\ngfor(seq i, n)\r\n    a(i) = a(i) + 1;</code></pre>\r\nIn this case, each instance of the gfor loop is independent, thus ArrayFire will automatically tile out the <code>a</code> array in device memory and execute the increment kernels in parallel.\r\n\r\nTo see another example, you could run an <a class=\"el\" title=\"C++ Interface exclusive sum (cumulative sum) of an array. \" href=\"http://arrayfire.org/docs/group__scan__func__accum.htm\">accum()</a> on every slice of a matrix in a for-loop, or you could \"vectorize\" and simply do it all in one gfor-loop operation:\r\n<div class=\"fragment\">\r\n<div class=\"line\">\r\n<pre class=\"lang:default decode:true \">// runs each accum() in sequence\r\nfor (int i = 0; i &lt; N; ++i)\r\n    B(span,i) = accum(A(span,i));\r\n \r\n// runs N accums in parallel\r\ngfor (seq i, N)\r\n    B(span,i) = accum(A(span,i));</pre>\r\n</div>\r\n</div>\r\nHowever, returning to our previous vectorization technique, <a class=\"el\" title=\"C++ Interface exclusive sum (cumulative sum) of an array. \" href=\"http://arrayfire.org/docs/group__scan__func__accum.htm\">accum()</a> is already vectorized and the operation could be completely replaced with merely:\r\n<div class=\"fragment\">\r\n<div class=\"line\">\r\n<pre class=\"lang:default decode:true \">B = accum(A);</pre>\r\n</div>\r\n</div>\r\nIt is best to vectorize computation as much as possible to avoid the overhead in both for-loops and gfor-loops. However, the gfor-loop construct is most effective in the narrow case of broadcast-style operations. Consider the case when we have a vector of constants that we wish to apply to a collection of variables, such as expressing the values of a linear combination for multiple vectors. The broadcast of one set of constants to many vectors works well with gfor-loops:\r\n<div class=\"fragment\">\r\n<div class=\"line\">\r\n<pre class=\"lang:default decode:true \">const static int p=4, n=1000;\r\naf::array consts = af::randu(p);\r\naf::array var_terms = randn(p, n);\r\n \r\ngfor(seq i, n)\r\n    combination(span, i) = consts * var_terms(span, i);</pre>\r\n</div>\r\n</div>\r\nUsing GFOR requires following several rules and multiple guidelines for optimal performance. The details of this vectorization method can be found in the <a class=\"el\" href=\"http://arrayfire.org/docs/page_gfor.htm\">GFOR documentation</a>.\r\n<h4><a id=\"Batching_127\"></a>Batching</h4>\r\nThe <a class=\"el\" href=\"http://arrayfire.org/docs/namespaceaf.htm#aa0eb9e160f5be4b95234543e5c47934b\">batchFunc()</a> function allows the broad application of existing ArrayFire functions to multiple sets of data. Effectively,<a class=\"el\" href=\"http://arrayfire.org/docs/namespaceaf.htm#aa0eb9e160f5be4b95234543e5c47934b\">batchFunc()</a> allows ArrayFire functions to execute in \"batch processing\" mode. In this mode, functions will find a dimension which contains \"batches\" of data to be processed and will parallelize the procedure.\r\n\r\nConsider the following example. Here we create a filter which we would like to apply to each of the weight vectors. The naive solution would be using a for-loop as we have seen previously:\r\n<div class=\"fragment\">\r\n<div class=\"line\">\r\n<pre class=\"lang:default decode:true \">// Create the filter and the weight vectors\r\naf::array filter = randn(1, 5);\r\naf::array weights = randu(5, 5);\r\n \r\n// Apply the filter using a for-loop\r\naf::array filtered_weights = constant(0, 5, 5);\r\nfor(int i=0; i&lt;weights.dims(1); ++i){\r\n    filtered_weights.col(i) = filter * weights.col(i);\r\n}</pre>\r\n</div>\r\n</div>\r\nHowever, as we have discussed above, this solution will be very inefficient. One may be tempted to implement a vectorized solution as follows:\r\n<div class=\"fragment\">\r\n<div class=\"line\">\r\n<pre class=\"lang:default decode:true \">// Create the filter and the weight vectors\r\naf::array filter = randn(1, 5);\r\naf::array weights = randu(5, 5);\r\n \r\naf::array filtered_weights = filter * weights; // fails due to dimension mismatch</pre>\r\n</div>\r\n</div>\r\nHowever, the dimensions of <code>filter</code> and <code>weights</code> do not match, thus ArrayFire will generate a runtime error.\r\n\r\n<code>batchfunc()</code> was created to solve this specific problem. The signature of the function is as follows:\r\n<div class=\"fragment\">\r\n<div class=\"line\">\r\n<pre class=\"lang:default decode:true \">array batchFunc(const array &amp;lhs, const array &amp;rhs, batchFunc_t func);</pre>\r\n</div>\r\n</div>\r\nwhere <code>batchFunc_t</code> is a function pointer of the form:\r\n<div class=\"fragment\">\r\n<div class=\"line\">\r\n<pre class=\"lang:default decode:true \">typedef array (*batchFunc_t) (const array &amp;lhs, const array &amp;rhs);</pre>\r\n</div>\r\n</div>\r\nSo, to use <a class=\"el\" href=\"http://arrayfire.org/docs/namespaceaf.htm#aa0eb9e160f5be4b95234543e5c47934b\">batchFunc()</a>, we need to provide the function we wish to apply as a batch operation. For illustration\'s sake, let\'s \"implement\" a multiplication function following the format.\r\n<div class=\"fragment\">\r\n<div class=\"line\">\r\n<pre class=\"lang:default decode:true \">af::array my_mult (const af::array &amp;lhs, const af::array &amp;rhs){\r\nreturn lhs * rhs;\r\n}</pre>\r\n</div>\r\n</div>\r\nOur final batch call is not much more difficult than the ideal syntax we imagined.\r\n<div class=\"fragment\">\r\n<div class=\"line\">\r\n<pre class=\"lang:default decode:true \">// Create the filter and the weight vectors\r\naf::array filter = randn(1, 5);\r\naf::array weights = randu(5, 5);\r\n \r\n// Apply the batch function\r\naf::array filtered_weights = batchFunc( filter, weights, my_mult );</pre>\r\n</div>\r\n</div>\r\nThe batch function will work with many previously mentioned vectorized ArrayFire functions. It can even work with a combination of those functions if they are wrapped inside a helper function matching the <code>__batchFunc_t__</code> signature. One limitation of <code>batchfunc()</code> is that it cannot be used from within a <code><a class=\"el\" href=\"http://arrayfire.org/docs/gfor_8h.htm#a6d6cd11d53daad217fd0b92f5a7ceec6\">gfor()</a></code> loop at the present time.\r\n<h4><a id=\"Advanced_Vectorization_181\"></a>Advanced Vectorization</h4>\r\nWe have seen the different methods ArrayFire provides to vectorize our code. Tying them all together is a slightly more involved process that needs to consider data dimensionality and layout, memory usage, nesting order, etc. An excellent example and discussion of these factors can be found in another blog post:\r\n\r\n<a href=\"http://sandbox.arrayfire.com/how-to-write-vectorized-code/\">http://sandbox.arrayfire.com/how-to-write-vectorized-code/</a>\r\n\r\nIt’s worth noting that the whole implementation discussed in the blog has since been transformed into a convenient <strong>af::nearestNeighbour()</strong> function. Before writing something from scratch, check that ArrayFire doesn’t already have an implementation. The default vectorized nature of ArrayFire and an extensive collection of functions will speed things up in addition to replacing dozens of lines of code!','Introduction to Vectorization in ArrayFire','','publish','open','closed','','introduction-to-vectorization','','','2017-08-07 02:38:19','2017-08-07 06:38:19','',0,'http://sandbox.arrayfire.com/?p=8735',0,'post','',0),(8736,18673,'2015-12-03 20:56:43','2015-12-03 20:56:43','<title>introduction_to_vectorization.md</title>\r\n<p>Introduction to Vectorization</p>\r\n<p>Programmers and Data Scientists want to take advantage of fast and parallel\r\ncomputational devices. Writing vectorized code is becoming a necessity to get\r\nthe best performance out of the current generation parallel hardware and\r\nscientific computing software. However, writing vectorized code may not be\r\nintuitive immediately. Arrayfire provides many ways to vectorize a given code\r\nsegment. In this tutorial, we will be presenting various ways to vectorize code\r\nusing ArrayFire and the benefits and drawbacks associated with each method.</p>\r\n<h1><a id=\"GenericDefault_vectorization_10\"></a>Generic/Default vectorization</h1>\r\n<p>By its very nature, Arrayfire is a vectorized library. Most functions operate on\r\narrays as a whole – on all elements in parallel. Wherever possible, existing\r\nvectorized functions should be used opposed to manually indexing into arrays.\r\nFor example, consider this valid, yet mislead code that attempts to increment\r\neach element of an array:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> a = af::range(<span class=\"hljs-number\">10</span>); <span class=\"hljs-comment\">// [0,  9]</span>\r\n<span class=\"hljs-keyword\">for</span>(<span class=\"hljs-keyword\">int</span> i = <span class=\"hljs-number\">0</span>; i &lt; a.dims(<span class=\"hljs-number\">0</span>); ++i)\r\n{\r\n    a(i) = a(i) + <span class=\"hljs-number\">1</span>;         <span class=\"hljs-comment\">// [1, 10]</span>\r\n}\r\n</code></pre>\r\n<p>Instead, the existing vectorized Arrayfire overload of the + operator should have been used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> a = af::range(<span class=\"hljs-number\">10</span>);  <span class=\"hljs-comment\">// [0,  9]</span>\r\na = a + <span class=\"hljs-number\">1</span>;                    <span class=\"hljs-comment\">// [1, 10]</span>\r\n</code></pre>\r\n<p>Most Arrayfire functions are vectorized. A small subset of these include:</p>\r\n<p><strong>Arithmetic operations:</strong> +, -, *, / , %, &gt;&gt;, &lt;&lt;</p>\r\n<p><strong>Complex operations:</strong> real(), imag(), conj()…</p>\r\n<p><strong>Exponential and logarithmic functions:</strong> exp(), log(), expm1(), log1p()…</p>\r\n<p><strong>Hyperbolic functions:</strong> sinh(), cosh(), tanh()…</p>\r\n<p><strong>Logical operations:</strong> &amp;&amp;, ||, &lt;, &gt;, ==, !=</p>\r\n<p><strong>Numeric functions:</strong> abs(), floor(), round(), min(), max()…</p>\r\n<p><strong>Trigonometric functions:</strong> sin(), cos(), tan()…</p>\r\n<p>Not only elementwise arithmetic operations are vectorized in Arrayfire.</p>\r\n<p>Vector operations such as <strong>min()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> arr = randn(<span class=\"hljs-number\">100</span>);\r\n<span class=\"hljs-built_in\">std</span>::<span class=\"hljs-built_in\">cout</span> &lt;&lt; min&lt;<span class=\"hljs-keyword\">float</span>&gt;(arr) &lt;&lt; <span class=\"hljs-built_in\">std</span>::endl;\r\n</code></pre>\r\n<p>Signal processing functions like <strong>convolve()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\"><span class=\"hljs-keyword\">float</span> g_coef[] = { <span class=\"hljs-number\">1</span>, <span class=\"hljs-number\">2</span>, <span class=\"hljs-number\">1</span>,\r\n                   <span class=\"hljs-number\">2</span>, <span class=\"hljs-number\">4</span>, <span class=\"hljs-number\">2</span>,\r\n                   <span class=\"hljs-number\">1</span>, <span class=\"hljs-number\">2</span>, <span class=\"hljs-number\">1</span> };\r\n\r\naf::<span class=\"hljs-built_in\">array</span> filter = <span class=\"hljs-number\">1.f</span>/<span class=\"hljs-number\">16</span> * af::<span class=\"hljs-built_in\">array</span>(<span class=\"hljs-number\">3</span>, <span class=\"hljs-number\">3</span>, f_coef);\r\n\r\naf::<span class=\"hljs-built_in\">array</span> signal = randu(WIDTH, HEIGHT, NUM);\r\naf::<span class=\"hljs-built_in\">array</span> conv = convolve2(signal, filter);\r\n</code></pre>\r\n<p>Image processing functions such as <strong>rotate()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> imgs = randu(WIDTH, HEIGHT, <span class=\"hljs-number\">100</span>); <span class=\"hljs-comment\">// 100 (WIDTH x HEIGHT) images</span>\r\naf::<span class=\"hljs-built_in\">array</span> rot_imgs = rotate(imgs, <span class=\"hljs-number\">45</span>); <span class=\"hljs-comment\">// 100 rotated images</span>\r\n</code></pre>\r\n<p>One class of functions that does not support vectorization is the set of linear\r\nalgebra functions. Using the built in vectorized operations should be the first\r\nand preferred method of vectorizing any code written with Arrayfire.</p>\r\n<h1><a id=\"GFOR_Parallel_forloops_76\"></a>GFOR: Parallel for-loops</h1>\r\n<p>Another novel method of vectorization present in Arrayfire is the GFOR loop\r\nreplacement construct. GFOR allows launching all iterations of a loop in parallel\r\non the GPU or device, as long as the iterations are independent. While the\r\nstandard for-loop performs each iteration sequentially, ArrayFire’s gfor-loop\r\nperforms each iteration at the same time (in parallel). ArrayFire does this by\r\ntiling out the values of all loop iterations and then performing computation on\r\nthose tiles in one pass. You can think of gfor as performing auto-vectorization\r\nof your code, e.g. you write a gfor-loop that increments every element of a vector\r\nbut behind the scenes ArrayFire rewrites it to operate on the entire vector in\r\nparallel.</p>\r\n<p>We can remedy our first example with GFOR:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> a = af::range(<span class=\"hljs-number\">10</span>);\r\ngfor(seq i, n)\r\n    a(i) = a(i) + <span class=\"hljs-number\">1</span>;\r\n</code></pre>\r\n<p>To see another example, you could run an <strong>accum()</strong> on every slice of a matrix in a\r\nfor-loop, or you could “vectorize” and simply do it all in one gfor-loop operation:</p>\r\n<pre><code class=\"language-{.cpp}\">for <span class=\"hljs-comment\">(int i = 0; i &lt; N; ++i)</span>\r\n   B<span class=\"hljs-comment\">(span,i)</span> = accum<span class=\"hljs-comment\">(A(span,i)</span>); <span class=\"hljs-comment\">// runs each accum() in sequence</span>\r\ngfor <span class=\"hljs-comment\">(seq i, N)</span>\r\n   B<span class=\"hljs-comment\">(span,i)</span> = accum<span class=\"hljs-comment\">(A(span,i)</span>); <span class=\"hljs-comment\">// runs N accums in parallel</span>\r\n</code></pre>\r\n<p>However, returning to our previous vectorization technique, <strong>accum()</strong> is already\r\nvectorized and the operation could be completely replaced with merely:</p>\r\n<pre><code class=\"language-{.cpp}\">    B = accum(<span class=\"hljs-keyword\">A</span>)<span class=\"hljs-comment\">;</span>\r\n</code></pre>\r\n<p>It is best to vectorize computation as much as possible to avoid the overhead in\r\nboth for-loops and gfor-loops. However, the gfor-loop construct is most effective\r\nin the narrow case of broadcast-style operations. Consider the case when we have\r\na vector of constants that we wish to apply to a collection of variables, such as\r\nexpressing the values of a linear combination for multiple vectors. The broadcast\r\nof one set of constants to many vectors works well with gfor-loops:</p>\r\n<pre><code class=\"language-{.cpp}\"><span class=\"hljs-keyword\">const</span> <span class=\"hljs-keyword\">static</span> <span class=\"hljs-keyword\">int</span> p=<span class=\"hljs-number\">4</span>, n=<span class=\"hljs-number\">1000</span>;\r\naf::<span class=\"hljs-built_in\">array</span> consts = af::randu(p);\r\naf::<span class=\"hljs-built_in\">array</span> var_terms = randn(p, n);\r\n\r\ngfor(seq i, n)\r\n    combination(span, i) = <span class=\"hljs-function\">consts * <span class=\"hljs-title\">var_terms</span><span class=\"hljs-params\">(span, i)</span></span>;\r\n</code></pre>\r\n<p>Using GFOR requires following several rules and multiple guidelines for optimal performance.\r\nThe details of this vectorization method can be found in the [GFOR documentation](\\ref gfor).</p>\r\n<h1><a id=\"Batching_127\"></a>Batching</h1>\r\n<p>The <strong>batchFunc()</strong> function allows the broad application of existing Arrayfire\r\nfunctions to multiple sets of data. Effectively, batchFunc() allows Arrayfire\r\nfunctions to execute in “batch processing” mode. In this mode, functions will\r\nfind a dimension which contains “batches” of data to be processed and will\r\nparallelize the procedure.\r\nConsider the following example:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> filter = randn(<span class=\"hljs-number\">1</span>, <span class=\"hljs-number\">5</span>);\r\naf::<span class=\"hljs-built_in\">array</span> weights = randu(<span class=\"hljs-number\">5</span>, <span class=\"hljs-number\">5</span>);\r\n</code></pre>\r\n<p>We have a filter that we would like to apply to each of several weights vectors.\r\nThe naive solution would be using a loop as we’ve seen before:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> filtered_weights = constant(<span class=\"hljs-number\">0</span>, <span class=\"hljs-number\">5</span>, <span class=\"hljs-number\">5</span>);\r\n<span class=\"hljs-keyword\">for</span>(<span class=\"hljs-keyword\">int</span> i=<span class=\"hljs-number\">0</span>; i&lt;weights.dims(<span class=\"hljs-number\">1</span>); ++i){\r\n    filtered_weights.col(i) = filter * weights.col(i);\r\n}\r\n</code></pre>\r\n<p>However we would like a vectorized solution. The following syntax begs to be used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> filtered_weights = filter * weights; <span class=\"hljs-comment\">// fails due to dimension mismatch</span>\r\n</code></pre>\r\n<p>but it fails due to the (5x1), (5x5) dimension mismatch. Wouldn’t it be nice if\r\nArrayfire could figure out along which dimension we intend to apply the batch\r\noperation? That is exactly what <strong>batchFunc()</strong> does!\r\nThe signature of the function is:</p>\r\n<blockquote>\r\n<p>array batchFunc(const array &amp;lhs, const array &amp;rhs, batchFunc_t func);</p>\r\n</blockquote>\r\n<p>where <strong>batchFunc_t</strong> is a function pointer of the form:\r\n<code>typedef array (*batchFunc_t) (const array &amp;lhs, const array &amp;rhs);</code></p>\r\n<p>So, to use <strong>batchFunc()</strong>, we need to provide the function we will be applying as a\r\nbatch operation. For illustration’s sake, let’s “implement” a multiplication\r\nfunction following the format.</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-function\"><span class=\"hljs-built_in\">array</span> <span class=\"hljs-title\">my_mult</span> <span class=\"hljs-params\">(<span class=\"hljs-keyword\">const</span> af::<span class=\"hljs-built_in\">array</span> &amp;lhs, <span class=\"hljs-keyword\">const</span> af::<span class=\"hljs-built_in\">array</span> &amp;rhs)</span></span>{\r\n    <span class=\"hljs-keyword\">return</span> lhs * rhs;\r\n}\r\n</code></pre>\r\n<p>Our final batch call is not much more difficult than the ideal\r\nsyntax we imagined.</p>\r\n<pre><code class=\"language-{.cpp}\"><span class=\"hljs-rule\"><span class=\"hljs-attribute\">af</span>:<span class=\"hljs-value\">:array filtered_weights = <span class=\"hljs-function\">batchFunc</span>( filter, weights, my_mult )</span></span>;\r\n</code></pre>\r\n<p>The batch function will work with many previously mentioned vectorized Arrayfire\r\nfunctions. It can even work with a combination of those functions if they are\r\nwrapped inside a helper function matching the <strong>batchFunc_t</strong> signature. Unfortunately,\r\nthe batch function cannot be used within a gfor() construct at this moment.</p>\r\n<h1><a id=\"Advanced_Vectorization_181\"></a>Advanced Vectorization</h1>\r\n<p>We have seen the different methods Arrayfire provides to vectorize our code. Tying\r\nthem all together is a slightly more involved process that needs to consider data\r\ndimensionality and layout, memory usage, nesting order, etc. An excellent example\r\nand discussion of these factors can be found in another blog post:</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/how-to-write-vectorized-code/\">http://sandbox.arrayfire.com/how-to-write-vectorized-code/</a></p>\r\n<p>It’s worth noting that the content discussed in the blog has since been transformed\r\ninto a convenient <strong>af::nearestNeighbour()</strong> function. Before writing something from\r\nscratch, check that Arrayfire doesn’t already have an implementation. The default\r\nvectorized nature of Arrayfire and an extensive collection of functions will\r\nspeed things up in addition to replacing dozens of lines of code!</p>\r\n\r\n','Introduction to Vectorization','','inherit','open','closed','','8735-revision-v1','','','2015-12-03 20:56:43','2015-12-03 20:56:43','',8735,'http://sandbox.arrayfire.com/8735-revision-v1/',0,'revision','',0),(8737,18673,'2015-12-03 20:59:46','2015-12-03 20:59:46','<p>Programmers and Data Scientists want to take advantage of fast and parallel\r\ncomputational devices. Writing vectorized code is becoming a necessity to get\r\nthe best performance out of the current generation parallel hardware and\r\nscientific computing software. However, writing vectorized code may not be\r\nintuitive immediately. Arrayfire provides many ways to vectorize a given code\r\nsegment. In this tutorial, we will be presenting various ways to vectorize code\r\nusing ArrayFire and the benefits and drawbacks associated with each method.</p>\r\n<h2><a id=\"GenericDefault_vectorization_10\"></a>Generic/Default vectorization</h2>\r\n<p>By its very nature, Arrayfire is a vectorized library. Most functions operate on\r\narrays as a whole – on all elements in parallel. Wherever possible, existing\r\nvectorized functions should be used opposed to manually indexing into arrays.\r\nFor example, consider this valid, yet mislead code that attempts to increment\r\neach element of an array:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> a = af::range(<span class=\"hljs-number\">10</span>); <span class=\"hljs-comment\">// [0,  9]</span>\r\n<span class=\"hljs-keyword\">for</span>(<span class=\"hljs-keyword\">int</span> i = <span class=\"hljs-number\">0</span>; i &lt; a.dims(<span class=\"hljs-number\">0</span>); ++i)\r\n{\r\n    a(i) = a(i) + <span class=\"hljs-number\">1</span>;         <span class=\"hljs-comment\">// [1, 10]</span>\r\n}\r\n</code></pre>\r\n<p>Instead, the existing vectorized Arrayfire overload of the + operator should have been used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> a = af::range(<span class=\"hljs-number\">10</span>);  <span class=\"hljs-comment\">// [0,  9]</span>\r\na = a + <span class=\"hljs-number\">1</span>;                    <span class=\"hljs-comment\">// [1, 10]</span>\r\n</code></pre>\r\n<p>Most Arrayfire functions are vectorized. A small subset of these include:</p>\r\n<p><strong>Arithmetic operations:</strong> +, -, *, / , %, &gt;&gt;, &lt;&lt;</p>\r\n<p><strong>Complex operations:</strong> real(), imag(), conj()…</p>\r\n<p><strong>Exponential and logarithmic functions:</strong> exp(), log(), expm1(), log1p()…</p>\r\n<p><strong>Hyperbolic functions:</strong> sinh(), cosh(), tanh()…</p>\r\n<p><strong>Logical operations:</strong> &amp;&amp;, ||, &lt;, &gt;, ==, !=</p>\r\n<p><strong>Numeric functions:</strong> abs(), floor(), round(), min(), max()…</p>\r\n<p><strong>Trigonometric functions:</strong> sin(), cos(), tan()…</p>\r\n<p>Not only elementwise arithmetic operations are vectorized in Arrayfire.</p>\r\n<p>Vector operations such as <strong>min()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> arr = randn(<span class=\"hljs-number\">100</span>);\r\n<span class=\"hljs-built_in\">std</span>::<span class=\"hljs-built_in\">cout</span> &lt;&lt; min&lt;<span class=\"hljs-keyword\">float</span>&gt;(arr) &lt;&lt; <span class=\"hljs-built_in\">std</span>::endl;\r\n</code></pre>\r\n<p>Signal processing functions like <strong>convolve()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\"><span class=\"hljs-keyword\">float</span> g_coef[] = { <span class=\"hljs-number\">1</span>, <span class=\"hljs-number\">2</span>, <span class=\"hljs-number\">1</span>,\r\n                   <span class=\"hljs-number\">2</span>, <span class=\"hljs-number\">4</span>, <span class=\"hljs-number\">2</span>,\r\n                   <span class=\"hljs-number\">1</span>, <span class=\"hljs-number\">2</span>, <span class=\"hljs-number\">1</span> };\r\n\r\naf::<span class=\"hljs-built_in\">array</span> filter = <span class=\"hljs-number\">1.f</span>/<span class=\"hljs-number\">16</span> * af::<span class=\"hljs-built_in\">array</span>(<span class=\"hljs-number\">3</span>, <span class=\"hljs-number\">3</span>, f_coef);\r\n\r\naf::<span class=\"hljs-built_in\">array</span> signal = randu(WIDTH, HEIGHT, NUM);\r\naf::<span class=\"hljs-built_in\">array</span> conv = convolve2(signal, filter);\r\n</code></pre>\r\n<p>Image processing functions such as <strong>rotate()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> imgs = randu(WIDTH, HEIGHT, <span class=\"hljs-number\">100</span>); <span class=\"hljs-comment\">// 100 (WIDTH x HEIGHT) images</span>\r\naf::<span class=\"hljs-built_in\">array</span> rot_imgs = rotate(imgs, <span class=\"hljs-number\">45</span>); <span class=\"hljs-comment\">// 100 rotated images</span>\r\n</code></pre>\r\n<p>One class of functions that does not support vectorization is the set of linear\r\nalgebra functions. Using the built in vectorized operations should be the first\r\nand preferred method of vectorizing any code written with Arrayfire.</p>\r\n<h2><a id=\"GFOR_Parallel_forloops_76\"></a>GFOR: Parallel for-loops</h2>\r\n<p>Another novel method of vectorization present in Arrayfire is the GFOR loop\r\nreplacement construct. GFOR allows launching all iterations of a loop in parallel\r\non the GPU or device, as long as the iterations are independent. While the\r\nstandard for-loop performs each iteration sequentially, ArrayFire’s gfor-loop\r\nperforms each iteration at the same time (in parallel). ArrayFire does this by\r\ntiling out the values of all loop iterations and then performing computation on\r\nthose tiles in one pass. You can think of gfor as performing auto-vectorization\r\nof your code, e.g. you write a gfor-loop that increments every element of a vector\r\nbut behind the scenes ArrayFire rewrites it to operate on the entire vector in\r\nparallel.</p>\r\n<p>We can remedy our first example with GFOR:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> a = af::range(<span class=\"hljs-number\">10</span>);\r\ngfor(seq i, n)\r\n    a(i) = a(i) + <span class=\"hljs-number\">1</span>;\r\n</code></pre>\r\n<p>To see another example, you could run an <strong>accum()</strong> on every slice of a matrix in a\r\nfor-loop, or you could “vectorize” and simply do it all in one gfor-loop operation:</p>\r\n<pre><code class=\"language-{.cpp}\">for <span class=\"hljs-comment\">(int i = 0; i &lt; N; ++i)</span>\r\n   B<span class=\"hljs-comment\">(span,i)</span> = accum<span class=\"hljs-comment\">(A(span,i)</span>); <span class=\"hljs-comment\">// runs each accum() in sequence</span>\r\ngfor <span class=\"hljs-comment\">(seq i, N)</span>\r\n   B<span class=\"hljs-comment\">(span,i)</span> = accum<span class=\"hljs-comment\">(A(span,i)</span>); <span class=\"hljs-comment\">// runs N accums in parallel</span>\r\n</code></pre>\r\n<p>However, returning to our previous vectorization technique, <strong>accum()</strong> is already\r\nvectorized and the operation could be completely replaced with merely:</p>\r\n<pre><code class=\"language-{.cpp}\">    B = accum(<span class=\"hljs-keyword\">A</span>)<span class=\"hljs-comment\">;</span>\r\n</code></pre>\r\n<p>It is best to vectorize computation as much as possible to avoid the overhead in\r\nboth for-loops and gfor-loops. However, the gfor-loop construct is most effective\r\nin the narrow case of broadcast-style operations. Consider the case when we have\r\na vector of constants that we wish to apply to a collection of variables, such as\r\nexpressing the values of a linear combination for multiple vectors. The broadcast\r\nof one set of constants to many vectors works well with gfor-loops:</p>\r\n<pre><code class=\"language-{.cpp}\"><span class=\"hljs-keyword\">const</span> <span class=\"hljs-keyword\">static</span> <span class=\"hljs-keyword\">int</span> p=<span class=\"hljs-number\">4</span>, n=<span class=\"hljs-number\">1000</span>;\r\naf::<span class=\"hljs-built_in\">array</span> consts = af::randu(p);\r\naf::<span class=\"hljs-built_in\">array</span> var_terms = randn(p, n);\r\n\r\ngfor(seq i, n)\r\n    combination(span, i) = <span class=\"hljs-function\">consts * <span class=\"hljs-title\">var_terms</span><span class=\"hljs-params\">(span, i)</span></span>;\r\n</code></pre>\r\n<p>Using GFOR requires following several rules and multiple guidelines for optimal performance.\r\nThe details of this vectorization method can be found in the [GFOR documentation](\\ref gfor).</p>\r\n<h2><a id=\"Batching_127\"></a>Batching</h2>\r\n<p>The <strong>batchFunc()</strong> function allows the broad application of existing Arrayfire\r\nfunctions to multiple sets of data. Effectively, batchFunc() allows Arrayfire\r\nfunctions to execute in “batch processing” mode. In this mode, functions will\r\nfind a dimension which contains “batches” of data to be processed and will\r\nparallelize the procedure.\r\nConsider the following example:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> filter = randn(<span class=\"hljs-number\">1</span>, <span class=\"hljs-number\">5</span>);\r\naf::<span class=\"hljs-built_in\">array</span> weights = randu(<span class=\"hljs-number\">5</span>, <span class=\"hljs-number\">5</span>);\r\n</code></pre>\r\n<p>We have a filter that we would like to apply to each of several weights vectors.\r\nThe naive solution would be using a loop as we’ve seen before:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> filtered_weights = constant(<span class=\"hljs-number\">0</span>, <span class=\"hljs-number\">5</span>, <span class=\"hljs-number\">5</span>);\r\n<span class=\"hljs-keyword\">for</span>(<span class=\"hljs-keyword\">int</span> i=<span class=\"hljs-number\">0</span>; i&lt;weights.dims(<span class=\"hljs-number\">1</span>); ++i){\r\n    filtered_weights.col(i) = filter * weights.col(i);\r\n}\r\n</code></pre>\r\n<p>However we would like a vectorized solution. The following syntax begs to be used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">array</span> filtered_weights = filter * weights; <span class=\"hljs-comment\">// fails due to dimension mismatch</span>\r\n</code></pre>\r\n<p>but it fails due to the (5x1), (5x5) dimension mismatch. Wouldn’t it be nice if\r\nArrayfire could figure out along which dimension we intend to apply the batch\r\noperation? That is exactly what <strong>batchFunc()</strong> does!\r\nThe signature of the function is:</p>\r\n<blockquote>\r\n<p>array batchFunc(const array &amp;lhs, const array &amp;rhs, batchFunc_t func);</p>\r\n</blockquote>\r\n<p>where <strong>batchFunc_t</strong> is a function pointer of the form:\r\n<code>typedef array (*batchFunc_t) (const array &amp;lhs, const array &amp;rhs);</code></p>\r\n<p>So, to use <strong>batchFunc()</strong>, we need to provide the function we will be applying as a\r\nbatch operation. For illustration’s sake, let’s “implement” a multiplication\r\nfunction following the format.</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-function\"><span class=\"hljs-built_in\">array</span> <span class=\"hljs-title\">my_mult</span> <span class=\"hljs-params\">(<span class=\"hljs-keyword\">const</span> af::<span class=\"hljs-built_in\">array</span> &amp;lhs, <span class=\"hljs-keyword\">const</span> af::<span class=\"hljs-built_in\">array</span> &amp;rhs)</span></span>{\r\n    <span class=\"hljs-keyword\">return</span> lhs * rhs;\r\n}\r\n</code></pre>\r\n<p>Our final batch call is not much more difficult than the ideal\r\nsyntax we imagined.</p>\r\n<pre><code class=\"language-{.cpp}\"><span class=\"hljs-rule\"><span class=\"hljs-attribute\">af</span>:<span class=\"hljs-value\">:array filtered_weights = <span class=\"hljs-function\">batchFunc</span>( filter, weights, my_mult )</span></span>;\r\n</code></pre>\r\n<p>The batch function will work with many previously mentioned vectorized Arrayfire\r\nfunctions. It can even work with a combination of those functions if they are\r\nwrapped inside a helper function matching the <strong>batchFunc_t</strong> signature. Unfortunately,\r\nthe batch function cannot be used within a gfor() construct at this moment.</p>\r\n<h2><a id=\"Advanced_Vectorization_181\"></a>Advanced Vectorization</h2>\r\n<p>We have seen the different methods Arrayfire provides to vectorize our code. Tying\r\nthem all together is a slightly more involved process that needs to consider data\r\ndimensionality and layout, memory usage, nesting order, etc. An excellent example\r\nand discussion of these factors can be found in another blog post:</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/how-to-write-vectorized-code/\">http://sandbox.arrayfire.com/how-to-write-vectorized-code/</a></p>\r\n<p>It’s worth noting that the content discussed in the blog has since been transformed\r\ninto a convenient <strong>af::nearestNeighbour()</strong> function. Before writing something from\r\nscratch, check that Arrayfire doesn’t already have an implementation. The default\r\nvectorized nature of Arrayfire and an extensive collection of functions will\r\nspeed things up in addition to replacing dozens of lines of code!</p>\r\n\r\n','Introduction to Vectorization','','inherit','open','closed','','8735-revision-v1','','','2015-12-03 20:59:46','2015-12-03 20:59:46','',8735,'http://sandbox.arrayfire.com/8735-revision-v1/',0,'revision','',0),(8738,18673,'2015-12-03 21:08:44','2015-12-03 21:08:44','<p>Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be\r\nintuitive immediately. Arrayfire provides many ways to vectorize a given code segment. In this tutorial, we will be presenting various ways to vectorize code using ArrayFire and the benefits and drawbacks associated with each method.</p>\r\n<h2><a id=\"GenericDefault_vectorization_10\"></a>Generic/Default vectorization</h2>\r\n<p>By its very nature, Arrayfire is a vectorized library. Most functions operate on arrays as a whole – on all elements in parallel. Wherever possible, existing vectorized functions should be used opposed to manually indexing into arrays. For example, consider this valid, yet mislead code that attempts to increment each element of an array:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">af::array a = af::range(10); // [0,  9]\r\nfor(int i = 0; i &lt; a.dims(0); ++i)\r\n{\r\n    a(i) = a(i) + 1;         // [1, 10]\r\n}\r\n</code></pre>\r\n<p>Instead, the existing vectorized Arrayfire overload of the + operator should have been used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);  // [0,  9]\r\na = a + 1;                    // [1, 10]\r\n</code></pre>\r\n<p>Most Arrayfire functions are vectorized. A small subset of these include:</p>\r\n<p><strong>Arithmetic operations:</strong> +, -, *, / , %, &gt;&gt;, &lt;&lt;</p>\r\n<p><strong>Complex operations:</strong> real(), imag(), conj()…</p>\r\n<p><strong>Exponential and logarithmic functions:</strong> exp(), log(), expm1(), log1p()…</p>\r\n<p><strong>Hyperbolic functions:</strong> sinh(), cosh(), tanh()…</p>\r\n<p><strong>Logical operations:</strong> &amp;&amp;, ||, &lt;, &gt;, ==, !=</p>\r\n<p><strong>Numeric functions:</strong> abs(), floor(), round(), min(), max()…</p>\r\n<p><strong>Trigonometric functions:</strong> sin(), cos(), tan()…</p>\r\n<p>Not only elementwise arithmetic operations are vectorized in Arrayfire.</p>\r\n<p>Vector operations such as <strong>min()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array arr = randn(100);\r\nstd::cout &lt;&lt; min(arr) &lt;&lt; std::endl;\r\n</code></pre>\r\n<p>Signal processing functions like <strong>convolve()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">float g_coef[] = { 1, 2, 1,\r\n                   2, 4, 2,\r\n                   1, 2, 1 };\r\n\r\naf::array filter = 1.f/16 * af::array(3, 3, f_coef);\r\n\r\naf::array signal = randu(WIDTH, HEIGHT, NUM);\r\naf::array conv = convolve2(signal, filter);\r\n</code></pre>\r\n<p>Image processing functions such as <strong>rotate()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array imgs = randu(WIDTH, HEIGHT, 100); // 100 (WIDTH x HEIGHT) images\r\naf::array rot_imgs = rotate(imgs, 45); // 100 rotated images\r\n</code></pre>\r\n<p>One class of functions that does not support vectorization is the set of linear\r\nalgebra functions. Using the built in vectorized operations should be the first\r\nand preferred method of vectorizing any code written with Arrayfire.</p>\r\n<h2><a id=\"GFOR_Parallel_forloops_76\"></a>GFOR: Parallel for-loops</h2>\r\n<p>Another novel method of vectorization present in Arrayfire is the GFOR loop\r\nreplacement construct. GFOR allows launching all iterations of a loop in parallel\r\non the GPU or device, as long as the iterations are independent. While the\r\nstandard for-loop performs each iteration sequentially, ArrayFire’s gfor-loop\r\nperforms each iteration at the same time (in parallel). ArrayFire does this by\r\ntiling out the values of all loop iterations and then performing computation on\r\nthose tiles in one pass. You can think of gfor as performing auto-vectorization\r\nof your code, e.g. you write a gfor-loop that increments every element of a vector\r\nbut behind the scenes ArrayFire rewrites it to operate on the entire vector in\r\nparallel.</p>\r\n<p>We can remedy our first example with GFOR:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);\r\ngfor(seq i, n)\r\n    a(i) = a(i) + 1;</code></pre>\r\n<p>To see another example, you could run an <strong>accum()</strong> on every slice of a matrix in a\r\nfor-loop, or you could “vectorize” and simply do it all in one gfor-loop operation:</p>\r\n<pre><code class=\"language-{.cpp}\">for (int i = 0; i &lt; N; ++i)\r\n   B(span,i) = accum(A(span,i)); // runs each accum() in sequence\r\ngfor (seq i, N)\r\n   B(span,i) = accum(A(span,i)); // runs N accums in parallel\r\n</code></pre>\r\n<p>However, returning to our previous vectorization technique, <strong>accum()</strong> is already\r\nvectorized and the operation could be completely replaced with merely:</p>\r\n<pre><code class=\"language-{.cpp}\">    B = accum(A);\r\n</code></pre>\r\n<p>It is best to vectorize computation as much as possible to avoid the overhead in\r\nboth for-loops and gfor-loops. However, the gfor-loop construct is most effective\r\nin the narrow case of broadcast-style operations. Consider the case when we have\r\na vector of constants that we wish to apply to a collection of variables, such as\r\nexpressing the values of a linear combination for multiple vectors. The broadcast\r\nof one set of constants to many vectors works well with gfor-loops:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int p=4, n=1000;\r\naf::array consts = af::randu(p);\r\naf::array var_terms = randn(p, n);\r\n\r\ngfor(seq i, n)\r\n    combination(span, i) = consts * var_terms(span, i);\r\n</code></pre>\r\n<p>Using GFOR requires following several rules and multiple guidelines for optimal performance.\r\nThe details of this vectorization method can be found in the [GFOR documentation](\\ref gfor).</p>\r\n<h2><a id=\"Batching_127\"></a>Batching</h2>\r\n<p>The <strong>batchFunc()</strong> function allows the broad application of existing Arrayfire\r\nfunctions to multiple sets of data. Effectively, batchFunc() allows Arrayfire\r\nfunctions to execute in “batch processing” mode. In this mode, functions will\r\nfind a dimension which contains “batches” of data to be processed and will\r\nparallelize the procedure.\r\nConsider the following example:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filter = randn(1, 5);\r\naf::array weights = randu(5, 5);\r\n</code></pre>\r\n<p>We have a filter that we would like to apply to each of several weights vectors.\r\nThe naive solution would be using a loop as we’ve seen before:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = constant(0, 5, 5);\r\nfor(int i=0; i&lt;weights.dims(1); ++i){\r\n    filtered_weights.col(i) = filter * weights.col(i);\r\n}\r\n</code></pre>\r\n<p>However we would like a vectorized solution. The following syntax begs to be used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = filter * weights; // fails due to dimension mismatch\r\n</code></pre>\r\n<p>but it fails due to the (5x1), (5x5) dimension mismatch. Wouldn’t it be nice if\r\nArrayfire could figure out along which dimension we intend to apply the batch\r\noperation? That is exactly what <strong>batchFunc()</strong> does!\r\nThe signature of the function is:</p>\r\n<p>array batchFunc(const array &amp;lhs, const array &amp;rhs, batchFunc_t func);</strong></code></p>\r\n<p>where <strong>batchFunc_t<code><strong></strong> is a function pointer of the form:\r\n<code>typedef array (*batchFunc_t) (const array &amp;lhs, const array &amp;rhs);</code></p>\r\n<p>So, to use <strong>batchFunc()</strong>, we need to provide the function we will be applying as a\r\nbatch operation. For illustration’s sake, let’s “implement” a multiplication\r\nfunction following the format.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array my_mult (const af::array &amp;lhs, const af::array &amp;rhs){\r\n    return lhs * rhs;\r\n}</code></pre>\r\n<p>Our final batch call is not much more difficult than the ideal\r\nsyntax we imagined.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = batchFunc( filter, weights, my_mult );\r\n</code></pre>\r\n<p>The batch function will work with many previously mentioned vectorized Arrayfire\r\nfunctions. It can even work with a combination of those functions if they are\r\nwrapped inside a helper function matching the <strong>batchFunc_t</strong> signature. Unfortunately,\r\nthe batch function cannot be used within a gfor() construct at this moment.</p>\r\n<h2><a id=\"Advanced_Vectorization_181\"></a>Advanced Vectorization</h2>\r\n<p>We have seen the different methods Arrayfire provides to vectorize our code. Tying\r\nthem all together is a slightly more involved process that needs to consider data\r\ndimensionality and layout, memory usage, nesting order, etc. An excellent example\r\nand discussion of these factors can be found in another blog post:</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/how-to-write-vectorized-code/\">http://sandbox.arrayfire.com/how-to-write-vectorized-code/</a></p>\r\n<p>It’s worth noting that the content discussed in the blog has since been transformed\r\ninto a convenient <strong>af::nearestNeighbour()</strong> function. Before writing something from\r\nscratch, check that Arrayfire doesn’t already have an implementation. The default\r\nvectorized nature of Arrayfire and an extensive collection of functions will\r\nspeed things up in addition to replacing dozens of lines of code!</p>\r\n\r\n','Introduction to Vectorization','','inherit','open','closed','','8735-revision-v1','','','2015-12-03 21:08:44','2015-12-03 21:08:44','',8735,'http://sandbox.arrayfire.com/8735-revision-v1/',0,'revision','',0),(8739,18673,'2015-12-03 21:13:37','2015-12-03 21:13:37','<p>Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. Arrayfire provides many ways to vectorize a given code segment. In this tutorial, we will be presenting various ways to vectorize code using ArrayFire and the benefits and drawbacks associated with each method.</p>\r\n<h2><a id=\"GenericDefault_vectorization_10\"></a>Generic/Default vectorization</h2>\r\n<p>By its very nature, Arrayfire is a vectorized library. Most functions operate on arrays as a whole – on all elements in parallel. Wherever possible, existing vectorized functions should be used opposed to manually indexing into arrays. For example, consider this valid, yet mislead code that attempts to increment each element of an array:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">af::array a = af::range(10); // [0,  9]\r\nfor(int i = 0; i &lt; a.dims(0); ++i)\r\n{\r\n    a(i) = a(i) + 1;         // [1, 10]\r\n}\r\n</code></pre>\r\n<p>Instead, the existing vectorized Arrayfire overload of the + operator should have been used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);  // [0,  9]\r\na = a + 1;                    // [1, 10]\r\n</code></pre>\r\n<p>Most Arrayfire functions are vectorized. A small subset of these include:</p>\r\n<p><strong>Arithmetic operations:</strong> +, -, *, / , %, &gt;&gt;, &lt;&lt;</p>\r\n<p><strong>Complex operations:</strong> real(), imag(), conj()…\r\n<strong>Exponential and logarithmic functions:</strong> exp(), log(), expm1(), log1p()…\r\n<strong>Hyperbolic functions:</strong> sinh(), cosh(), tanh()…\r\n<strong>Logical operations:</strong> &amp;&amp;, ||, &lt;, &gt;, ==, !=\r\n<strong>Numeric functions:</strong> abs(), floor(), round(), min(), max()…\r\n<strong>Trigonometric functions:</strong> sin(), cos(), tan()…</p>\r\n<p>Not only elementwise arithmetic operations are vectorized in Arrayfire.</p>\r\n<p>Vector operations such as <strong>min()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array arr = randn(100);\r\nstd::cout &lt;&lt; min(arr) &lt;&lt; std::endl;\r\n</code></pre>\r\n<p>Signal processing functions like <strong>convolve()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">float g_coef[] = { 1, 2, 1,\r\n                   2, 4, 2,\r\n                   1, 2, 1 };\r\n\r\naf::array filter = 1.f/16 * af::array(3, 3, f_coef);\r\n\r\naf::array signal = randu(WIDTH, HEIGHT, NUM);\r\naf::array conv = convolve2(signal, filter);\r\n</code></pre>\r\n<p>Image processing functions such as <strong>rotate()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array imgs = randu(WIDTH, HEIGHT, 100); // 100 (WIDTH x HEIGHT) images\r\naf::array rot_imgs = rotate(imgs, 45); // 100 rotated images\r\n</code></pre>\r\n<p>One class of functions that does not support vectorization is the set of linear\r\nalgebra functions. Using the built in vectorized operations should be the first\r\nand preferred method of vectorizing any code written with Arrayfire.</p>\r\n<h2><a id=\"GFOR_Parallel_forloops_76\"></a>GFOR: Parallel for-loops</h2>\r\n<p>Another novel method of vectorization present in Arrayfire is the GFOR loop\r\nreplacement construct. GFOR allows launching all iterations of a loop in parallel\r\non the GPU or device, as long as the iterations are independent. While the\r\nstandard for-loop performs each iteration sequentially, ArrayFire’s gfor-loop\r\nperforms each iteration at the same time (in parallel). ArrayFire does this by\r\ntiling out the values of all loop iterations and then performing computation on\r\nthose tiles in one pass. You can think of gfor as performing auto-vectorization\r\nof your code, e.g. you write a gfor-loop that increments every element of a vector\r\nbut behind the scenes ArrayFire rewrites it to operate on the entire vector in\r\nparallel.</p>\r\n<p>We can remedy our first example with GFOR:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);\r\ngfor(seq i, n)\r\n    a(i) = a(i) + 1;</code></pre>\r\n<p>To see another example, you could run an <strong>accum()</strong> on every slice of a matrix in a\r\nfor-loop, or you could “vectorize” and simply do it all in one gfor-loop operation:</p>\r\n<pre><code class=\"language-{.cpp}\">for (int i = 0; i &lt; N; ++i)\r\n   B(span,i) = accum(A(span,i)); // runs each accum() in sequence\r\ngfor (seq i, N)\r\n   B(span,i) = accum(A(span,i)); // runs N accums in parallel\r\n</code></pre>\r\n<p>However, returning to our previous vectorization technique, <strong>accum()</strong> is already\r\nvectorized and the operation could be completely replaced with merely:</p>\r\n<pre><code class=\"language-{.cpp}\">    B = accum(A);\r\n</code></pre>\r\n<p>It is best to vectorize computation as much as possible to avoid the overhead in\r\nboth for-loops and gfor-loops. However, the gfor-loop construct is most effective\r\nin the narrow case of broadcast-style operations. Consider the case when we have\r\na vector of constants that we wish to apply to a collection of variables, such as\r\nexpressing the values of a linear combination for multiple vectors. The broadcast\r\nof one set of constants to many vectors works well with gfor-loops:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int p=4, n=1000;\r\naf::array consts = af::randu(p);\r\naf::array var_terms = randn(p, n);\r\n\r\ngfor(seq i, n)\r\n    combination(span, i) = consts * var_terms(span, i);\r\n</code></pre>\r\n<p>Using GFOR requires following several rules and multiple guidelines for optimal performance.\r\nThe details of this vectorization method can be found in the [GFOR documentation](\\ref gfor).</p>\r\n<h2><a id=\"Batching_127\"></a>Batching</h2>\r\n<p>The <strong>batchFunc()</strong> function allows the broad application of existing Arrayfire\r\nfunctions to multiple sets of data. Effectively, batchFunc() allows Arrayfire\r\nfunctions to execute in “batch processing” mode. In this mode, functions will\r\nfind a dimension which contains “batches” of data to be processed and will\r\nparallelize the procedure.\r\nConsider the following example:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filter = randn(1, 5);\r\naf::array weights = randu(5, 5);\r\n</code></pre>\r\n<p>We have a filter that we would like to apply to each of several weights vectors.\r\nThe naive solution would be using a loop as we’ve seen before:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = constant(0, 5, 5);\r\nfor(int i=0; i&lt;weights.dims(1); ++i){\r\n    filtered_weights.col(i) = filter * weights.col(i);\r\n}\r\n</code></pre>\r\n<p>However we would like a vectorized solution. The following syntax begs to be used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = filter * weights; // fails due to dimension mismatch\r\n</code></pre>\r\n<p>but it fails due to the (5x1), (5x5) dimension mismatch. Wouldn’t it be nice if\r\nArrayfire could figure out along which dimension we intend to apply the batch\r\noperation? That is exactly what <strong>batchFunc()</strong> does!\r\nThe signature of the function is:</p>\r\n<p>array batchFunc(const array &amp;lhs, const array &amp;rhs, batchFunc_t func);</strong></code></p>\r\n<p>where <strong>batchFunc_t<code><strong></strong> is a function pointer of the form:\r\n<code>typedef array (*batchFunc_t) (const array &amp;lhs, const array &amp;rhs);</code></p>\r\n<p>So, to use <strong>batchFunc()</strong>, we need to provide the function we will be applying as a\r\nbatch operation. For illustration’s sake, let’s “implement” a multiplication\r\nfunction following the format.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array my_mult (const af::array &amp;lhs, const af::array &amp;rhs){\r\n    return lhs * rhs;\r\n}</code></pre>\r\n<p>Our final batch call is not much more difficult than the ideal\r\nsyntax we imagined.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = batchFunc( filter, weights, my_mult );\r\n</code></pre>\r\n<p>The batch function will work with many previously mentioned vectorized Arrayfire\r\nfunctions. It can even work with a combination of those functions if they are\r\nwrapped inside a helper function matching the <strong>batchFunc_t</strong> signature. Unfortunately,\r\nthe batch function cannot be used within a gfor() construct at this moment.</p>\r\n<h2><a id=\"Advanced_Vectorization_181\"></a>Advanced Vectorization</h2>\r\n<p>We have seen the different methods Arrayfire provides to vectorize our code. Tying\r\nthem all together is a slightly more involved process that needs to consider data\r\ndimensionality and layout, memory usage, nesting order, etc. An excellent example\r\nand discussion of these factors can be found in another blog post:</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/how-to-write-vectorized-code/\">http://sandbox.arrayfire.com/how-to-write-vectorized-code/</a></p>\r\n<p>It’s worth noting that the content discussed in the blog has since been transformed\r\ninto a convenient <strong>af::nearestNeighbour()</strong> function. Before writing something from\r\nscratch, check that Arrayfire doesn’t already have an implementation. The default\r\nvectorized nature of Arrayfire and an extensive collection of functions will\r\nspeed things up in addition to replacing dozens of lines of code!</p>\r\n\r\n','Introduction to Vectorization','','inherit','open','closed','','8735-revision-v1','','','2015-12-03 21:13:37','2015-12-03 21:13:37','',8735,'http://sandbox.arrayfire.com/8735-revision-v1/',0,'revision','',0),(8740,18673,'2015-12-03 21:14:13','2015-12-03 21:14:13','<p>Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. Arrayfire provides many ways to vectorize a given code segment. In this tutorial, we will be presenting various ways to vectorize code using ArrayFire and the benefits and drawbacks associated with each method.</p>\r\n<h2><a id=\"GenericDefault_vectorization_10\"></a>Generic/Default vectorization</h2>\r\n<p>By its very nature, Arrayfire is a vectorized library. Most functions operate on arrays as a whole – on all elements in parallel. Wherever possible, existing vectorized functions should be used opposed to manually indexing into arrays. For example, consider this valid, yet mislead code that attempts to increment each element of an array:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">af::array a = af::range(10); // [0,  9]\r\nfor(int i = 0; i &lt; a.dims(0); ++i)\r\n{\r\n    a(i) = a(i) + 1;         // [1, 10]\r\n}\r\n</code></pre>\r\n<p>Instead, the existing vectorized Arrayfire overload of the + operator should have been used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);  // [0,  9]\r\na = a + 1;                    // [1, 10]\r\n</code></pre>\r\n<p>Most Arrayfire functions are vectorized. A small subset of these include:</p>\r\n<p><strong>Arithmetic operations:</strong> +, -, *, / , %, &gt;&gt;, &lt;&lt;\r\n<strong>Complex operations:</strong> real(), imag(), conj()…\r\n<strong>Exponential and logarithmic functions:</strong> exp(), log(), expm1(), log1p()…\r\n<strong>Hyperbolic functions:</strong> sinh(), cosh(), tanh()…\r\n<strong>Logical operations:</strong> &amp;&amp;, ||, &lt;, &gt;, ==, !=\r\n<strong>Numeric functions:</strong> abs(), floor(), round(), min(), max()…\r\n<strong>Trigonometric functions:</strong> sin(), cos(), tan()…</p>\r\n<p>Not only elementwise arithmetic operations are vectorized in Arrayfire.</p>\r\n<p>Vector operations such as <strong>min()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array arr = randn(100);\r\nstd::cout &lt;&lt; min(arr) &lt;&lt; std::endl;\r\n</code></pre>\r\n<p>Signal processing functions like <strong>convolve()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">float g_coef[] = { 1, 2, 1,\r\n                   2, 4, 2,\r\n                   1, 2, 1 };\r\n\r\naf::array filter = 1.f/16 * af::array(3, 3, f_coef);\r\n\r\naf::array signal = randu(WIDTH, HEIGHT, NUM);\r\naf::array conv = convolve2(signal, filter);\r\n</code></pre>\r\n<p>Image processing functions such as <strong>rotate()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array imgs = randu(WIDTH, HEIGHT, 100); // 100 (WIDTH x HEIGHT) images\r\naf::array rot_imgs = rotate(imgs, 45); // 100 rotated images\r\n</code></pre>\r\n<p>One class of functions that does not support vectorization is the set of linear\r\nalgebra functions. Using the built in vectorized operations should be the first\r\nand preferred method of vectorizing any code written with Arrayfire.</p>\r\n<h2><a id=\"GFOR_Parallel_forloops_76\"></a>GFOR: Parallel for-loops</h2>\r\n<p>Another novel method of vectorization present in Arrayfire is the GFOR loop\r\nreplacement construct. GFOR allows launching all iterations of a loop in parallel\r\non the GPU or device, as long as the iterations are independent. While the\r\nstandard for-loop performs each iteration sequentially, ArrayFire’s gfor-loop\r\nperforms each iteration at the same time (in parallel). ArrayFire does this by\r\ntiling out the values of all loop iterations and then performing computation on\r\nthose tiles in one pass. You can think of gfor as performing auto-vectorization\r\nof your code, e.g. you write a gfor-loop that increments every element of a vector\r\nbut behind the scenes ArrayFire rewrites it to operate on the entire vector in\r\nparallel.</p>\r\n<p>We can remedy our first example with GFOR:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);\r\ngfor(seq i, n)\r\n    a(i) = a(i) + 1;</code></pre>\r\n<p>To see another example, you could run an <strong>accum()</strong> on every slice of a matrix in a\r\nfor-loop, or you could “vectorize” and simply do it all in one gfor-loop operation:</p>\r\n<pre><code class=\"language-{.cpp}\">for (int i = 0; i &lt; N; ++i)\r\n   B(span,i) = accum(A(span,i)); // runs each accum() in sequence\r\ngfor (seq i, N)\r\n   B(span,i) = accum(A(span,i)); // runs N accums in parallel\r\n</code></pre>\r\n<p>However, returning to our previous vectorization technique, <strong>accum()</strong> is already\r\nvectorized and the operation could be completely replaced with merely:</p>\r\n<pre><code class=\"language-{.cpp}\">    B = accum(A);\r\n</code></pre>\r\n<p>It is best to vectorize computation as much as possible to avoid the overhead in\r\nboth for-loops and gfor-loops. However, the gfor-loop construct is most effective\r\nin the narrow case of broadcast-style operations. Consider the case when we have\r\na vector of constants that we wish to apply to a collection of variables, such as\r\nexpressing the values of a linear combination for multiple vectors. The broadcast\r\nof one set of constants to many vectors works well with gfor-loops:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int p=4, n=1000;\r\naf::array consts = af::randu(p);\r\naf::array var_terms = randn(p, n);\r\n\r\ngfor(seq i, n)\r\n    combination(span, i) = consts * var_terms(span, i);\r\n</code></pre>\r\n<p>Using GFOR requires following several rules and multiple guidelines for optimal performance.\r\nThe details of this vectorization method can be found in the [GFOR documentation](\\ref gfor).</p>\r\n<h2><a id=\"Batching_127\"></a>Batching</h2>\r\n<p>The <strong>batchFunc()</strong> function allows the broad application of existing Arrayfire\r\nfunctions to multiple sets of data. Effectively, batchFunc() allows Arrayfire\r\nfunctions to execute in “batch processing” mode. In this mode, functions will\r\nfind a dimension which contains “batches” of data to be processed and will\r\nparallelize the procedure.\r\nConsider the following example:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filter = randn(1, 5);\r\naf::array weights = randu(5, 5);\r\n</code></pre>\r\n<p>We have a filter that we would like to apply to each of several weights vectors.\r\nThe naive solution would be using a loop as we’ve seen before:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = constant(0, 5, 5);\r\nfor(int i=0; i&lt;weights.dims(1); ++i){\r\n    filtered_weights.col(i) = filter * weights.col(i);\r\n}\r\n</code></pre>\r\n<p>However we would like a vectorized solution. The following syntax begs to be used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = filter * weights; // fails due to dimension mismatch\r\n</code></pre>\r\n<p>but it fails due to the (5x1), (5x5) dimension mismatch. Wouldn’t it be nice if\r\nArrayfire could figure out along which dimension we intend to apply the batch\r\noperation? That is exactly what <strong>batchFunc()</strong> does!\r\nThe signature of the function is:</p>\r\n<p>array batchFunc(const array &amp;lhs, const array &amp;rhs, batchFunc_t func);</strong></code></p>\r\n<p>where <strong>batchFunc_t<code><strong></strong> is a function pointer of the form:\r\n<code>typedef array (*batchFunc_t) (const array &amp;lhs, const array &amp;rhs);</code></p>\r\n<p>So, to use <strong>batchFunc()</strong>, we need to provide the function we will be applying as a\r\nbatch operation. For illustration’s sake, let’s “implement” a multiplication\r\nfunction following the format.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array my_mult (const af::array &amp;lhs, const af::array &amp;rhs){\r\n    return lhs * rhs;\r\n}</code></pre>\r\n<p>Our final batch call is not much more difficult than the ideal\r\nsyntax we imagined.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = batchFunc( filter, weights, my_mult );\r\n</code></pre>\r\n<p>The batch function will work with many previously mentioned vectorized Arrayfire\r\nfunctions. It can even work with a combination of those functions if they are\r\nwrapped inside a helper function matching the <strong>batchFunc_t</strong> signature. Unfortunately,\r\nthe batch function cannot be used within a gfor() construct at this moment.</p>\r\n<h2><a id=\"Advanced_Vectorization_181\"></a>Advanced Vectorization</h2>\r\n<p>We have seen the different methods Arrayfire provides to vectorize our code. Tying\r\nthem all together is a slightly more involved process that needs to consider data\r\ndimensionality and layout, memory usage, nesting order, etc. An excellent example\r\nand discussion of these factors can be found in another blog post:</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/how-to-write-vectorized-code/\">http://sandbox.arrayfire.com/how-to-write-vectorized-code/</a></p>\r\n<p>It’s worth noting that the content discussed in the blog has since been transformed\r\ninto a convenient <strong>af::nearestNeighbour()</strong> function. Before writing something from\r\nscratch, check that Arrayfire doesn’t already have an implementation. The default\r\nvectorized nature of Arrayfire and an extensive collection of functions will\r\nspeed things up in addition to replacing dozens of lines of code!</p>\r\n\r\n','Introduction to Vectorization','','inherit','open','closed','','8735-revision-v1','','','2015-12-03 21:14:13','2015-12-03 21:14:13','',8735,'http://sandbox.arrayfire.com/8735-revision-v1/',0,'revision','',0),(8741,18673,'2015-12-03 21:31:42','2015-12-03 21:31:42','<p>Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. Arrayfire provides many ways to vectorize a given code segment. In this tutorial, we will be presenting various ways to vectorize code using ArrayFire and the benefits and drawbacks associated with each method.</p>\r\n<h2><a id=\"GenericDefault_vectorization_10\"></a>Generic/Default vectorization</h2>\r\n<p>By its very nature, Arrayfire is a vectorized library. Most functions operate on arrays as a whole – on all elements in parallel. Wherever possible, existing vectorized functions should be used opposed to manually indexing into arrays. For example, consider this valid, yet mislead code that attempts to increment each element of an array:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">af::array a = af::range(10); // [0,  9]\r\nfor(int i = 0; i &lt; a.dims(0); ++i)\r\n{\r\n    a(i) = a(i) + 1;         // [1, 10]\r\n}\r\n</code></pre>\r\n<p>Instead, the existing vectorized Arrayfire overload of the + operator should have been used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);  // [0,  9]\r\na = a + 1;                    // [1, 10]\r\n</code></pre>\r\n<p>Most Arrayfire functions are vectorized. A small subset of these include:</p>\r\n<p><strong>Arithmetic operations:</strong> +, -, *, / , %, &gt;&gt;, &lt;&lt;\r\n<strong>Complex operations:</strong> real(), imag(), conj()…\r\n<strong>Exponential and logarithmic functions:</strong> exp(), log(), expm1(), log1p()…\r\n<strong>Hyperbolic functions:</strong> sinh(), cosh(), tanh()…\r\n<strong>Logical operations:</strong> &amp;&amp;, ||, &lt;, &gt;, ==, !=\r\n<strong>Numeric functions:</strong> abs(), floor(), round(), min(), max()…\r\n<strong>Trigonometric functions:</strong> sin(), cos(), tan()…</p>\r\n<p>Not only elementwise arithmetic operations are vectorized in Arrayfire.</p>\r\n<p>Vector operations such as <strong>min()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array arr = randn(100);\r\nstd::cout &lt;&lt; min(arr) &lt;&lt; std::endl;\r\n</code></pre>\r\n<p>Signal processing functions like <strong>convolve()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">float g_coef[] = { 1, 2, 1,\r\n                   2, 4, 2,\r\n                   1, 2, 1 };\r\n\r\naf::array filter = 1.f/16 * af::array(3, 3, f_coef);\r\n\r\naf::array signal = randu(WIDTH, HEIGHT, NUM);\r\naf::array conv = convolve2(signal, filter);\r\n</code></pre>\r\n<p>Image processing functions such as <strong>rotate()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array imgs = randu(WIDTH, HEIGHT, 100); // 100 (WIDTH x HEIGHT) images\r\naf::array rot_imgs = rotate(imgs, 45); // 100 rotated images\r\n</code></pre>\r\n<p>One class of functions that does not support vectorization is the set of linear algebra functions. Using the built in vectorized operations should be the first and preferred method of vectorizing any code written with Arrayfire.</p>\r\n<h2><a id=\"GFOR_Parallel_forloops_76\"></a>GFOR: Parallel for-loops</h2>\r\n<p>Another novel method of vectorization present in Arrayfire is the GFOR loop replacement construct. GFOR allows launching all iterations of a loop in parallel on the GPU or device, as long as the iterations are independent. While the standard for-loop performs each iteration sequentially, ArrayFire’s gfor-loop performs each iteration at the same time (in parallel). ArrayFire does this by tiling out the values of all loop iterations and then performing computation on those tiles in one pass. You can think of gfor as performing auto-vectorization of your code, e.g. you write a gfor-loop that increments every element of a vector but behind the scenes ArrayFire rewrites it to operate on the entire vector in parallel.</p>\r\n<p>We can remedy our first example with GFOR:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);\r\ngfor(seq i, n)\r\n    a(i) = a(i) + 1;</code></pre>\r\n<p>To see another example, you could run an <strong>accum()</strong> on every slice of a matrix in a for-loop, or you could “vectorize” and simply do it all in one gfor-loop operation:</p>\r\n<pre><code class=\"language-{.cpp}\">for (int i = 0; i &lt; N; ++i)\r\n   B(span,i) = accum(A(span,i)); // runs each accum() in sequence\r\ngfor (seq i, N)\r\n   B(span,i) = accum(A(span,i)); // runs N accums in parallel\r\n</code></pre>\r\n<p>However, returning to our previous vectorization technique, <strong>accum()</strong> is already vectorized and the operation could be completely replaced with merely:</p>\r\n<pre><code class=\"language-{.cpp}\">    B = accum(A);\r\n</code></pre>\r\n<p>It is best to vectorize computation as much as possible to avoid the overhead in both for-loops and gfor-loops. However, the gfor-loop construct is most effective in the narrow case of broadcast-style operations. Consider the case when we have a vector of constants that we wish to apply to a collection of variables, such as expressing the values of a linear combination for multiple vectors. The broadcast of one set of constants to many vectors works well with gfor-loops:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int p=4, n=1000;\r\naf::array consts = af::randu(p);\r\naf::array var_terms = randn(p, n);\r\n\r\ngfor(seq i, n)\r\n    combination(span, i) = consts * var_terms(span, i);\r\n</code></pre>\r\n<p>Using GFOR requires following several rules and multiple guidelines for optimal performance. The details of this vectorization method can be found in the [GFOR documentation](\\ref gfor).</p>\r\n<h2><a id=\"Batching_127\"></a>Batching</h2>\r\n<p>The <strong>batchFunc()</strong> function allows the broad application of existing Arrayfire functions to multiple sets of data. Effectively, batchFunc() allows Arrayfire functions to execute in “batch processing” mode. In this mode, functions will find a dimension which contains “batches” of data to be processed and will parallelize the procedure. Consider the following example:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filter = randn(1, 5);\r\naf::array weights = randu(5, 5);\r\n</code></pre>\r\n<p>We have a filter that we would like to apply to each of several weights vectors. The naive solution would be using a loop as we’ve seen before:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = constant(0, 5, 5);\r\nfor(int i=0; i&lt;weights.dims(1); ++i){\r\n    filtered_weights.col(i) = filter * weights.col(i);\r\n}\r\n</code></pre>\r\n<p>However we would like a vectorized solution. The following syntax begs to be used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = filter * weights; // fails due to dimension mismatch\r\n</code></pre>\r\n<p>but it fails due to the (5x1), (5x5) dimension mismatch. Wouldn’t it be nice if Arrayfire could figure out along which dimension we intend to apply the batch operation? That is exactly what <strong>batchFunc()</strong> does! The signature of the function is:</p>\r\n<p><code>array batchFunc(const array &amp;lhs, const array &amp;rhs, batchFunc_t func);</strong></code></p>\r\n<p>where <strong>batchFunc_t<code><strong></strong> is a function pointer of the form:\r\n<code>typedef array (*batchFunc_t) (const array &amp;lhs, const array &amp;rhs);</code></p>\r\n<p>So, to use <strong>batchFunc()</strong>, we need to provide the function we will be applying as a batch operation. For illustration’s sake, let’s “implement” a multiplication function following the format.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array my_mult (const af::array &amp;lhs, const af::array &amp;rhs){\r\n    return lhs * rhs;\r\n}</code></pre>\r\n<p>Our final batch call is not much more difficult than the ideal syntax we imagined.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = batchFunc( filter, weights, my_mult );\r\n</code></pre>\r\n<p>The batch function will work with many previously mentioned vectorized Arrayfire functions. It can even work with a combination of those functions if they are wrapped inside a helper function matching the <strong>batchFunc_t</strong> signature. Unfortunately, the batch function cannot be used within a gfor() construct at this moment.</p>\r\n<h2><a id=\"Advanced_Vectorization_181\"></a>Advanced Vectorization</h2>\r\n<p>We have seen the different methods Arrayfire provides to vectorize our code. Tying them all together is a slightly more involved process that needs to consider data dimensionality and layout, memory usage, nesting order, etc. An excellent example and discussion of these factors can be found in another blog post:</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/how-to-write-vectorized-code/\">http://sandbox.arrayfire.com/how-to-write-vectorized-code/</a></p>\r\n<p>It’s worth noting that the whole implementation discussed in the blog has since been transformed into a convenient <strong>af::nearestNeighbour()</strong> function. Before writing something from scratch, check that Arrayfire doesn’t already have an implementation. The default vectorized nature of Arrayfire and an extensive collection of functions will speed things up in addition to replacing dozens of lines of code!</p>\r\n\r\n','Introduction to Vectorization','','inherit','open','closed','','8735-revision-v1','','','2015-12-03 21:31:42','2015-12-03 21:31:42','',8735,'http://sandbox.arrayfire.com/8735-revision-v1/',0,'revision','',0),(8742,18673,'2015-12-03 21:35:50','2015-12-03 21:35:50','<p>Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. Arrayfire provides many ways to vectorize a given code segment. In this tutorial, we will be presenting various ways to vectorize code using ArrayFire and the benefits and drawbacks associated with each method.</p>\r\n<h2><a id=\"GenericDefault_vectorization_10\"></a>Generic/Default vectorization</h2>\r\n<p>By its very nature, Arrayfire is a vectorized library. Most functions operate on arrays as a whole – on all elements in parallel. Wherever possible, existing vectorized functions should be used opposed to manually indexing into arrays. For example, consider this valid, yet mislead code that attempts to increment each element of an array:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">af::array a = af::range(10); // [0,  9]\r\nfor(int i = 0; i &lt; a.dims(0); ++i)\r\n{\r\n    a(i) = a(i) + 1;         // [1, 10]\r\n}\r\n</code></pre>\r\n<p>Instead, the existing vectorized Arrayfire overload of the + operator should have been used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);  // [0,  9]\r\na = a + 1;                    // [1, 10]\r\n</code></pre>\r\n<p>Most Arrayfire functions are vectorized. A small subset of these include:</p>\r\n<p><strong>Arithmetic operations:</strong> +, -, *, / , %, &gt;&gt;, &lt;&lt;\r\n<strong>Complex operations:</strong> real(), imag(), conj()…\r\n<strong>Exponential and logarithmic functions:</strong> exp(), log(), expm1(), log1p()…\r\n<strong>Hyperbolic functions:</strong> sinh(), cosh(), tanh()…\r\n<strong>Logical operations:</strong> &amp;&amp;, ||, &lt;, &gt;, ==, !=\r\n<strong>Numeric functions:</strong> abs(), floor(), round(), min(), max()…\r\n<strong>Trigonometric functions:</strong> sin(), cos(), tan()…</p>\r\n<p>Not only elementwise arithmetic operations are vectorized in Arrayfire.</p>\r\n<p>Vector operations such as <strong>min()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array arr = randn(100);\r\nstd::cout &lt;&lt; min(arr) &lt;&lt; std::endl;\r\n</code></pre>\r\n<p>Signal processing functions like <strong>convolve()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">float g_coef[] = { 1, 2, 1,\r\n                   2, 4, 2,\r\n                   1, 2, 1 };\r\n\r\naf::array filter = 1.f/16 * af::array(3, 3, f_coef);\r\n\r\naf::array signal = randu(WIDTH, HEIGHT, NUM);\r\naf::array conv = convolve2(signal, filter);\r\n</code></pre>\r\n<p>Image processing functions such as <strong>rotate()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array imgs = randu(WIDTH, HEIGHT, 100); // 100 (WIDTH x HEIGHT) images\r\naf::array rot_imgs = rotate(imgs, 45); // 100 rotated images\r\n</code></pre>\r\n<p>One class of functions that does not support vectorization is the set of linear algebra functions. Using the built in vectorized operations should be the first and preferred method of vectorizing any code written with Arrayfire.</p>\r\n<h2><a id=\"GFOR_Parallel_forloops_76\"></a>GFOR: Parallel for-loops</h2>\r\n<p>Another novel method of vectorization present in Arrayfire is the GFOR loop replacement construct. GFOR allows launching all iterations of a loop in parallel on the GPU or device, as long as the iterations are independent. While the standard for-loop performs each iteration sequentially, ArrayFire’s gfor-loop performs each iteration at the same time (in parallel). ArrayFire does this by tiling out the values of all loop iterations and then performing computation on those tiles in one pass. You can think of gfor as performing auto-vectorization of your code, e.g. you write a gfor-loop that increments every element of a vector but behind the scenes ArrayFire rewrites it to operate on the entire vector in parallel.</p>\r\n<p>We can remedy our first example with GFOR:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);\r\ngfor(seq i, n)\r\n    a(i) = a(i) + 1;</code></pre>\r\n<p>To see another example, you could run an <strong>accum()</strong> on every slice of a matrix in a for-loop, or you could “vectorize” and simply do it all in one gfor-loop operation:</p>\r\n<pre><code class=\"language-{.cpp}\">for (int i = 0; i &lt; N; ++i)\r\n   B(span,i) = accum(A(span,i)); // runs each accum() in sequence\r\ngfor (seq i, N)\r\n   B(span,i) = accum(A(span,i)); // runs N accums in parallel\r\n</code></pre>\r\n<p>However, returning to our previous vectorization technique, <strong>accum()</strong> is already vectorized and the operation could be completely replaced with merely:</p>\r\n<pre><code class=\"language-{.cpp}\">    B = accum(A);\r\n</code></pre>\r\n<p>It is best to vectorize computation as much as possible to avoid the overhead in both for-loops and gfor-loops. However, the gfor-loop construct is most effective in the narrow case of broadcast-style operations. Consider the case when we have a vector of constants that we wish to apply to a collection of variables, such as expressing the values of a linear combination for multiple vectors. The broadcast of one set of constants to many vectors works well with gfor-loops:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int p=4, n=1000;\r\naf::array consts = af::randu(p);\r\naf::array var_terms = randn(p, n);\r\n\r\ngfor(seq i, n)\r\n    combination(span, i) = consts * var_terms(span, i);\r\n</code></pre>\r\n<p>Using GFOR requires following several rules and multiple guidelines for optimal performance. The details of this vectorization method can be found in the [GFOR documentation](\\ref gfor).</p>\r\n<h2><a id=\"Batching_127\"></a>Batching</h2>\r\n<p>The <strong>batchFunc()</strong> function allows the broad application of existing Arrayfire functions to multiple sets of data. Effectively, batchFunc() allows Arrayfire functions to execute in “batch processing” mode. In this mode, functions will find a dimension which contains “batches” of data to be processed and will parallelize the procedure. Consider the following example:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filter = randn(1, 5);\r\naf::array weights = randu(5, 5);\r\n</code></pre>\r\n<p>We have a filter that we would like to apply to each of several weights vectors. The naive solution would be using a loop as we’ve seen before:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = constant(0, 5, 5);\r\nfor(int i=0; i &lt; weights.dims(1); ++i){\r\n    filtered_weights.col(i) = filter * weights.col(i);\r\n}\r\n</code></pre>\r\n<p>However we would like a vectorized solution. The following syntax begs to be used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = filter * weights; // fails due to dimension mismatch\r\n</code></pre>\r\n<p>but it fails due to the (5x1), (5x5) dimension mismatch. Wouldn’t it be nice if Arrayfire could figure out along which dimension we intend to apply the batch operation? That is exactly what <strong>batchFunc()</strong> does! The signature of the function is:</p>\r\n<p><code>array batchFunc(const array &amp;lhs, const array &amp;rhs, batchFunc_t func);</strong></code></p>\r\n<p>where <strong>batchFunc_t</strong> is a function pointer of the form:\r\n<code>typedef array (*batchFunc_t) (const array &amp;lhs, const array &amp;rhs);</code></p>\r\n<p>So, to use <strong>batchFunc()</strong>, we need to provide the function we will be applying as a batch operation. For illustration’s sake, let’s “implement” a multiplication function following the format.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array my_mult (const af::array &amp;lhs, const af::array &amp;rhs){\r\n    return lhs * rhs;\r\n}</code></pre>\r\n<p>Our final batch call is not much more difficult than the ideal syntax we imagined.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = batchFunc( filter, weights, my_mult );\r\n</code></pre>\r\n<p>The batch function will work with many previously mentioned vectorized Arrayfire functions. It can even work with a combination of those functions if they are wrapped inside a helper function matching the <strong>batchFunc_t</strong> signature. Unfortunately, the batch function cannot be used within a gfor() construct at this moment.</p>\r\n<h2><a id=\"Advanced_Vectorization_181\"></a>Advanced Vectorization</h2>\r\n<p>We have seen the different methods Arrayfire provides to vectorize our code. Tying them all together is a slightly more involved process that needs to consider data dimensionality and layout, memory usage, nesting order, etc. An excellent example and discussion of these factors can be found in another blog post:</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/how-to-write-vectorized-code/\">http://sandbox.arrayfire.com/how-to-write-vectorized-code/</a></p>\r\n<p>It’s worth noting that the whole implementation discussed in the blog has since been transformed into a convenient <strong>af::nearestNeighbour()</strong> function. Before writing something from scratch, check that Arrayfire doesn’t already have an implementation. The default vectorized nature of Arrayfire and an extensive collection of functions will speed things up in addition to replacing dozens of lines of code!</p>\r\n\r\n','Introduction to Vectorization','','inherit','open','closed','','8735-revision-v1','','','2015-12-03 21:35:50','2015-12-03 21:35:50','',8735,'http://sandbox.arrayfire.com/8735-revision-v1/',0,'revision','',0),(8743,18673,'2015-12-03 21:40:46','2015-12-03 21:40:46','<p>Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. Arrayfire provides many ways to vectorize a given code segment. In this tutorial, we will be presenting various ways to vectorize code using ArrayFire and the benefits and drawbacks associated with each method.</p>\r\n<h2><a id=\"GenericDefault_vectorization_10\"></a>Generic/Default vectorization</h2>\r\n<p>By its very nature, Arrayfire is a vectorized library. Most functions operate on arrays as a whole – on all elements in parallel. Wherever possible, existing vectorized functions should be used opposed to manually indexing into arrays. For example, consider this valid, yet mislead code that attempts to increment each element of an array:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">af::array a = af::range(10); // [0,  9]\r\nfor(int i = 0; i &lt; a.dims(0); ++i)\r\n{\r\n    a(i) = a(i) + 1;         // [1, 10]\r\n}\r\n</code></pre>\r\n<p>Instead, the existing vectorized Arrayfire overload of the + operator should have been used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);  // [0,  9]\r\na = a + 1;                    // [1, 10]\r\n</code></pre>\r\n<p>Most Arrayfire functions are vectorized. A small subset of these include:</p>\r\n<p><strong>Arithmetic operations:</strong> +, -, *, / , %, &gt;&gt;, &lt;&lt;\r\n<strong>Complex operations:</strong> real(), imag(), conj()…\r\n<strong>Exponential and logarithmic functions:</strong> exp(), log(), expm1(), log1p()…\r\n<strong>Hyperbolic functions:</strong> sinh(), cosh(), tanh()…\r\n<strong>Logical operations:</strong> &amp;&amp;, ||, &lt;, &gt;, ==, !=\r\n<strong>Numeric functions:</strong> abs(), floor(), round(), min(), max()…\r\n<strong>Trigonometric functions:</strong> sin(), cos(), tan()…</p>\r\n<p>Not only elementwise arithmetic operations are vectorized in Arrayfire.</p>\r\n<p>Vector operations such as <strong>min()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array arr = randn(100);\r\nstd::cout &lt;&lt; min(arr) &lt;&lt; std::endl;\r\n</code></pre>\r\n<p>Signal processing functions like <strong>convolve()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">float g_coef[] = { 1, 2, 1,\r\n                   2, 4, 2,\r\n                   1, 2, 1 };\r\n\r\naf::array filter = 1.f/16 * af::array(3, 3, f_coef);\r\n\r\naf::array signal = randu(WIDTH, HEIGHT, NUM);\r\naf::array conv = convolve2(signal, filter);\r\n</code></pre>\r\n<p>Image processing functions such as <strong>rotate()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array imgs = randu(WIDTH, HEIGHT, 100); // 100 (WIDTH x HEIGHT) images\r\naf::array rot_imgs = rotate(imgs, 45); // 100 rotated images\r\n</code></pre>\r\n<p>One class of functions that does not support vectorization is the set of linear algebra functions. Using the built in vectorized operations should be the first and preferred method of vectorizing any code written with Arrayfire.</p>\r\n<h2><a id=\"GFOR_Parallel_forloops_76\"></a>GFOR: Parallel for-loops</h2>\r\n<p>Another novel method of vectorization present in Arrayfire is the GFOR loop replacement construct. GFOR allows launching all iterations of a loop in parallel on the GPU or device, as long as the iterations are independent. While the standard for-loop performs each iteration sequentially, ArrayFire’s gfor-loop performs each iteration at the same time (in parallel). ArrayFire does this by tiling out the values of all loop iterations and then performing computation on those tiles in one pass. You can think of gfor as performing auto-vectorization of your code, e.g. you write a gfor-loop that increments every element of a vector but behind the scenes ArrayFire rewrites it to operate on the entire vector in parallel.</p>\r\n<p>We can remedy our first example with GFOR:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);\r\ngfor(seq i, n)\r\n    a(i) = a(i) + 1;</code></pre>\r\n<p>To see another example, you could run an <strong>accum()</strong> on every slice of a matrix in a for-loop, or you could “vectorize” and simply do it all in one gfor-loop operation:</p>\r\n<pre><code class=\"language-{.cpp}\">for (int i = 0; i &lt; N; ++i)\r\n   B(span,i) = accum(A(span,i)); // runs each accum() in sequence\r\ngfor (seq i, N)\r\n   B(span,i) = accum(A(span,i)); // runs N accums in parallel\r\n</code></pre>\r\n<p>However, returning to our previous vectorization technique, <strong>accum()</strong> is already vectorized and the operation could be completely replaced with merely:</p>\r\n<pre><code class=\"language-{.cpp}\">    B = accum(A);\r\n</code></pre>\r\n<p>It is best to vectorize computation as much as possible to avoid the overhead in both for-loops and gfor-loops. However, the gfor-loop construct is most effective in the narrow case of broadcast-style operations. Consider the case when we have a vector of constants that we wish to apply to a collection of variables, such as expressing the values of a linear combination for multiple vectors. The broadcast of one set of constants to many vectors works well with gfor-loops:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int p=4, n=1000;\r\naf::array consts = af::randu(p);\r\naf::array var_terms = randn(p, n);\r\n\r\ngfor(seq i, n)\r\n    combination(span, i) = consts * var_terms(span, i);\r\n</code></pre>\r\n<p>Using GFOR requires following several rules and multiple guidelines for optimal performance. The details of this vectorization method can be found in the [GFOR documentation](\\ref gfor).</p>\r\n<h2><a id=\"Batching_127\"></a>Batching</h2>\r\n<p>The <strong>batchFunc()</strong> function allows the broad application of existing Arrayfire functions to multiple sets of data. Effectively, batchFunc() allows Arrayfire functions to execute in “batch processing” mode. In this mode, functions will find a dimension which contains “batches” of data to be processed and will parallelize the procedure. Consider the following example:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filter = randn(1, 5);\r\naf::array weights = randu(5, 5);\r\n</code></pre>\r\n<p>We have a filter that we would like to apply to each of several weights vectors. The naive solution would be using a loop as we’ve seen before:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = constant(0, 5, 5);\r\nfor(int i=0; i &lt; weights.dims(1); ++i){\r\n    filtered_weights.col(i) = filter * weights.col(i);\r\n}\r\n</code></pre>\r\n<p>However we would like a vectorized solution. The following syntax begs to be used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = filter * weights; // fails due to dimension mismatch\r\n</code></pre>\r\n<p>but it fails due to the (5x1), (5x5) dimension mismatch. Wouldn’t it be nice if Arrayfire could figure out along which dimension we intend to apply the batch operation? That is exactly what <strong>batchFunc()</strong> does! The signature of the function is:\r\n<code>array batchFunc(const array &amp;lhs, const array &amp;rhs, batchFunc_t func);</strong></code></p>\r\n<p>where <strong>batchFunc_t</strong> is a function pointer of the form:\r\n<code>typedef array (*batchFunc_t) (const array &amp;lhs, const array &amp;rhs);</code></p>\r\n<p>So, to use <strong>batchFunc()</strong>, we need to provide the function we will be applying as a batch operation. For illustration’s sake, let’s “implement” a multiplication function following the format.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array my_mult (const af::array &amp; lhs, const af::array &amp; rhs){\r\n    return lhs * rhs;\r\n}</code></pre>\r\n<p>Our final batch call is not much more difficult than the ideal syntax we imagined.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = batchFunc( filter, weights, my_mult );\r\n</code></pre>\r\n<p>The batch function will work with many previously mentioned vectorized Arrayfire functions. It can even work with a combination of those functions if they are wrapped inside a helper function matching the <strong>batchFunc_t</strong> signature. Unfortunately, the batch function cannot be used within a gfor() construct at this moment.</p>\r\n<h2><a id=\"Advanced_Vectorization_181\"></a>Advanced Vectorization</h2>\r\n<p>We have seen the different methods Arrayfire provides to vectorize our code. Tying them all together is a slightly more involved process that needs to consider data dimensionality and layout, memory usage, nesting order, etc. An excellent example and discussion of these factors can be found in another blog post:</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/how-to-write-vectorized-code/\">http://sandbox.arrayfire.com/how-to-write-vectorized-code/</a></p>\r\n<p>It’s worth noting that the whole implementation discussed in the blog has since been transformed into a convenient <strong>af::nearestNeighbour()</strong> function. Before writing something from scratch, check that Arrayfire doesn’t already have an implementation. The default vectorized nature of Arrayfire and an extensive collection of functions will speed things up in addition to replacing dozens of lines of code!</p>\r\n\r\n','Introduction to Vectorization','','inherit','open','closed','','8735-revision-v1','','','2015-12-03 21:40:46','2015-12-03 21:40:46','',8735,'http://sandbox.arrayfire.com/8735-revision-v1/',0,'revision','',0),(8744,18673,'2015-12-03 21:43:30','2015-12-03 21:43:30','<p>Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. Arrayfire provides many ways to vectorize a given code segment. In this tutorial, we will be presenting various ways to vectorize code using ArrayFire and the benefits and drawbacks associated with each method.</p>\r\n<h2><a id=\"GenericDefault_vectorization_10\"></a>Generic/Default vectorization</h2>\r\n<p>By its very nature, Arrayfire is a vectorized library. Most functions operate on arrays as a whole – on all elements in parallel. Wherever possible, existing vectorized functions should be used opposed to manually indexing into arrays. For example, consider this valid, yet mislead code that attempts to increment each element of an array:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">af::array a = af::range(10); // [0,  9]\r\nfor(int i = 0; i &lt; a.dims(0); ++i)\r\n{\r\n    a(i) = a(i) + 1;         // [1, 10]\r\n}\r\n</code></pre>\r\n<p>Instead, the existing vectorized Arrayfire overload of the + operator should have been used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);  // [0,  9]\r\na = a + 1;                    // [1, 10]\r\n</code></pre>\r\n<p>Most Arrayfire functions are vectorized. A small subset of these include:</p>\r\n<p><strong>Arithmetic operations:</strong> +, -, *, / , %, &gt;&gt;, &lt;&lt;\r\n<strong>Complex operations:</strong> real(), imag(), conj()…\r\n<strong>Exponential and logarithmic functions:</strong> exp(), log(), expm1(), log1p()…\r\n<strong>Hyperbolic functions:</strong> sinh(), cosh(), tanh()…\r\n<strong>Logical operations:</strong> &amp;&amp;, ||, &lt;, &gt;, ==, !=\r\n<strong>Numeric functions:</strong> abs(), floor(), round(), min(), max()…\r\n<strong>Trigonometric functions:</strong> sin(), cos(), tan()…</p>\r\n<p>Not only elementwise arithmetic operations are vectorized in Arrayfire.</p>\r\n<p>Vector operations such as <strong>min()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array arr = randn(100);\r\nstd::cout &lt;&lt; min(arr) &lt;&lt; std::endl;\r\n</code></pre>\r\n<p>Signal processing functions like <strong>convolve()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">float g_coef[] = { 1, 2, 1,\r\n                   2, 4, 2,\r\n                   1, 2, 1 };\r\n\r\naf::array filter = 1.f/16 * af::array(3, 3, f_coef);\r\n\r\naf::array signal = randu(WIDTH, HEIGHT, NUM);\r\naf::array conv = convolve2(signal, filter);\r\n</code></pre>\r\n<p>Image processing functions such as <strong>rotate()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array imgs = randu(WIDTH, HEIGHT, 100); // 100 (WIDTH x HEIGHT) images\r\naf::array rot_imgs = rotate(imgs, 45); // 100 rotated images\r\n</code></pre>\r\n<p>One class of functions that does not support vectorization is the set of linear algebra functions. Using the built in vectorized operations should be the first and preferred method of vectorizing any code written with Arrayfire.</p>\r\n<h2><a id=\"GFOR_Parallel_forloops_76\"></a>GFOR: Parallel for-loops</h2>\r\n<p>Another novel method of vectorization present in Arrayfire is the GFOR loop replacement construct. GFOR allows launching all iterations of a loop in parallel on the GPU or device, as long as the iterations are independent. While the standard for-loop performs each iteration sequentially, ArrayFire’s gfor-loop performs each iteration at the same time (in parallel). ArrayFire does this by tiling out the values of all loop iterations and then performing computation on those tiles in one pass. You can think of gfor as performing auto-vectorization of your code, e.g. you write a gfor-loop that increments every element of a vector but behind the scenes ArrayFire rewrites it to operate on the entire vector in parallel.</p>\r\n<p>We can remedy our first example with GFOR:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);\r\ngfor(seq i, n)\r\n    a(i) = a(i) + 1;</code></pre>\r\n<p>To see another example, you could run an <strong>accum()</strong> on every slice of a matrix in a for-loop, or you could “vectorize” and simply do it all in one gfor-loop operation:</p>\r\n<pre><code class=\"language-{.cpp}\">for (int i = 0; i &lt; N; ++i)\r\n   B(span,i) = accum(A(span,i)); // runs each accum() in sequence\r\ngfor (seq i, N)\r\n   B(span,i) = accum(A(span,i)); // runs N accums in parallel\r\n</code></pre>\r\n<p>However, returning to our previous vectorization technique, <strong>accum()</strong> is already vectorized and the operation could be completely replaced with merely:</p>\r\n<pre><code class=\"language-{.cpp}\">    B = accum(A);\r\n</code></pre>\r\n<p>It is best to vectorize computation as much as possible to avoid the overhead in both for-loops and gfor-loops. However, the gfor-loop construct is most effective in the narrow case of broadcast-style operations. Consider the case when we have a vector of constants that we wish to apply to a collection of variables, such as expressing the values of a linear combination for multiple vectors. The broadcast of one set of constants to many vectors works well with gfor-loops:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int p=4, n=1000;\r\naf::array consts = af::randu(p);\r\naf::array var_terms = randn(p, n);\r\n\r\ngfor(seq i, n)\r\n    combination(span, i) = consts * var_terms(span, i);\r\n</code></pre>\r\n<p>Using GFOR requires following several rules and multiple guidelines for optimal performance. The details of this vectorization method can be found in the [GFOR documentation](\\ref gfor).</p>\r\n<h2><a id=\"Batching_127\"></a>Batching</h2>\r\n<p>The <strong>batchFunc()</strong> function allows the broad application of existing Arrayfire functions to multiple sets of data. Effectively, batchFunc() allows Arrayfire functions to execute in “batch processing” mode. In this mode, functions will find a dimension which contains “batches” of data to be processed and will parallelize the procedure. Consider the following example:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filter = randn(1, 5);\r\naf::array weights = randu(5, 5);\r\n</code></pre>\r\n<p>We have a filter that we would like to apply to each of several weights vectors. The naive solution would be using a loop as we’ve seen before:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = constant(0, 5, 5);\r\nfor(int i=0; i &lt; weights.dims(1); ++i){\r\n    filtered_weights.col(i) = filter * weights.col(i);\r\n}\r\n</code></pre>\r\n<p>However we would like a vectorized solution. The following syntax begs to be used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = filter * weights; // fails due to dimension mismatch\r\n</code></pre>\r\n<p>but it fails due to the (5x1), (5x5) dimension mismatch. Wouldn’t it be nice if Arrayfire could figure out along which dimension we intend to apply the batch operation? That is exactly what <strong>batchFunc()</strong> does! The signature of the function is:\r\n<code>array batchFunc(const array &amp;lhs, const array &amp;rhs, batchFunc_t func);</strong></code></p>\r\n<p>where <strong>batchFunc_t</strong> is a function pointer of the form:\r\n<code>typedef array (*batchFunc_t) (const array &amp;lhs, const array &amp;rhs);</code>\r\nSo, to use <strong>batchFunc()</strong>, we need to provide the function we will be applying as a batch operation. For illustration’s sake, let’s “implement” a multiplication function following the format.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array my_mult (const af::array &amp; lhs, const af::array &amp; rhs){\r\n    return lhs * rhs;\r\n}</code></pre>\r\n<p>Our final batch call is not much more difficult than the ideal syntax we imagined.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = batchFunc( filter, weights, my_mult );\r\n</code></pre>\r\n<p>The batch function will work with many previously mentioned vectorized Arrayfire functions. It can even work with a combination of those functions if they are wrapped inside a helper function matching the <strong>batchFunc_t</strong> signature. Unfortunately, the batch function cannot be used within a gfor() construct at this moment.</p>\r\n<h2><a id=\"Advanced_Vectorization_181\"></a>Advanced Vectorization</h2>\r\n<p>We have seen the different methods Arrayfire provides to vectorize our code. Tying them all together is a slightly more involved process that needs to consider data dimensionality and layout, memory usage, nesting order, etc. An excellent example and discussion of these factors can be found in another blog post:</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/how-to-write-vectorized-code/\">http://sandbox.arrayfire.com/how-to-write-vectorized-code/</a></p>\r\n<p>It’s worth noting that the whole implementation discussed in the blog has since been transformed into a convenient <strong>af::nearestNeighbour()</strong> function. Before writing something from scratch, check that Arrayfire doesn’t already have an implementation. The default vectorized nature of Arrayfire and an extensive collection of functions will speed things up in addition to replacing dozens of lines of code!</p>\r\n\r\n','Introduction to Vectorization','','inherit','open','closed','','8735-revision-v1','','','2015-12-03 21:43:30','2015-12-03 21:43:30','',8735,'http://sandbox.arrayfire.com/8735-revision-v1/',0,'revision','',0),(8745,18673,'2015-12-03 21:44:18','2015-12-03 21:44:18','<p>Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. Arrayfire provides many ways to vectorize a given code segment. In this tutorial, we will be presenting various ways to vectorize code using ArrayFire and the benefits and drawbacks associated with each method.</p>\r\n<h2><a id=\"GenericDefault_vectorization_10\"></a>Generic/Default vectorization</h2>\r\n<p>By its very nature, Arrayfire is a vectorized library. Most functions operate on arrays as a whole – on all elements in parallel. Wherever possible, existing vectorized functions should be used opposed to manually indexing into arrays. For example, consider this valid, yet mislead code that attempts to increment each element of an array:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">af::array a = af::range(10); // [0,  9]\r\nfor(int i = 0; i &lt; a.dims(0); ++i)\r\n{\r\n    a(i) = a(i) + 1;         // [1, 10]\r\n}\r\n</code></pre>\r\n<p>Instead, the existing vectorized Arrayfire overload of the + operator should have been used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);  // [0,  9]\r\na = a + 1;                    // [1, 10]\r\n</code></pre>\r\n<p>Most Arrayfire functions are vectorized. A small subset of these include:</p>\r\n<p><strong>Arithmetic operations:</strong> +, -, *, / , %, &gt;&gt;, &lt;&lt;\r\n<strong>Complex operations:</strong> real(), imag(), conj()…\r\n<strong>Exponential and logarithmic functions:</strong> exp(), log(), expm1(), log1p()…\r\n<strong>Hyperbolic functions:</strong> sinh(), cosh(), tanh()…\r\n<strong>Logical operations:</strong> &amp;&amp;, ||, &lt;, &gt;, ==, !=\r\n<strong>Numeric functions:</strong> abs(), floor(), round(), min(), max()…\r\n<strong>Trigonometric functions:</strong> sin(), cos(), tan()…</p>\r\n<p>Not only elementwise arithmetic operations are vectorized in Arrayfire.</p>\r\n<p>Vector operations such as <strong>min()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array arr = randn(100);\r\nstd::cout &lt;&lt; min(arr) &lt;&lt; std::endl;\r\n</code></pre>\r\n<p>Signal processing functions like <strong>convolve()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">float g_coef[] = { 1, 2, 1,\r\n                   2, 4, 2,\r\n                   1, 2, 1 };\r\n\r\naf::array filter = 1.f/16 * af::array(3, 3, f_coef);\r\n\r\naf::array signal = randu(WIDTH, HEIGHT, NUM);\r\naf::array conv = convolve2(signal, filter);\r\n</code></pre>\r\n<p>Image processing functions such as <strong>rotate()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array imgs = randu(WIDTH, HEIGHT, 100); // 100 (WIDTH x HEIGHT) images\r\naf::array rot_imgs = rotate(imgs, 45); // 100 rotated images\r\n</code></pre>\r\n<p>One class of functions that does not support vectorization is the set of linear algebra functions. Using the built in vectorized operations should be the first and preferred method of vectorizing any code written with Arrayfire.</p>\r\n<h2><a id=\"GFOR_Parallel_forloops_76\"></a>GFOR: Parallel for-loops</h2>\r\n<p>Another novel method of vectorization present in Arrayfire is the GFOR loop replacement construct. GFOR allows launching all iterations of a loop in parallel on the GPU or device, as long as the iterations are independent. While the standard for-loop performs each iteration sequentially, ArrayFire’s gfor-loop performs each iteration at the same time (in parallel). ArrayFire does this by tiling out the values of all loop iterations and then performing computation on those tiles in one pass. You can think of gfor as performing auto-vectorization of your code, e.g. you write a gfor-loop that increments every element of a vector but behind the scenes ArrayFire rewrites it to operate on the entire vector in parallel.</p>\r\n<p>We can remedy our first example with GFOR:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);\r\ngfor(seq i, n)\r\n    a(i) = a(i) + 1;</code></pre>\r\n<p>To see another example, you could run an <strong>accum()</strong> on every slice of a matrix in a for-loop, or you could “vectorize” and simply do it all in one gfor-loop operation:</p>\r\n<pre><code class=\"language-{.cpp}\">for (int i = 0; i &lt; N; ++i)\r\n   B(span,i) = accum(A(span,i)); // runs each accum() in sequence\r\ngfor (seq i, N)\r\n   B(span,i) = accum(A(span,i)); // runs N accums in parallel\r\n</code></pre>\r\n<p>However, returning to our previous vectorization technique, <strong>accum()</strong> is already vectorized and the operation could be completely replaced with merely:</p>\r\n<pre><code class=\"language-{.cpp}\">    B = accum(A);\r\n</code></pre>\r\n<p>It is best to vectorize computation as much as possible to avoid the overhead in both for-loops and gfor-loops. However, the gfor-loop construct is most effective in the narrow case of broadcast-style operations. Consider the case when we have a vector of constants that we wish to apply to a collection of variables, such as expressing the values of a linear combination for multiple vectors. The broadcast of one set of constants to many vectors works well with gfor-loops:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int p=4, n=1000;\r\naf::array consts = af::randu(p);\r\naf::array var_terms = randn(p, n);\r\n\r\ngfor(seq i, n)\r\n    combination(span, i) = consts * var_terms(span, i);\r\n</code></pre>\r\n<p>Using GFOR requires following several rules and multiple guidelines for optimal performance. The details of this vectorization method can be found in the [GFOR documentation](\\ref gfor).</p>\r\n<h2><a id=\"Batching_127\"></a>Batching</h2>\r\n<p>The <strong>batchFunc()</strong> function allows the broad application of existing Arrayfire functions to multiple sets of data. Effectively, batchFunc() allows Arrayfire functions to execute in “batch processing” mode. In this mode, functions will find a dimension which contains “batches” of data to be processed and will parallelize the procedure. Consider the following example:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filter = randn(1, 5);\r\naf::array weights = randu(5, 5);\r\n</code></pre>\r\n<p>We have a filter that we would like to apply to each of several weights vectors. The naive solution would be using a loop as we’ve seen before:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = constant(0, 5, 5);\r\nfor(int i=0; i &lt; weights.dims(1); ++i){\r\n    filtered_weights.col(i) = filter * weights.col(i);\r\n}\r\n</code></pre>\r\n<p>However we would like a vectorized solution. The following syntax begs to be used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = filter * weights; // fails due to dimension mismatch\r\n</code></pre>\r\n<p>but it fails due to the (5x1), (5x5) dimension mismatch. Wouldn’t it be nice if Arrayfire could figure out along which dimension we intend to apply the batch operation? That is exactly what <strong>batchFunc()</strong> does! The signature of the function is:\r\n<code>array batchFunc(const array &amp;lhs, const array &amp;rhs, batchFunc_t func);</strong></code>\r\nwhere <strong>batchFunc_t</strong> is a function pointer of the form:\r\n<code>typedef array (*batchFunc_t) (const array &amp;lhs, const array &amp;rhs);</code></p>\r\n<p>So, to use <strong>batchFunc()</strong>, we need to provide the function we will be applying as a batch operation. For illustration’s sake, let’s “implement” a multiplication function following the format.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array my_mult (const af::array &amp; lhs, const af::array &amp; rhs){\r\n    return lhs * rhs;\r\n}</code></pre>\r\n<p>Our final batch call is not much more difficult than the ideal syntax we imagined.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = batchFunc( filter, weights, my_mult );\r\n</code></pre>\r\n<p>The batch function will work with many previously mentioned vectorized Arrayfire functions. It can even work with a combination of those functions if they are wrapped inside a helper function matching the <strong>batchFunc_t</strong> signature. Unfortunately, the batch function cannot be used within a gfor() construct at this moment.</p>\r\n<h2><a id=\"Advanced_Vectorization_181\"></a>Advanced Vectorization</h2>\r\n<p>We have seen the different methods Arrayfire provides to vectorize our code. Tying them all together is a slightly more involved process that needs to consider data dimensionality and layout, memory usage, nesting order, etc. An excellent example and discussion of these factors can be found in another blog post:</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/how-to-write-vectorized-code/\">http://sandbox.arrayfire.com/how-to-write-vectorized-code/</a></p>\r\n<p>It’s worth noting that the whole implementation discussed in the blog has since been transformed into a convenient <strong>af::nearestNeighbour()</strong> function. Before writing something from scratch, check that Arrayfire doesn’t already have an implementation. The default vectorized nature of Arrayfire and an extensive collection of functions will speed things up in addition to replacing dozens of lines of code!</p>\r\n\r\n','Introduction to Vectorization','','inherit','open','closed','','8735-revision-v1','','','2015-12-03 21:44:18','2015-12-03 21:44:18','',8735,'http://sandbox.arrayfire.com/8735-revision-v1/',0,'revision','',0),(8746,18673,'2015-12-03 21:47:49','2015-12-03 21:47:49','<p>Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. Arrayfire provides many ways to vectorize a given code segment. In this tutorial, we will be presenting various ways to vectorize code using ArrayFire and the benefits and drawbacks associated with each method.</p>\r\n<h2><a id=\"GenericDefault_vectorization_10\"></a>Generic/Default vectorization</h2>\r\n<p>By its very nature, Arrayfire is a vectorized library. Most functions operate on arrays as a whole – on all elements in parallel. Wherever possible, existing vectorized functions should be used opposed to manually indexing into arrays. For example, consider this valid, yet mislead code that attempts to increment each element of an array:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10); // [0,  9]\r\nfor(int i = 0; i &lt; a.dims(0); ++i)\r\n{\r\n    a(i) = a(i) + 1;         // [1, 10]\r\n}\r\n</code></pre>\r\n<p>Instead, the existing vectorized Arrayfire overload of the + operator should have been used:</p>\r\n<pre><code class=\"language-{.cpp}\">\r\naf::array a = af::range(10);  // [0,  9]\r\na = a + 1;                    // [1, 10]\r\n</code></pre>\r\n<p>Most Arrayfire functions are vectorized. A small subset of these include:</p>\r\n<p><strong>Arithmetic operations:</strong> +, -, *, / , %, &gt;&gt;, &lt;&lt;\r\n<strong>Complex operations:</strong> real(), imag(), conj()…\r\n<strong>Exponential and logarithmic functions:</strong> exp(), log(), expm1(), log1p()…\r\n<strong>Hyperbolic functions:</strong> sinh(), cosh(), tanh()…\r\n<strong>Logical operations:</strong> &amp;&amp;, ||, &lt;, &gt;, ==, !=\r\n<strong>Numeric functions:</strong> abs(), floor(), round(), min(), max()…\r\n<strong>Trigonometric functions:</strong> sin(), cos(), tan()…</p>\r\n<p>Not only elementwise arithmetic operations are vectorized in Arrayfire.</p>\r\n<p>Vector operations such as <strong>min()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array arr = randn(100);\r\nstd::cout &lt;&lt; min(arr) &lt;&lt; std::endl;\r\n</code></pre>\r\n<p>Signal processing functions like <strong>convolve()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">float g_coef[] = { 1, 2, 1,\r\n                   2, 4, 2,\r\n                   1, 2, 1 };\r\n\r\naf::array filter = 1.f/16 * af::array(3, 3, f_coef);\r\n\r\naf::array signal = randu(WIDTH, HEIGHT, NUM);\r\naf::array conv = convolve2(signal, filter);\r\n</code></pre>\r\n<p>Image processing functions such as <strong>rotate()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array imgs = randu(WIDTH, HEIGHT, 100); // 100 (WIDTH x HEIGHT) images\r\naf::array rot_imgs = rotate(imgs, 45); // 100 rotated images\r\n</code></pre>\r\n<p>One class of functions that does not support vectorization is the set of linear algebra functions. Using the built in vectorized operations should be the first and preferred method of vectorizing any code written with Arrayfire.</p>\r\n<h2><a id=\"GFOR_Parallel_forloops_76\"></a>GFOR: Parallel for-loops</h2>\r\n<p>Another novel method of vectorization present in Arrayfire is the GFOR loop replacement construct. GFOR allows launching all iterations of a loop in parallel on the GPU or device, as long as the iterations are independent. While the standard for-loop performs each iteration sequentially, ArrayFire’s gfor-loop performs each iteration at the same time (in parallel). ArrayFire does this by tiling out the values of all loop iterations and then performing computation on those tiles in one pass. You can think of gfor as performing auto-vectorization of your code, e.g. you write a gfor-loop that increments every element of a vector but behind the scenes ArrayFire rewrites it to operate on the entire vector in parallel.</p>\r\n<p>We can remedy our first example with GFOR:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);\r\ngfor(seq i, n)\r\n    a(i) = a(i) + 1;</code></pre>\r\n<p>To see another example, you could run an <strong>accum()</strong> on every slice of a matrix in a for-loop, or you could “vectorize” and simply do it all in one gfor-loop operation:</p>\r\n<pre><code class=\"language-{.cpp}\">for (int i = 0; i &lt; N; ++i)\r\n   B(span,i) = accum(A(span,i)); // runs each accum() in sequence\r\ngfor (seq i, N)\r\n   B(span,i) = accum(A(span,i)); // runs N accums in parallel\r\n</code></pre>\r\n<p>However, returning to our previous vectorization technique, <strong>accum()</strong> is already vectorized and the operation could be completely replaced with merely:</p>\r\n<pre><code class=\"language-{.cpp}\">    B = accum(A);\r\n</code></pre>\r\n<p>It is best to vectorize computation as much as possible to avoid the overhead in both for-loops and gfor-loops. However, the gfor-loop construct is most effective in the narrow case of broadcast-style operations. Consider the case when we have a vector of constants that we wish to apply to a collection of variables, such as expressing the values of a linear combination for multiple vectors. The broadcast of one set of constants to many vectors works well with gfor-loops:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int p=4, n=1000;\r\naf::array consts = af::randu(p);\r\naf::array var_terms = randn(p, n);\r\n\r\ngfor(seq i, n)\r\n    combination(span, i) = consts * var_terms(span, i);\r\n</code></pre>\r\n<p>Using GFOR requires following several rules and multiple guidelines for optimal performance. The details of this vectorization method can be found in the [GFOR documentation](\\ref gfor).</p>\r\n<h2><a id=\"Batching_127\"></a>Batching</h2>\r\n<p>The <strong>batchFunc()</strong> function allows the broad application of existing Arrayfire functions to multiple sets of data. Effectively, batchFunc() allows Arrayfire functions to execute in “batch processing” mode. In this mode, functions will find a dimension which contains “batches” of data to be processed and will parallelize the procedure. Consider the following example:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filter = randn(1, 5);\r\naf::array weights = randu(5, 5);\r\n</code></pre>\r\n<p>We have a filter that we would like to apply to each of several weights vectors. The naive solution would be using a loop as we’ve seen before:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = constant(0, 5, 5);\r\nfor(int i=0; i &lt; weights.dims(1); ++i){\r\n    filtered_weights.col(i) = filter * weights.col(i);\r\n}\r\n</code></pre>\r\n<p>However we would like a vectorized solution. The following syntax begs to be used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = filter * weights; // fails due to dimension mismatch\r\n</code></pre>\r\n<p>but it fails due to the (5x1), (5x5) dimension mismatch. Wouldn’t it be nice if Arrayfire could figure out along which dimension we intend to apply the batch operation? That is exactly what <strong>batchFunc()</strong> does! The signature of the function is:\r\n<code>array batchFunc(const array &amp;lhs, const array &amp;rhs, batchFunc_t func);</strong></code>\r\nwhere <strong>batchFunc_t</strong> is a function pointer of the form:\r\n<code>typedef array (*batchFunc_t) (const array &amp;lhs, const array &amp;rhs);</code></p>\r\n<p>So, to use <strong>batchFunc()</strong>, we need to provide the function we will be applying as a batch operation. For illustration’s sake, let’s “implement” a multiplication function following the format.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array my_mult (const af::array &amp; lhs, const af::array &amp; rhs){\r\n    return lhs * rhs;\r\n}</code></pre>\r\n<p>Our final batch call is not much more difficult than the ideal syntax we imagined.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = batchFunc( filter, weights, my_mult );\r\n</code></pre>\r\n<p>The batch function will work with many previously mentioned vectorized Arrayfire functions. It can even work with a combination of those functions if they are wrapped inside a helper function matching the <strong>batchFunc_t</strong> signature. Unfortunately, the batch function cannot be used within a gfor() construct at this moment.</p>\r\n<h2><a id=\"Advanced_Vectorization_181\"></a>Advanced Vectorization</h2>\r\n<p>We have seen the different methods Arrayfire provides to vectorize our code. Tying them all together is a slightly more involved process that needs to consider data dimensionality and layout, memory usage, nesting order, etc. An excellent example and discussion of these factors can be found in another blog post:</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/how-to-write-vectorized-code/\">http://sandbox.arrayfire.com/how-to-write-vectorized-code/</a></p>\r\n<p>It’s worth noting that the whole implementation discussed in the blog has since been transformed into a convenient <strong>af::nearestNeighbour()</strong> function. Before writing something from scratch, check that Arrayfire doesn’t already have an implementation. The default vectorized nature of Arrayfire and an extensive collection of functions will speed things up in addition to replacing dozens of lines of code!</p>\r\n\r\n','Introduction to Vectorization','','inherit','open','closed','','8735-revision-v1','','','2015-12-03 21:47:49','2015-12-03 21:47:49','',8735,'http://sandbox.arrayfire.com/8735-revision-v1/',0,'revision','',0),(8747,18673,'2015-12-03 21:49:40','2015-12-03 21:49:40','<p>Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. Arrayfire provides many ways to vectorize a given code segment. In this tutorial, we will be presenting various ways to vectorize code using ArrayFire and the benefits and drawbacks associated with each method.</p>\r\n<h2><a id=\"GenericDefault_vectorization_10\"></a>Generic/Default vectorization</h2>\r\n<p>By its very nature, Arrayfire is a vectorized library. Most functions operate on arrays as a whole – on all elements in parallel. Wherever possible, existing vectorized functions should be used opposed to manually indexing into arrays. For example, consider this valid, yet mislead code that attempts to increment each element of an array:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10); // [0,  9]\r\nfor(int i = 0; i &lt; ims(0); ++i)\r\n{\r\n    a(i) = a(i) + 1;         // [1, 10]\r\n}\r\n</code></pre>\r\n<p>Instead, the existing vectorized Arrayfire overload of the + operator should have been used:</p>\r\n<pre><code class=\"language-{.cpp}\">\r\naf::array a = af::range(10);  // [0,  9]\r\na = a + 1;                    // [1, 10]\r\n</code></pre>\r\n<p>Most Arrayfire functions are vectorized. A small subset of these include:</p>\r\n<p><strong>Arithmetic operations:</strong> +, -, *, / , %, &gt;&gt;, &lt;&lt;\r\n<strong>Complex operations:</strong> real(), imag(), conj()…\r\n<strong>Exponential and logarithmic functions:</strong> exp(), log(), expm1(), log1p()…\r\n<strong>Hyperbolic functions:</strong> sinh(), cosh(), tanh()…\r\n<strong>Logical operations:</strong> &amp;&amp;, ||, &lt;, &gt;, ==, !=\r\n<strong>Numeric functions:</strong> abs(), floor(), round(), min(), max()…\r\n<strong>Trigonometric functions:</strong> sin(), cos(), tan()…</p>\r\n<p>Not only elementwise arithmetic operations are vectorized in Arrayfire.</p>\r\n<p>Vector operations such as <strong>min()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array arr = randn(100);\r\nstd::cout &lt;&lt; min(arr) &lt;&lt; std::endl;\r\n</code></pre>\r\n<p>Signal processing functions like <strong>convolve()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">float g_coef[] = { 1, 2, 1,\r\n                   2, 4, 2,\r\n                   1, 2, 1 };\r\n\r\naf::array filter = 1.f/16 * af::array(3, 3, f_coef);\r\n\r\naf::array signal = randu(WIDTH, HEIGHT, NUM);\r\naf::array conv = convolve2(signal, filter);\r\n</code></pre>\r\n<p>Image processing functions such as <strong>rotate()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array imgs = randu(WIDTH, HEIGHT, 100); // 100 (WIDTH x HEIGHT) images\r\naf::array rot_imgs = rotate(imgs, 45); // 100 rotated images\r\n</code></pre>\r\n<p>One class of functions that does not support vectorization is the set of linear algebra functions. Using the built in vectorized operations should be the first and preferred method of vectorizing any code written with Arrayfire.</p>\r\n<h2><a id=\"GFOR_Parallel_forloops_76\"></a>GFOR: Parallel for-loops</h2>\r\n<p>Another novel method of vectorization present in Arrayfire is the GFOR loop replacement construct. GFOR allows launching all iterations of a loop in parallel on the GPU or device, as long as the iterations are independent. While the standard for-loop performs each iteration sequentially, ArrayFire’s gfor-loop performs each iteration at the same time (in parallel). ArrayFire does this by tiling out the values of all loop iterations and then performing computation on those tiles in one pass. You can think of gfor as performing auto-vectorization of your code, e.g. you write a gfor-loop that increments every element of a vector but behind the scenes ArrayFire rewrites it to operate on the entire vector in parallel.</p>\r\n<p>We can remedy our first example with GFOR:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);\r\ngfor(seq i, n)\r\n    a(i) = a(i) + 1;</code></pre>\r\n<p>To see another example, you could run an <strong>accum()</strong> on every slice of a matrix in a for-loop, or you could “vectorize” and simply do it all in one gfor-loop operation:</p>\r\n<pre><code class=\"language-{.cpp}\">for (int i = 0; i &lt; N; ++i)\r\n   B(span,i) = accum(A(span,i)); // runs each accum() in sequence\r\ngfor (seq i, N)\r\n   B(span,i) = accum(A(span,i)); // runs N accums in parallel\r\n</code></pre>\r\n<p>However, returning to our previous vectorization technique, <strong>accum()</strong> is already vectorized and the operation could be completely replaced with merely:</p>\r\n<pre><code class=\"language-{.cpp}\">    B = accum(A);\r\n</code></pre>\r\n<p>It is best to vectorize computation as much as possible to avoid the overhead in both for-loops and gfor-loops. However, the gfor-loop construct is most effective in the narrow case of broadcast-style operations. Consider the case when we have a vector of constants that we wish to apply to a collection of variables, such as expressing the values of a linear combination for multiple vectors. The broadcast of one set of constants to many vectors works well with gfor-loops:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int p=4, n=1000;\r\naf::array consts = af::randu(p);\r\naf::array var_terms = randn(p, n);\r\n\r\ngfor(seq i, n)\r\n    combination(span, i) = consts * var_terms(span, i);\r\n</code></pre>\r\n<p>Using GFOR requires following several rules and multiple guidelines for optimal performance. The details of this vectorization method can be found in the [GFOR documentation](\\ref gfor).</p>\r\n<h2><a id=\"Batching_127\"></a>Batching</h2>\r\n<p>The <strong>batchFunc()</strong> function allows the broad application of existing Arrayfire functions to multiple sets of data. Effectively, batchFunc() allows Arrayfire functions to execute in “batch processing” mode. In this mode, functions will find a dimension which contains “batches” of data to be processed and will parallelize the procedure. Consider the following example:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filter = randn(1, 5);\r\naf::array weights = randu(5, 5);\r\n</code></pre>\r\n<p>We have a filter that we would like to apply to each of several weights vectors. The naive solution would be using a loop as we’ve seen before:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = constant(0, 5, 5);\r\nfor(int i=0; i &lt; weights.dims(1); ++i){\r\n    filtered_weights.col(i) = filter * weights.col(i);\r\n}\r\n</code></pre>\r\n<p>However we would like a vectorized solution. The following syntax begs to be used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = filter * weights; // fails due to dimension mismatch\r\n</code></pre>\r\n<p>but it fails due to the (5x1), (5x5) dimension mismatch. Wouldn’t it be nice if Arrayfire could figure out along which dimension we intend to apply the batch operation? That is exactly what <strong>batchFunc()</strong> does! The signature of the function is:\r\n<code>array batchFunc(const array &amp;lhs, const array &amp;rhs, batchFunc_t func);</strong></code>\r\nwhere <strong>batchFunc_t</strong> is a function pointer of the form:\r\n<code>typedef array (*batchFunc_t) (const array &amp;lhs, const array &amp;rhs);</code></p>\r\n<p>So, to use <strong>batchFunc()</strong>, we need to provide the function we will be applying as a batch operation. For illustration’s sake, let’s “implement” a multiplication function following the format.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array my_mult (const af::array &amp; lhs, const af::array &amp; rhs){\r\n    return lhs * rhs;\r\n}</code></pre>\r\n<p>Our final batch call is not much more difficult than the ideal syntax we imagined.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = batchFunc( filter, weights, my_mult );\r\n</code></pre>\r\n<p>The batch function will work with many previously mentioned vectorized Arrayfire functions. It can even work with a combination of those functions if they are wrapped inside a helper function matching the <strong>batchFunc_t</strong> signature. Unfortunately, the batch function cannot be used within a gfor() construct at this moment.</p>\r\n<h2><a id=\"Advanced_Vectorization_181\"></a>Advanced Vectorization</h2>\r\n<p>We have seen the different methods Arrayfire provides to vectorize our code. Tying them all together is a slightly more involved process that needs to consider data dimensionality and layout, memory usage, nesting order, etc. An excellent example and discussion of these factors can be found in another blog post:</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/how-to-write-vectorized-code/\">http://sandbox.arrayfire.com/how-to-write-vectorized-code/</a></p>\r\n<p>It’s worth noting that the whole implementation discussed in the blog has since been transformed into a convenient <strong>af::nearestNeighbour()</strong> function. Before writing something from scratch, check that Arrayfire doesn’t already have an implementation. The default vectorized nature of Arrayfire and an extensive collection of functions will speed things up in addition to replacing dozens of lines of code!</p>\r\n\r\n','Introduction to Vectorization','','inherit','open','closed','','8735-revision-v1','','','2015-12-03 21:49:40','2015-12-03 21:49:40','',8735,'http://sandbox.arrayfire.com/8735-revision-v1/',0,'revision','',0),(8748,18673,'2015-12-03 21:50:34','2015-12-03 21:50:34','<p>Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. Arrayfire provides many ways to vectorize a given code segment. In this tutorial, we will be presenting various ways to vectorize code using ArrayFire and the benefits and drawbacks associated with each method.</p>\r\n<h2><a id=\"GenericDefault_vectorization_10\"></a>Generic/Default vectorization</h2>\r\n<p>By its very nature, Arrayfire is a vectorized library. Most functions operate on arrays as a whole – on all elements in parallel. Wherever possible, existing vectorized functions should be used opposed to manually indexing into arrays. For example, consider this valid, yet mislead code that attempts to increment each element of an array:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">af::array a = af::range(10); // [0,  9]\r\nfor(int i = 0; i &lt; a.dims(0); ++i)\r\n{\r\n    a(i) = a(i) + 1;         // [1, 10]\r\n}\r\n</code></pre>\r\n<p>Instead, the existing vectorized Arrayfire overload of the + operator should have been used:</p>\r\n<pre><code class=\"language-{.cpp}\">\r\naf::array a = af::range(10);  // [0,  9]\r\na = a + 1;                    // [1, 10]\r\n</code></pre>\r\n<p>Most Arrayfire functions are vectorized. A small subset of these include:</p>\r\n<p><strong>Arithmetic operations:</strong> +, -, *, / , %, &gt;&gt;, &lt;&lt;\r\n<strong>Complex operations:</strong> real(), imag(), conj()…\r\n<strong>Exponential and logarithmic functions:</strong> exp(), log(), expm1(), log1p()…\r\n<strong>Hyperbolic functions:</strong> sinh(), cosh(), tanh()…\r\n<strong>Logical operations:</strong> &amp;&amp;, ||, &lt;, &gt;, ==, !=\r\n<strong>Numeric functions:</strong> abs(), floor(), round(), min(), max()…\r\n<strong>Trigonometric functions:</strong> sin(), cos(), tan()…</p>\r\n<p>Not only elementwise arithmetic operations are vectorized in Arrayfire.</p>\r\n<p>Vector operations such as <strong>min()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array arr = randn(100);\r\nstd::cout &lt;&lt; min(arr) &lt;&lt; std::endl;\r\n</code></pre>\r\n<p>Signal processing functions like <strong>convolve()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">float g_coef[] = { 1, 2, 1,\r\n                   2, 4, 2,\r\n                   1, 2, 1 };\r\n\r\naf::array filter = 1.f/16 * af::array(3, 3, f_coef);\r\n\r\naf::array signal = randu(WIDTH, HEIGHT, NUM);\r\naf::array conv = convolve2(signal, filter);\r\n</code></pre>\r\n<p>Image processing functions such as <strong>rotate()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array imgs = randu(WIDTH, HEIGHT, 100); // 100 (WIDTH x HEIGHT) images\r\naf::array rot_imgs = rotate(imgs, 45); // 100 rotated images\r\n</code></pre>\r\n<p>One class of functions that does not support vectorization is the set of linear algebra functions. Using the built in vectorized operations should be the first and preferred method of vectorizing any code written with Arrayfire.</p>\r\n<h2><a id=\"GFOR_Parallel_forloops_76\"></a>GFOR: Parallel for-loops</h2>\r\n<p>Another novel method of vectorization present in Arrayfire is the GFOR loop replacement construct. GFOR allows launching all iterations of a loop in parallel on the GPU or device, as long as the iterations are independent. While the standard for-loop performs each iteration sequentially, ArrayFire’s gfor-loop performs each iteration at the same time (in parallel). ArrayFire does this by tiling out the values of all loop iterations and then performing computation on those tiles in one pass. You can think of gfor as performing auto-vectorization of your code, e.g. you write a gfor-loop that increments every element of a vector but behind the scenes ArrayFire rewrites it to operate on the entire vector in parallel.</p>\r\n<p>We can remedy our first example with GFOR:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);\r\ngfor(seq i, n)\r\n    a(i) = a(i) + 1;</code></pre>\r\n<p>To see another example, you could run an <strong>accum()</strong> on every slice of a matrix in a for-loop, or you could “vectorize” and simply do it all in one gfor-loop operation:</p>\r\n<pre><code class=\"language-{.cpp}\">for (int i = 0; i &lt; N; ++i)\r\n   B(span,i) = accum(A(span,i)); // runs each accum() in sequence\r\ngfor (seq i, N)\r\n   B(span,i) = accum(A(span,i)); // runs N accums in parallel\r\n</code></pre>\r\n<p>However, returning to our previous vectorization technique, <strong>accum()</strong> is already vectorized and the operation could be completely replaced with merely:</p>\r\n<pre><code class=\"language-{.cpp}\">    B = accum(A);\r\n</code></pre>\r\n<p>It is best to vectorize computation as much as possible to avoid the overhead in both for-loops and gfor-loops. However, the gfor-loop construct is most effective in the narrow case of broadcast-style operations. Consider the case when we have a vector of constants that we wish to apply to a collection of variables, such as expressing the values of a linear combination for multiple vectors. The broadcast of one set of constants to many vectors works well with gfor-loops:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int p=4, n=1000;\r\naf::array consts = af::randu(p);\r\naf::array var_terms = randn(p, n);\r\n\r\ngfor(seq i, n)\r\n    combination(span, i) = consts * var_terms(span, i);\r\n</code></pre>\r\n<p>Using GFOR requires following several rules and multiple guidelines for optimal performance. The details of this vectorization method can be found in the [GFOR documentation](\\ref gfor).</p>\r\n<h2><a id=\"Batching_127\"></a>Batching</h2>\r\n<p>The <strong>batchFunc()</strong> function allows the broad application of existing Arrayfire functions to multiple sets of data. Effectively, batchFunc() allows Arrayfire functions to execute in “batch processing” mode. In this mode, functions will find a dimension which contains “batches” of data to be processed and will parallelize the procedure. Consider the following example:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filter = randn(1, 5);\r\naf::array weights = randu(5, 5);\r\n</code></pre>\r\n<p>We have a filter that we would like to apply to each of several weights vectors. The naive solution would be using a loop as we’ve seen before:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = constant(0, 5, 5);\r\nfor(int i=0; i &lt; weights.dims(1); ++i){\r\n    filtered_weights.col(i) = filter * weights.col(i);\r\n}\r\n</code></pre>\r\n<p>However we would like a vectorized solution. The following syntax begs to be used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = filter * weights; // fails due to dimension mismatch\r\n</code></pre>\r\n<p>but it fails due to the (5x1), (5x5) dimension mismatch. Wouldn’t it be nice if Arrayfire could figure out along which dimension we intend to apply the batch operation? That is exactly what <strong>batchFunc()</strong> does! The signature of the function is:\r\n<code>array batchFunc(const array &amp;lhs, const array &amp;rhs, batchFunc_t func);</strong></code>\r\nwhere <strong>batchFunc_t</strong> is a function pointer of the form:\r\n<code>typedef array (*batchFunc_t) (const array &amp;lhs, const array &amp;rhs);</code></p>\r\n<p>So, to use <strong>batchFunc()</strong>, we need to provide the function we will be applying as a batch operation. For illustration’s sake, let’s “implement” a multiplication function following the format.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array my_mult (const af::array &amp; lhs, const af::array &amp; rhs){\r\n    return lhs * rhs;\r\n}</code></pre>\r\n<p>Our final batch call is not much more difficult than the ideal syntax we imagined.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = batchFunc( filter, weights, my_mult );\r\n</code></pre>\r\n<p>The batch function will work with many previously mentioned vectorized Arrayfire functions. It can even work with a combination of those functions if they are wrapped inside a helper function matching the <strong>batchFunc_t</strong> signature. Unfortunately, the batch function cannot be used within a gfor() construct at this moment.</p>\r\n<h2><a id=\"Advanced_Vectorization_181\"></a>Advanced Vectorization</h2>\r\n<p>We have seen the different methods Arrayfire provides to vectorize our code. Tying them all together is a slightly more involved process that needs to consider data dimensionality and layout, memory usage, nesting order, etc. An excellent example and discussion of these factors can be found in another blog post:</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/how-to-write-vectorized-code/\">http://sandbox.arrayfire.com/how-to-write-vectorized-code/</a></p>\r\n<p>It’s worth noting that the whole implementation discussed in the blog has since been transformed into a convenient <strong>af::nearestNeighbour()</strong> function. Before writing something from scratch, check that Arrayfire doesn’t already have an implementation. The default vectorized nature of Arrayfire and an extensive collection of functions will speed things up in addition to replacing dozens of lines of code!</p>\r\n\r\n','Introduction to Vectorization','','inherit','open','closed','','8735-revision-v1','','','2015-12-03 21:50:34','2015-12-03 21:50:34','',8735,'http://sandbox.arrayfire.com/8735-revision-v1/',0,'revision','',0),(8762,18673,'2015-12-03 22:37:32','2015-12-03 22:37:32','<p>Programmers and Data Scientists want to take advantage of fast and parallel computational devices. Writing vectorized code is becoming a necessity to get the best performance out of the current generation parallel hardware and scientific computing software. However, writing vectorized code may not be intuitive immediately. Arrayfire provides many ways to vectorize a given code segment. In this tutorial, we will be presenting various ways to vectorize code using ArrayFire and the benefits and drawbacks associated with each method.</p>\r\n<h2><a id=\"GenericDefault_vectorization_10\"></a>Generic/Default vectorization</h2>\r\n<p>By its very nature, Arrayfire is a vectorized library. Most functions operate on arrays as a whole – on all elements in parallel. Wherever possible, existing vectorized functions should be used opposed to manually indexing into arrays. For example, consider this valid, yet mislead code that attempts to increment each element of an array:</p>\r\n<pre><code class=\"language-{.cpp}\">af::<span class=\"hljs-built_in\">af::array a = af::range(10); // [0,  9]\r\nfor(int i = 0; i &lt; a.dims(0); ++i)\r\n{\r\n    a(i) = a(i) + 1;         // [1, 10]\r\n}\r\n</code></pre>\r\n<p>Instead, the existing vectorized Arrayfire overload of the + operator should have been used:</p>\r\n<pre><code class=\"language-{.cpp}\">\r\naf::array a = af::range(10);  // [0,  9]\r\na = a + 1;                    // [1, 10]\r\n</code></pre>\r\n<p>Most Arrayfire functions are vectorized. A small subset of these include:</p>\r\n<p><strong>Arithmetic operations:</strong> +, -, *, / , %, &gt;&gt;, &lt;&lt;\r\n<strong>Complex operations:</strong> real(), imag(), conj()…\r\n<strong>Exponential and logarithmic functions:</strong> exp(), log(), expm1(), log1p()…\r\n<strong>Hyperbolic functions:</strong> sinh(), cosh(), tanh()…\r\n<strong>Logical operations:</strong> &amp;&amp;, ||, &lt;, &gt;, ==, !=\r\n<strong>Numeric functions:</strong> abs(), floor(), round(), min(), max()…\r\n<strong>Trigonometric functions:</strong> sin(), cos(), tan()…</p>\r\n<p>Not only elementwise arithmetic operations are vectorized in Arrayfire.</p>\r\n<p>Vector operations such as <strong>min()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array arr = randn(100);\r\nstd::cout &lt;&lt; min(arr) &lt;&lt; std::endl;\r\n</code></pre>\r\n<p>Signal processing functions like <strong>convolve()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">float g_coef[] = { 1, 2, 1,\r\n                   2, 4, 2,\r\n                   1, 2, 1 };\r\n\r\naf::array filter = 1.f/16 * af::array(3, 3, f_coef);\r\n\r\naf::array signal = randu(WIDTH, HEIGHT, NUM);\r\naf::array conv = convolve2(signal, filter);\r\n</code></pre>\r\n<p>Image processing functions such as <strong>rotate()</strong> support vectorization:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array imgs = randu(WIDTH, HEIGHT, 100); // 100 (WIDTH x HEIGHT) images\r\naf::array rot_imgs = rotate(imgs, 45); // 100 rotated images\r\n</code></pre>\r\n<p>One class of functions that does not support vectorization is the set of linear algebra functions. Using the built in vectorized operations should be the first and preferred method of vectorizing any code written with Arrayfire.</p>\r\n<h2><a id=\"GFOR_Parallel_forloops_76\"></a>GFOR: Parallel for-loops</h2>\r\n<p>Another novel method of vectorization present in Arrayfire is the GFOR loop replacement construct. GFOR allows launching all iterations of a loop in parallel on the GPU or device, as long as the iterations are independent. While the standard for-loop performs each iteration sequentially, ArrayFire’s gfor-loop performs each iteration at the same time (in parallel). ArrayFire does this by tiling out the values of all loop iterations and then performing computation on those tiles in one pass. You can think of gfor as performing auto-vectorization of your code, e.g. you write a gfor-loop that increments every element of a vector but behind the scenes ArrayFire rewrites it to operate on the entire vector in parallel.</p>\r\n<p>We can remedy our first example with GFOR:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array a = af::range(10);\r\ngfor(seq i, n)\r\n    a(i) = a(i) + 1;</code></pre>\r\n<p>To see another example, you could run an <strong>accum()</strong> on every slice of a matrix in a for-loop, or you could “vectorize” and simply do it all in one gfor-loop operation:</p>\r\n<pre><code class=\"language-{.cpp}\">for (int i = 0; i &lt; N; ++i)\r\n   B(span,i) = accum(A(span,i)); // runs each accum() in sequence\r\ngfor (seq i, N)\r\n   B(span,i) = accum(A(span,i)); // runs N accums in parallel\r\n</code></pre>\r\n<p>However, returning to our previous vectorization technique, <strong>accum()</strong> is already vectorized and the operation could be completely replaced with merely:</p>\r\n<pre><code class=\"language-{.cpp}\">    B = accum(A);\r\n</code></pre>\r\n<p>It is best to vectorize computation as much as possible to avoid the overhead in both for-loops and gfor-loops. However, the gfor-loop construct is most effective in the narrow case of broadcast-style operations. Consider the case when we have a vector of constants that we wish to apply to a collection of variables, such as expressing the values of a linear combination for multiple vectors. The broadcast of one set of constants to many vectors works well with gfor-loops:</p>\r\n<pre><code class=\"language-{.cpp}\">const static int p=4, n=1000;\r\naf::array consts = af::randu(p);\r\naf::array var_terms = randn(p, n);\r\n\r\ngfor(seq i, n)\r\n    combination(span, i) = consts * var_terms(span, i);\r\n</code></pre>\r\n<p>Using GFOR requires following several rules and multiple guidelines for optimal performance. The details of this vectorization method can be found in the <a href=\"http://www.sandbox.arrayfire.com/docs/page_gfor.htm\">GFOR documentation.</a></p>\r\n<h2><a id=\"Batching_127\"></a>Batching</h2>\r\n<p>The <strong>batchFunc()</strong> function allows the broad application of existing Arrayfire functions to multiple sets of data. Effectively, batchFunc() allows Arrayfire functions to execute in “batch processing” mode. In this mode, functions will find a dimension which contains “batches” of data to be processed and will parallelize the procedure. Consider the following example:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filter = randn(1, 5);\r\naf::array weights = randu(5, 5);\r\n</code></pre>\r\n<p>We have a filter that we would like to apply to each of several weights vectors. The naive solution would be using a loop as we’ve seen before:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = constant(0, 5, 5);\r\nfor(int i=0; i &lt; weights.dims(1); ++i){\r\n    filtered_weights.col(i) = filter * weights.col(i);\r\n}\r\n</code></pre>\r\n<p>However we would like a vectorized solution. The following syntax begs to be used:</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = filter * weights; // fails due to dimension mismatch\r\n</code></pre>\r\n<p>but it fails due to the (5x1), (5x5) dimension mismatch. Wouldn’t it be nice if Arrayfire could figure out along which dimension we intend to apply the batch operation? That is exactly what <strong>batchFunc()</strong> does! The signature of the function is:\r\n<code>array batchFunc(const array &amp;lhs, const array &amp;rhs, batchFunc_t func);</strong></code>\r\nwhere <strong>batchFunc_t</strong> is a function pointer of the form:\r\n<code>typedef array (*batchFunc_t) (const array &amp;lhs, const array &amp;rhs);</code></p>\r\n<p>So, to use <strong>batchFunc()</strong>, we need to provide the function we will be applying as a batch operation. For illustration’s sake, let’s “implement” a multiplication function following the format.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array my_mult (const af::array &amp; lhs, const af::array &amp; rhs){\r\n    return lhs * rhs;\r\n}</code></pre>\r\n<p>Our final batch call is not much more difficult than the ideal syntax we imagined.</p>\r\n<pre><code class=\"language-{.cpp}\">af::array filtered_weights = batchFunc( filter, weights, my_mult );\r\n</code></pre>\r\n<p>The batch function will work with many previously mentioned vectorized Arrayfire functions. It can even work with a combination of those functions if they are wrapped inside a helper function matching the <strong>batchFunc_t</strong> signature. Unfortunately, the batch function cannot be used within a gfor() construct at this moment.</p>\r\n<h2><a id=\"Advanced_Vectorization_181\"></a>Advanced Vectorization</h2>\r\n<p>We have seen the different methods Arrayfire provides to vectorize our code. Tying them all together is a slightly more involved process that needs to consider data dimensionality and layout, memory usage, nesting order, etc. An excellent example and discussion of these factors can be found in another blog post:</p>\r\n<p><a href=\"http://sandbox.arrayfire.com/how-to-write-vectorized-code/\">http://sandbox.arrayfire.com/how-to-write-vectorized-code/</a></p>\r\n<p>It’s worth noting that the whole implementation discussed in the blog has since been transformed into a convenient <strong>af::nearestNeighbour()</strong> function. Before writing something from scratch, check that Arrayfire doesn’t already have an implementation. The default vectorized nature of Arrayfire and an extensive collection of functions will speed things up in addition to replacing dozens of lines of code!</p>\r\n\r\n','Introduction to Vectorization','','inherit','open','closed','','8735-revision-v1','','','2015-12-03 22:37:32','2015-12-03 22:37:32','',8735,'http://sandbox.arrayfire.com/8735-revision-v1/',0,'revision','',0),(8763,18673,'2015-12-03 22:42:56','2015-12-03 22:42:56','Today, we will be looking at solving a simple linear least squares regression problem with Arrayfire. Least squares regression is a commonly used form of linear regression. The often large sample sizes and underlying matrix operations used for fitting Linear Least Squares makes it an excellent candidate for a parallelized gpu. The specific problem we will be examining today is the classic polynomial fit to a scattered collection of points.\r\n<h3><a id=\"Mathematical_Background_4\"></a>Mathematical Background</h3>\r\nLinear regression methods model relationships between a dependent variable (<strong>y</strong>) and one or more independent variables (<strong>X</strong>). Linear regression explores the conditional probability ( <strong>y</strong> | <strong>X</strong> ) Data are modeled using <em>linear</em> predictor functions. Given this linearity assumption between the dependent and independent variables, and (n) data points of the form:\r\n<strong>{y<sub>i</sub>,&nbsp;&nbsp;&nbsp;&nbsp; x<sub>i1</sub>, … , x<sub>ip</sub>}</strong> ,\r\nwe can construct a model of the form:\r\n\r\n<strong>y<sub>i</sub> = b<sub>1</sub>x<sub>i1</sub> + … + b<sub>p</sub>x<sub>ip</sub> + <em>e</em><sub>i</sub></strong>,&nbsp;&nbsp;&nbsp;&nbsp; where <strong>i = 1, …, n</strong>.\r\n\r\nor, if we stack each point’s linear model atop each other, in vector form:\r\n\r\n<strong>y = Xb + <em>e</em></strong>    where,\r\n\r\n<strong>y</strong> - vector of dependent variables\r\n<strong>X</strong> - “Design Matrix” of size <em>(n x p)</em> . This matrix contains the independent variables.\r\n<strong>b</strong> - parameter vector the regression will be fitting\r\n<strong>e</strong> - error vector/noise\r\n\r\nThe goal of least squares linear regression is to find a parameter vector <strong>b</strong> such that the square of the error is minimized:\r\n\r\n<strong>b = argmin<sub>b</sub> S( b ) = argmin<sub>b</sub>|| e || <sup>2</sup> = argmin<sub>b</sub> || y - Xb || <sup>2</sup></strong>,\r\n\r\nwhere <strong>S( b )</strong> – cost function.\r\n\r\nSolving the minimization can be done through various gradient descent methods which iteratively work to set the gradient vector of the cost function to <strong>0</strong>. The minimized gradient of the cost function can also be found analytically. The resulting equations are called the normal equations and can be written in vector form as:\r\n\r\n<strong>(X<sup>T</sup>X) b = X<sup>T</sup>y</strong>\r\n\r\nAfter a quick re-arrangement, we can algebraically solve for our parameter vector:\r\n\r\n<strong>b = (X<sup>T</sup>X)<sup>-1</sup> X<sup>T</sup>y</strong>\r\n\r\nOn first glance, our specific problem of fitting an n-order polynomial(for example n = 5) might not seem like a linear problem since we have quadratic, cubic, and higher terms: <strong>y = x<sup>5</sup> + x<sup>4</sup> + x<sup>3</sup> + x<sup>2</sup> + x<sup>1</sup> + x<sup>0</sup></strong>, however we are actually fitting the parameter vector <em>b</em> and our equation is of the linear combination form:\r\n<strong>y = b<sub>1</sub>x<sup>5</sup> + b<sub>2</sub>x<sup>4</sup> + b<sub>3</sub>x<sup>3</sup> + b<sub>4</sub>x<sup>2</sup> + b<sub>5</sub>x<sup>1</sup> + b<sub>6</sub>x<sup>0</sup></strong>\r\n<h3><a id=\"Coding_with_Arrayfire_32\"></a>Coding with Arrayfire</h3>\r\nThe set of points to be fitted will be located within a window of size (WIDTH, HEIGHT). First, generate a set of points within the window:\r\n<pre><code>array particles = randu(NSAMPLES, 2); //generate (NSAMPLE x 2) random uniform matrix\r\n//scale [0,1] to [0, WIDTH] and [0, HEIGHT]\r\nparticles.col(0) *= WIDTH;\r\nparticles.col(1) *= HEIGHT;</code></pre>\r\nThen, form our regressors matrix <strong>( X )</strong>:\r\n<pre><code>array X = constant( 1, NSAMPLES, 2, f32);\r\nX.col(1) = particles.col(0); // X [NSAMPLES 2] = [ 1  xvals ]</code></pre>\r\nWith the dependent and independent variables prepared, evaluate the algebraic solution for the parameter vector <strong>b</strong>:\r\n<pre><code>array b = matmul(  matmul(inverse(matmul(X.T(), X)), X.T()), // (X\'X) * X\'                                \r\n                   particles.col(1) );                    //   * y</code></pre>\r\nNow that we have found <strong>b</strong>, we have a complete linear model that predicts <strong>( y | X )</strong>. It would be nice if we could see this linear model, so we will attempt to draw a simple grayscale visualization. First, set up an “image” matrix and visualize our original dataset:\r\n<pre><code>array image = constant(0, HEIGHT, WIDTH, f32); //declare a black image to match our window\r\narray ids(NSAMPLES, u32); //indexes specifying where in the image we should draw white\r\nids = (particles.col(0).as(u32) * (HEIGHT)) + particles.col(1).as(u32);\r\nimage(ids) = 1; //fill the specified indices with white\r\n\r\narray mask_point = array(5, 5, point_kernel);\r\nimage = dilate(image, mask_point); //dilate operation with point_kernel to prettify points</code></pre>\r\nThen plot the fitted line on our “image”:\r\n<pre><code>float *params = b.host(); //copy params from device to host array\r\narray yplot = range(dim4(WIDTH)) * params[1] + params[0]; //y = b1*x + b0\r\ndelete [] params;  //implicitly allocated params must be freed\r\n\r\nids = (range(dim4(WIDTH)).as(u32) * (HEIGHT)) + yplot.as(u32); //computes the indices in our image that the line passes through\r\nids = ids(yplot &gt; 0 &amp;&amp; yplot &lt; HEIGHT); //filters the ids where our y-values are out of bounds</code></pre>\r\nAnd voila!\r\n<h3> <a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/11/Screenshot-from-2015-11-12-16_56_511.png\"><img class=\" size-medium wp-image-8644 aligncenter\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/11/Screenshot-from-2015-11-12-16_56_511-300x150.png\" alt=\"Least square linear regression\" width=\"300\" height=\"150\" /></a></h3>\r\n<h3><a id=\"Coding_for_higher_order_polynomials_72\"></a>Coding for higher order polynomials</h3>\r\nIdeally, we would be able to fit any n-th order polynomial to our data, so first, prepare our design matrix to follow the higher order terms:\r\n<pre><code>X = constant(1, NSAMPLES, N_order, f32);\r\n X.col(1) *= particles.col(0);\r\n for(int i=2; i&lt;N_order; ++i)\r\n    X.col(i) = X.col(i-1) * particles.col(0); //replace each column with one order higher column\r\n// X [NSAMPLES N_order] = [ 1 x x^2 x^3 ... x^N_order]</code></pre>\r\nOur equations remain the same <strong>( (X<sup>T</sup>X) b = X<sup>T</sup>y )</strong>, and while the identical algebraic solution for <strong>b</strong> would work it is quite inefficient to find the inverse of a (now) large normal equations Gramian matrix <strong>( X<sup>T</sup>X )</strong>. Instead, since the Gramian matrix has the nice property of being a positive semi-definite matrix, we can substitute it with the result of a Cholesky decomposition. The equation slightly changes <strong>( U<sup>T</sup>U b = X<sup>T</sup>y )</strong> and the procedure is as follows:\r\n<ul>\r\n	<li>Find the upper triangular matrix <strong>( U )</strong> from the Cholesky decomposition of <strong>( X<sup>T</sup>X)</strong></li>\r\n	<li>Solve for vector z in <strong>U<sup>T</sup>z = X<sup>T</sup>y</strong></li>\r\n	<li>Finally, solve for the parameter vector <strong>b</strong> in <strong>Ub = z</strong></li>\r\n</ul>\r\nSuprisingly, Arrayfire has convenient functions for each of these steps.\r\n<pre><code>array U;\r\ncholesky(U, matmul(X.T(), X), true); //cholesky on X\'X, true parameter for upper triangular portion\r\narray z = solve(U.T(), matmul(X.T(), particles.col(1)), AF_MAT_LOWER); //solve and specify the coefficients are lower triangular for optimized solution method\r\nb = solve(U, z, AF_MAT_UPPER); //solve and specify the coefficients are upper triangular</code></pre>\r\nAnd our result:\r\n\r\n<img class=\" size-medium wp-image-8645 aligncenter\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/11/Screenshot-from-2015-11-12-16_59_251-300x150.png\" alt=\"Screenshot from 2015-11-12 16_59_25\" width=\"300\" height=\"150\" />\r\n\r\nThe complete source code for this project can be found <a href=\"https://github.com/syurkevi/leastsquares_arrayfire_example\">here.</a>\r\n<h3><a id=\"Conclusion_98\"></a>Conclusion</h3>\r\nWe have implemented a least squares linear regression with Arrayfire and also visualized its results. Arrayfire provides many convenient functions which allowed us to choose the most robust method of solving our problem without sacrificing convenience and ease of coding.','Linear Least Squares Regression with Arrayfire','','inherit','open','closed','','8640-revision-v1','','','2015-12-03 22:42:56','2015-12-03 22:42:56','',8640,'http://sandbox.arrayfire.com/8640-revision-v1/',0,'revision','',0),(8764,18528,'2015-12-04 15:30:03','2015-12-04 15:30:03','Under Windows and Mac the Intel GPU drivers include OpenCL support; however, on Linux OpenCL on Intel GPUs is implemented through an open source project called <a href=\"http://www.freedesktop.org/wiki/Software/Beignet/\">Beignet</a> (pronnounced like \"ben-yay\", a type of <a href=\"http://en.wikipedia.org/wiki/Beignet\">French pastry</a> akin to a what we would call a \"fritter\" in English). Below I have written a step-by-step guide on how you can get Beignet running on an Ubuntu 14.10 system which has an Intel 3rd, 4th, or 5th <a href=\"http://ark.intel.com/\">generation Intel processor</a>. Instructions for other variants of Linux will be similar, except for the commands to install the prerequisite packages.\r\n\r\nThere are several little caveats which need to be discussed up front. Foremost, the Beignet project supports the following hardware:\r\n<ul>\r\n	<li>3rd Generation Intel Core Processors</li>\r\n	<li>Intel “Bay Trail” platforms with Intel HD Graphics</li>\r\n	<li>4th Generation Intel Core Processors (requires a kernel patch be applied for shared memory!)</li>\r\n	<li>5th Generation Intel Core Processors \"Broadwell\".</li>\r\n</ul>\r\nThere are also a few noteworthy issues of which you should be aware:\r\n<ul>\r\n	<li>If your computer is running a Linux kernel in the 3.15 or 3.16 branch, you will need to disable some register whitelist functionality every time you reboot your system. This can be accomplished by running <code>echo 0 &gt; /sys/module/i915/parameters/enable_cmd_parser</code> as root.</li>\r\n	<li>4th Generation Intel Processors (i.e. i3/5/7-4xxx) require a kernel patch for shared/local memory to function.</li>\r\n	<li>There is no double precision support</li>\r\n	<li>OpenGL-OpenCL interop via <code>cl_khr_gl_sharing</code> is not supported</li>\r\n</ul>\r\nThere are additional release notes that can be found on the <a href=\"http://www.freedesktop.org/wiki/Software/Beignet/\">Beignet</a> project page.\r\n<h3>Installing prerequisites</h3>\r\n<pre><code>sudo apt-get install build-essential g++ cmake \r\nsudo apt-get install clang libclang-3.5-dev libclang-dev libclang1\r\nsudo apt-get install ocl-icd-opencl-dev ocl-icd-libopencl1</code></pre>\r\nNote, if you are on a Ubuntu 14.04 system, you should install <code>libclang-3.4-dev</code> instead, then run <code>update-alternatives</code> to point <code>llvm-link</code> and <code>llvm-as</code> to the correct version. The latter can be accomplished using the following commands:\r\n<pre><code>sudo update-alternatives --install /usr/bin/llvm-link llvm-link /usr/bin/llvm-link-3.4 34\r\nsudo update-alternatives --install /usr/bin/llvm-as llvm-as /usr/bin/llvm-as-3.4 34  \r\n</code></pre>\r\nIf you want to use the standard OpenCL ICD loader, you will also need to install these packages:\r\n<pre><code>sudo apt-get install opencl-headers ocl-icd-dev ocl-icd-libopencl1    \r\n</code></pre>\r\nI would also recomment you install the <code>clinfo</code> program so that you can verify that your installation is successful:\r\n<pre><code>sudo apt-get install clinfo    \r\n</code></pre>\r\n<h3>Check out and compile Beignet</h3>\r\n<pre><code>git clone git://anongit.freedesktop.org/beignet\r\ncd beignet\r\ngit checkout Release_v1.0.0\r\nmkdir build\r\ncd build\r\ncmake ..   \r\n</code></pre>\r\nNOTE: There may be newer releases of Beinget. To find releases type <span class=\"lang:default decode:true crayon-inline\">git branch -a </span>on the console and pick the highest release version number.\r\n\r\nDuring the CMake stage, ensure that the OCL ICD header file is installed, otherwise the library will not create an installable client driver. If everything went fine, go ahead and compile the source using\r\n<pre><code>make    \r\n</code></pre>\r\n(Note, you can do make -jN with N &gt; 1 to do a parallel build.)\r\nNext we verify that Beignet is functioning correctly on your hardware by running unit tests. These can be found in the <code>utest</code> folder. The unit tests require some enviornmental variables be set prior to invocation:\r\n<pre><code>cd utests\r\nsource setenv.sh\r\n./utest_run   \r\n</code></pre>\r\nIf a significant fraction of the unit tests fail and you have a 3.15 or 3.16 kernel, you need to disable register whitelisting using a command similar to the following:\r\n<pre><code>sudo su\r\necho 0 &gt; /sys/module/i915/parameters/enable_cmd_parser\r\nexit    \r\n</code></pre>\r\nand try re-running the tests. Please note that this change is not permanent and you will need to re-run it if you reboot your system. Alternatively, you could add this command to a startup script. The Beignet release notes mention there is a kernel patch to fix this issue which you could backport if you so desired.\r\n\r\nIf most of the tests pass, but those that involve local memory (~20-30 of the tests) fail, you will need to apply the <a href=\"#kernel-patch\">kernel patch</a> listed below.\r\n\r\nIf all was well, install Beignet to your system:\r\n<pre><code>sudo make install   \r\n</code></pre>\r\nYou can see a list of installed software in the <code>install_manifest.txt</code> file in the build directory.\r\n<h3>Verify Beignet is installed</h3>\r\nIn a terminal run the <code>clinfo</code> program. You should see something like this:\r\n<pre><code>$ clinfo\r\n...      \r\nPlatform Name:              Intel Gen OCL Driver\r\nNumber of devices:          1\r\nDevice Type:                CL_DEVICE_TYPE_GPU\r\n...\r\nName:                       Intel(R) HD Graphics Haswell GT2 Desktop\r\nVendor:                     Intel\r\nDevice OpenCL C version:    OpenCL C 1.2 beignet 0.9.1\r\nDriver version:             0.9.1\r\nProfile:                    FULL_PROFILE\r\nVersion:                    OpenCL 1.2 beignet 0.9.1\r\nExtensions:                 cl_khr_global_int32_base_atomics \r\n                            cl_khr_global_int32_extended_atomics \r\n                            cl_khr_local_int32_base_atomics \r\n                            cl_khr_local_int32_extended_atomics \r\n                            cl_khr_byte_addressable_store cl_khr_icd   \r\n</code></pre>\r\nTake note that the Intel OpenCL driver is loaded for a GPU device using <code>beignet</code>. This indicates the Installable Client Driver (ICD) is correctly installed. Also note the extensions listed.\r\n<h3>Applying the kernel patch to enable OpenCL shared local memory.</h3>\r\nIf you are using Beignet on a 4th generation Intel processor, you will need to apply a kernel patch to enable shared/local memory. This is a fairly lengthy process that will require at least 70 GB of hard disk space and perhaps an hour of compilation time if the build is executed in parallel.\r\n\r\nIn the next few paragraphs I\'ll walk you through how you can apply the kernel patch. I have based my instructions on the <a href=\"https://help.ubuntu.com/community/Kernel/Compile\">kernel compilation instructions for Ubuntu</a>. Instructions for other variants of Linux will be significantly different.\r\n\r\nInstall prerequisites:\r\n<pre><code>sudo apt-get build-dep linux-image-`uname -r`    \r\n</code></pre>\r\nMake a working directory for the kernel somewhere and download the source\r\n<pre><code>mkdir kernel\r\ncd kernel\r\napt-get source linux-image-`uname -r`    \r\n</code></pre>\r\nNext we see if we can automatically apply the patch. First download the patch:\r\n<pre><code>wget https://01.org/sites/default/files/disable-batchbuffer-security.patch    \r\n</code></pre>\r\nNow <code>cd</code> into the kernel directory:\r\n<pre><code>cd linux-3.16.0    \r\n</code></pre>\r\nCheck some details about the patch\r\n<pre><code>git apply --stat ../disable-batchbuffer-security.patch    \r\n</code></pre>\r\nTry automatically applying the patch:\r\n<pre><code>git apply --check ../disable-batchbuffer-security.patch    \r\n</code></pre>\r\nIf it automatically applies with no errors, just apply it:\r\n<pre><code>git apply ../disable-batchbuffer-security.patch    \r\n</code></pre>\r\nIf it did not work (as was the case on my system), the change is fairly simple. Open the <code>drivers/gpu/drm/i915/i915_gem_execbuffer.c</code> file in an editor:\r\n<pre><code>gedit drivers/gpu/drm/i915/i915_gem_execbuffer.c   \r\n</code></pre>\r\nIn the <code>i915_gem_do_execbuffer</code> function, find the following code:\r\n<pre><code>flags = 0;\r\nif (args-&gt;flags &amp; I915_EXEC_SECURE) {\r\n    if (!file-&gt;is_master || !capable(CAP_SYS_ADMIN))\r\n        return -EPERM;    \r\n</code></pre>\r\nAnd add the line <code>flags |= I915_DISPATCH_SECURE;</code> as follows:\r\n<pre><code>flags = 0;\r\nflags |= I915_DISPATCH_SECURE;\r\nif (args-&gt;flags &amp; I915_EXEC_SECURE) {\r\n    if (!file-&gt;is_master || !capable(CAP_SYS_ADMIN))\r\n        return -EPERM;  \r\n</code></pre>\r\nThis was inserted on line 998 for me. Save the file. Now we need to compile and install the modified kernel.\r\n\r\nNow we build the new kernel. Run the following commands from within the kernel source directory:\r\n<pre><code>fakeroot debian/rules clean\r\nDEB_BUILD_OPTIONS=parallel=8 fakeroot debian/rules binary-headers binary-generic    \r\n</code></pre>\r\nThis will build some Debian packages and place them in the directory <em>above</em> the kernel source root.\r\n\r\nAfter the kernel has compiled, install it:\r\n<pre><code>cd ../ (or go back into the kernel directory)\r\nsudo dpkg -i linux-headers-3.16.0-29-generic_3.16.0-29.54_amd64.deb \r\nsudo dpkg -i linux-image-3.16.0-29-generic_3.16.0-29.54_amd64.deb    \r\n</code></pre>\r\n(you might have to change the numeric kernel version to match what you compiled) Now add the kernel to the boot options:\r\n<pre><code>sudo update-grub\r\nsudo reboot    \r\n</code></pre>\r\nNow go back and re-run the Beignet unit test framework from above. With any luck everything will work fine.','OpenCL on Intel HD / Iris graphics on Linux','','inherit','open','closed','','7739-revision-v1','','','2015-12-04 15:30:03','2015-12-04 15:30:03','',7739,'http://sandbox.arrayfire.com/7739-revision-v1/',0,'revision','',0),(8765,11,'2015-12-07 15:09:18','2015-12-07 15:09:18','[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"10px\" padding_bottom=\"40px\"]\r\n[custom_headline type=\"left\" level=\"h2\"]\r\nArrayFire Installers\r\n[/custom_headline]\r\n[custom_headline type=\"left\" level=\"h5\"]\r\nEach download contains both CUDA and OpenCL files.\r\n[/custom_headline]\r\n[gap size=\"4%\"]\r\n\r\n[column type=\"one-fourth\"][button  block=\"true\" onclick=\"&lt;!-- Google Code for ArrayFire Download (Windows) Conversion Page\r\nIn your html page, add the snippet and call\r\ngoog_report_conversion when someone clicks on the\r\nchosen link or button. --&gt;\r\n&lt;script type=\"text/javascript\"&gt;\r\n/* &lt;!&amp;#91;CDATA&amp;#91; */\r\ngoog_snippet_vars = function() {\r\nvar w = window;\r\nw.google_conversion_id = 1021026651;\r\nw.google_conversion_label = \"18VJCJjPql4Q28Lu5gM\";\r\nw.google_remarketing_only = false;\r\n}\r\n// DO NOT CHANGE THE CODE BELOW.\r\ngoog_report_conversion = function(url) {\r\ngoog_snippet_vars();\r\nwindow.google_conversion_format = \"3\";\r\nwindow.google_is_call = true;\r\nvar opt = new Object();\r\nopt.onload_callback = function() {\r\nif (typeof(url) != \'undefined\') {\r\nwindow.location = url;\r\n}\r\n}\r\nvar conv_handler = window&amp;#91;\'google_trackConversion\'&amp;#93;;\r\nif (typeof(conv_handler) == \'function\') {\r\nconv_handler(opt);\r\n}\r\n}\r\n/* &amp;#93;&amp;#93;&gt; */\r\n&lt;/script&gt;\r\n&lt;script type=\"text/javascript\"\r\nsrc=\"//www.googleadservices.com/pagead/conversion_async.js\"&gt;\r\n&lt;/script&gt;\" class=\"center-text\" type=\"flat\" shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/windows-installer\" size=\"regular\" ]Windows, v3.2.1\r\n(64-bit)[/button][/column] [column type=\"one-fourth\"][button block=\"true\" type=\"flat\"  shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/linux-x86_64-installer\" size=\"regular\" ]Linux, v3.2.1\r\n(64-bit)[/button][/column][column type=\"one-fourth\"][button  block=\"true\" type=\"flat\"  shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/osx-installer\" size=\"regular\" ]Mac OSX, v3.2.1\r\n(64-bit)[/button][/column] [column type=\"one-fourth\" last=\"true\"][button block=\"true\"  type=\"flat\"  shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/linux-armv7l-installer\" size=\"regular\" ]Tegra K1 v3.2.1\r\n(32-bit)[/button][/column][gap size=\"9%\"]\r\n\r\nCheck out our GitHub repository to <a href=\"https://github.com/arrayfire/arrayfire\">build from the source</a>.\r\n\r\nLooking for an older installer? <a href=\"http://sandbox.arrayfire.com/installer_archive\">Try here</a>.[/content_band]\r\n<p style=\"text-align: left;\">[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"10px\" padding_bottom=\"40px\" bg_color=\"#f1f1f1\"][column type=\"one-half\"][gap size=\"8%\"]<img class=\"aligncenter wp-image-5156\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/02/mobile_Exported1-e1395437261846.png\" alt=\"mobile_Exported\" width=\"233\" height=\"311\" />[/column][column type=\"one-half\" last=\"true\"]\r\n[custom_headline type=\"left\" level=\"h2\"]\r\nGreat. What now?\r\n[/custom_headline]</p>\r\n<p style=\"text-align: left;\">[gap size=\"5%\"]</p>\r\n<p style=\"text-align: left;\">Welcome to ArrayFire! You\'ve got an awesome library there—learn more about its features and functions on <a href=\"http://www.sandbox.arrayfire.com/docs/index.htm\">our documentation</a>.</p>\r\n<p style=\"text-align: left;\">In addition to our <a href=\"https://groups.google.com/forum/#!forum/arrayfire-users\">ArrayFire user group</a> and <a href=\"http://sandbox.arrayfire.com/blog/\">our blog</a>, we offer a plethora of <a href=\"http://sandbox.arrayfire.com/support/\">support options</a> to fit your needs.</p>\r\n<p style=\"text-align: left;\">Got a job that needs closer attention? Hire us! Our engineers are acceleration wizards. Check out our <a href=\"http://sandbox.arrayfire.com/consulting/\">consulting offerings</a>, or set up a free <a href=\"http://meetme.so/arrayfire\">technical consultation</a> with us today![/column]</p>\r\n<p style=\"text-align: left;\">[/content_band]</p>\r\n<p style=\"text-align: center;\"></p>','Download','','inherit','open','closed','','5931-revision-v1','','','2015-12-07 15:09:18','2015-12-07 15:09:18','',5931,'http://sandbox.arrayfire.com/5931-revision-v1/',0,'revision','',0),(8769,17729,'2015-12-11 16:01:59','2015-12-11 16:01:59','In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library: ArrayFire-Rust - Rust bindings for ArrayFire. We have been working on the wrapper and using it in daily production within the company for the last few months and now regard it stable enough for public distribution.\r\n<h4><a id=\"How_to_use_arrayfire_from_cratesio_2\"></a>How to use ArrayFire from <a href=\"http://crates.io\">crates.io</a></h4>\r\nTo use the rust bindings for ArrayFire from <strong><a href=\"http://crates.io\">crates.io</a></strong>, the following requirements are to be met first:\r\n<ol>\r\n	<li>Download and install ArrayFire binaries based on your operating system.</li>\r\n	<li>If you are on Linux or OSX, set the environment variable <code>AF_PATH</code> to point to ArrayFire installation root folder. (This is automatically set for you on Windows.)</li>\r\n	<li>Make sure you add the path to library files to your path environment variables.\r\n<ul>\r\n	<li>On Linux &amp; OSX: do <code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib</code></li>\r\n	<li>On Windows: Add <code>%AF_PATH%\\lib</code> to your PATH environment variable.</li>\r\n</ul>\r\n</li>\r\n	<li>Run <code>cargo new --bin helloworld &amp;&amp; helloworld</code></li>\r\n	<li>Edit <code>Cargo.toml</code> to add the line <code>arrayfire = \"3.3.0\"</code> to the <code>[dependencies]</code> section.</li>\r\n	<li>Add the following sample rust code to your source file <code>helloworld/src/main.rs</code>.\r\n<pre><code class=\"language-rust\">\r\nextern crate arrayfire as af;\r\nuse af::*; // Ideally, you should use only names you are about to use, for example purposes * is fine.\r\n    \r\nfn main() {\r\n    let num_rows: u64 = 5;\r\n    let num_cols: u64 = 3;\r\n    let dims = Dim4::new(&[num_rows, num_cols, 1, 1]);\r\n    println!(\"Create a 5-by-3 matrix of random floats on the GPU\");\r\n    let a = randu::<f32>(dims);\r\n    print(&a);\r\n}\r\n</code></pre>\r\n</li>\r\n	<li>Run <code>cargo run</code> and you should see output similar to the one below.\r\n<pre><code class=\"language-bash\">\r\nCreate a 5-by-3 matrix of random floats on the GPU\r\n[5 3 1 1]\r\n    0.7402     0.4464     0.7762\r\n    0.9210     0.6673     0.2948\r\n    0.0390     0.1099     0.7140\r\n    0.9690     0.4702     0.3585\r\n    0.9251     0.5132     0.6814\r\n</code></pre>\r\n</li>\r\n</ol>\r\n<h4><a id=\"Documentation_44\"></a>Documentation</h4>\r\nYou can find the documentation for all the functions and macros available in the crate over <a href=\"http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html\">here</a>. You can also look at the ArrayFire C/C++ API documentation <a href=\"http://sandbox.arrayfire.com/docs/group__func__categories.htm\">on ArrayFire.com</a> which categorizes ArrayFire functions into several specific domains.\r\n<h4><a id=\"Example_Project_47\"></a>Example Project</h4>\r\n<a href=\"https://github.com/jramapuram/hal\">hal</a> project is one of the initial adaptors of our rust wrapper for ArrayFire to enable use of GPUs from Rust via ArrayFire.\r\n<h4><a id=\"Credits_50\"></a>Credits</h4>\r\nWe would like to thank <a href=\"https://github.com/jramapuram\" target=\"_blank\">Jason Ramapuram</a> for helping us in writing and reviewing the rust bindings. We would also like to thank the <a href=\"https://users.rust-lang.org/\" target=\"_blank\">users from rust community</a> who provided their invaluable feedback while working on the bindings for ArrayFire.\r\n\r\n&nbsp;','Rust wrapper for ArrayFire','','publish','open','closed','','rust-wrapper-for-arrayfire','','','2016-06-08 01:08:19','2016-06-08 05:08:19','',0,'http://sandbox.arrayfire.com/?p=8769',0,'post','',0),(8770,17729,'2015-12-10 22:41:51','2015-12-10 22:41:51','','ArrayFire from Rust','','inherit','open','closed','','8769-revision-v1','','','2015-12-10 22:41:51','2015-12-10 22:41:51','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8771,17729,'2015-12-10 22:56:51','2015-12-10 22:56:51','We have been working\r\n\r\n&nbsp;\r\n\r\nAuthor Credits:\r\n\r\n[Jason Ramapuram](https://github.com/jramapuram)','ArrayFire from Rust','','inherit','open','closed','','8769-revision-v1','','','2015-12-10 22:56:51','2015-12-10 22:56:51','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8772,17729,'2015-12-10 23:08:47','2015-12-10 23:08:47','My journey with <a href=\"https://www.rust-lang.org/\" target=\"_blank\">Rust</a> started off by learning the basics of the language using the tutorials(<a href=\"https://doc.rust-lang.org/stable/book/guessing-game.html\" target=\"_blank\">Guessing Game</a> &amp; <a href=\"http://Dining Philosophers\" target=\"_blank\">Dining Philosophers</a>) available on the rust website. They are quite good to kick off the rusty ride.\r\n\r\n&nbsp;\r\n\r\nAuthor Credits:\r\n\r\n<a href=\"https://github.com/jramapuram\" target=\"_blank\">Jason Ramapuram</a>','ArrayFire from Rust','','inherit','open','closed','','8769-revision-v1','','','2015-12-10 23:08:47','2015-12-10 23:08:47','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8773,17729,'2015-12-10 23:48:27','2015-12-10 23:48:27','In this post, we would be talking about our latest &amp; newest language bindings for ArrayFire library, ArrayFire-Rust - Rust bindings for ArrayFire.\r\n\r\n&nbsp;\r\n\r\nAuthor Credits:\r\n\r\n<a href=\"https://github.com/jramapuram\" target=\"_blank\">Jason Ramapuram</a>','ArrayFire from Rust','','inherit','open','closed','','8769-revision-v1','','','2015-12-10 23:48:27','2015-12-10 23:48:27','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8774,17729,'2015-12-10 23:49:11','2015-12-10 23:49:11','In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library, ArrayFire-Rust - Rust bindings for ArrayFire.\r\n\r\n&nbsp;\r\n\r\nAuthor Credits:\r\n\r\n<a href=\"https://github.com/jramapuram\" target=\"_blank\">Jason Ramapuram</a>','ArrayFire from Rust','','inherit','open','closed','','8769-revision-v1','','','2015-12-10 23:49:11','2015-12-10 23:49:11','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8775,17729,'2015-12-10 23:55:37','2015-12-10 23:55:37','In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library, <a href=\"https://github.com/arrayfire/arrayfire-rust\" target=\"_blank\">ArrayFire-Rust</a> - Rust bindings for ArrayFire. The wrapper itself has been a work in progress for the past few months and we think now it is ready for it\'s first release. &lt;h4&gt;Credits&lt;/h4&gt;We would like to thank <a href=\"https://github.com/jramapuram\" target=\"_blank\">Jason Ramapuram</a> for helping us in writing and reviewing the rust bindings. We would also like to thank you the users from <a href=\"https://users.rust-lang.org/\" target=\"_blank\">rust community</a> who provided their valuable feedback while coming with the bindings for ArrayFire.\r\n\r\n&nbsp;\r\n\r\n&nbsp;','ArrayFire from Rust','','inherit','open','closed','','8769-revision-v1','','','2015-12-10 23:55:37','2015-12-10 23:55:37','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8776,17729,'2015-12-10 23:56:46','2015-12-10 23:56:46','In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library, <a href=\"https://github.com/arrayfire/arrayfire-rust\" target=\"_blank\">ArrayFire-Rust</a> - Rust bindings for ArrayFire. The wrapper itself has been a work in progress for the past few months and we think now it is ready for it\'s first release. CreditsWe would like to thank <a href=\"https://github.com/jramapuram\" target=\"_blank\">Jason Ramapuram</a> for helping us in writing and reviewing the rust bindings. We would also like to thank the users from <a href=\"https://users.rust-lang.org/\" target=\"_blank\">rust community</a> who provided their invaluable feedback while working on the bindings for ArrayFire.\r\n\r\n&nbsp;\r\n\r\n&nbsp;','ArrayFire from Rust','','inherit','open','closed','','8769-revision-v1','','','2015-12-10 23:56:46','2015-12-10 23:56:46','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8777,17729,'2015-12-10 23:57:34','2015-12-10 23:57:34','In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library, <a href=\"https://github.com/arrayfire/arrayfire-rust\" target=\"_blank\">ArrayFire-Rust</a> - Rust bindings for ArrayFire. The wrapper itself has been a work in progress for the past few months and we think now it is ready for it\'s first release.\r\n<h4>Credits</h4>\r\nWe would like to thank <a href=\"https://github.com/jramapuram\" target=\"_blank\">Jason Ramapuram</a> for helping us in writing and reviewing the rust bindings. We would also like to thank the users from <a href=\"https://users.rust-lang.org/\" target=\"_blank\">rust community</a> who provided their invaluable feedback while working on the bindings for ArrayFire.\r\n\r\n&nbsp;\r\n\r\n&nbsp;','ArrayFire from Rust','','inherit','open','closed','','8769-revision-v1','','','2015-12-10 23:57:34','2015-12-10 23:57:34','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8778,17729,'2015-12-11 00:01:26','2015-12-11 00:01:26','In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library, <a href=\"https://github.com/arrayfire/arrayfire-rust\" target=\"_blank\">ArrayFire-Rust</a> - Rust bindings for ArrayFire. The wrapper itself has been a work in progress for the past few months and we think now it is ready for it\'s first release.\r\n<h4>Use arrayfire from crates.io</h4>\r\nTo use the rust bindings for ArrayFire from crates.io, the following requirements are to be met first.\r\n<ol>\r\n	<li><a href=\"https://sandbox.arrayfire.com/download\">Download and install ArrayFire binaries</a> based on your operating system.</li>\r\n	<li>Set the evironment variable <code>AF_PATH</code> to point to ArrayFire installation root folder.</li>\r\n	<li>Make sure you add the path to library files to your path environment variables.\r\n<ul>\r\n	<li>On Linux &amp; OSX: do <code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib</code></li>\r\n	<li>On Windows: Add <code>%AF_PATH%\\lib</code> to your PATH environment variable.</li>\r\n</ul>\r\n</li>\r\n	<li>Add <code>arrayfire = \"3.2.0\"</code> to the dependencies section of your project\'s Cargo.toml file.</li>\r\n</ol>\r\n<h4>Credits</h4>\r\nWe would like to thank <a href=\"https://github.com/jramapuram\" target=\"_blank\">Jason Ramapuram</a> for helping us in writing and reviewing the rust bindings. We would also like to thank the users from <a href=\"https://users.rust-lang.org/\" target=\"_blank\">rust community</a> who provided their invaluable feedback while working on the bindings for ArrayFire.\r\n\r\n&nbsp;\r\n\r\n&nbsp;','ArrayFire from Rust','','inherit','open','closed','','8769-revision-v1','','','2015-12-11 00:01:26','2015-12-11 00:01:26','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0);
INSERT INTO `wp_posts` VALUES (8779,17729,'2015-12-11 00:31:44','2015-12-11 00:31:44','\r\n<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Untitled Document.md</title><style>@import \'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.2.0/katex.min.css\';code{color:#c7254e;background-color:#f9f2f4;border-radius:4px}code,kbd{padding:2px 4px}kbd{color:#fff;background-color:#333;border-radius:3px;box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;box-shadow:none}pre{display:block;margin:0 0 10px;word-break:break-all;word-wrap:break-word;color:#333;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}fieldset{border:0;min-width:0}legend{display:block;width:100%;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=\"radio\"],input[type=\"checkbox\"]{margin:1px 0 0;line-height:normal}input[type=\"file\"]{display:block}input[type=\"range\"]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=\"file\"]:focus,input[type=\"radio\"]:focus,input[type=\"checkbox\"]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{padding-top:7px}output,.form-control{display:block;font-size:14px;line-height:1.4285714;color:#555}.form-control{width:100%;height:34px;padding:6px 12px;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#777;opacity:1}.form-control:-ms-input-placeholder{color:#777}.form-control::-webkit-input-placeholder{color:#777}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=\"date\"],input[type=\"time\"],input[type=\"datetime-local\"],input[type=\"month\"]{line-height:34px;line-height:1.4285714 \\0}input[type=\"date\"].input-sm,.form-horizontal .form-group-sm input[type=\"date\"].form-control,.input-group-sm>input[type=\"date\"].form-control,.input-group-sm>input[type=\"date\"].input-group-addon,.input-group-sm>.input-group-btn>input[type=\"date\"].btn,input[type=\"time\"].input-sm,.form-horizontal .form-group-sm input[type=\"time\"].form-control,.input-group-sm>input[type=\"time\"].form-control,.input-group-sm>input[type=\"time\"].input-group-addon,.input-group-sm>.input-group-btn>input[type=\"time\"].btn,input[type=\"datetime-local\"].input-sm,.form-horizontal .form-group-sm input[type=\"datetime-local\"].form-control,.input-group-sm>input[type=\"datetime-local\"].form-control,.input-group-sm>input[type=\"datetime-local\"].input-group-addon,.input-group-sm>.input-group-btn>input[type=\"datetime-local\"].btn,input[type=\"month\"].input-sm,.form-horizontal .form-group-sm input[type=\"month\"].form-control,.input-group-sm>input[type=\"month\"].form-control,.input-group-sm>input[type=\"month\"].input-group-addon,.input-group-sm>.input-group-btn>input[type=\"month\"].btn{line-height:30px}input[type=\"date\"].input-lg,.form-horizontal .form-group-lg input[type=\"date\"].form-control,.input-group-lg>input[type=\"date\"].form-control,.input-group-lg>input[type=\"date\"].input-group-addon,.input-group-lg>.input-group-btn>input[type=\"date\"].btn,input[type=\"time\"].input-lg,.form-horizontal .form-group-lg input[type=\"time\"].form-control,.input-group-lg>input[type=\"time\"].form-control,.input-group-lg>input[type=\"time\"].input-group-addon,.input-group-lg>.input-group-btn>input[type=\"time\"].btn,input[type=\"datetime-local\"].input-lg,.form-horizontal .form-group-lg input[type=\"datetime-local\"].form-control,.input-group-lg>input[type=\"datetime-local\"].form-control,.input-group-lg>input[type=\"datetime-local\"].input-group-addon,.input-group-lg>.input-group-btn>input[type=\"datetime-local\"].btn,input[type=\"month\"].input-lg,.form-horizontal .form-group-lg input[type=\"month\"].form-control,.input-group-lg>input[type=\"month\"].form-control,.input-group-lg>input[type=\"month\"].input-group-addon,.input-group-lg>.input-group-btn>input[type=\"month\"].btn{line-height:46px}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;min-height:20px;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.radio input[type=\"radio\"],.radio-inline input[type=\"radio\"],.checkbox input[type=\"checkbox\"],.checkbox-inline input[type=\"checkbox\"]{position:absolute;margin-left:-20px;margin-top:4px \\9}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:400;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type=\"radio\"][disabled],input[type=\"radio\"].disabled,fieldset[disabled] input[type=\"radio\"],input[type=\"checkbox\"][disabled],input[type=\"checkbox\"].disabled,fieldset[disabled] input[type=\"checkbox\"],.radio-inline.disabled,fieldset[disabled] .radio-inline,.checkbox-inline.disabled,fieldset[disabled] .checkbox-inline,.radio.disabled label,fieldset[disabled] .radio label,.checkbox.disabled label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-horizontal .form-group-lg .form-control-static.form-control,.input-group-lg>.form-control-static.form-control,.input-group-lg>.form-control-static.input-group-addon,.input-group-lg>.input-group-btn>.form-control-static.btn,.form-control-static.input-sm,.form-horizontal .form-group-sm .form-control-static.form-control,.input-group-sm>.form-control-static.form-control,.input-group-sm>.form-control-static.input-group-addon,.input-group-sm>.input-group-btn>.form-control-static.btn{padding-left:0;padding-right:0}.input-sm,.form-horizontal .form-group-sm .form-control,.input-group-sm>.form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.input-group-sm>.input-group-addon{height:30px;line-height:1.5}.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm,.form-horizontal .form-group-sm select.form-control,.input-group-sm>select.form-control,.input-group-sm>select.input-group-addon,.input-group-sm>.input-group-btn>select.btn{height:30px;line-height:30px}textarea.input-sm,.form-horizontal .form-group-sm textarea.form-control,.input-group-sm>textarea.form-control,.input-group-sm>textarea.input-group-addon,.input-group-sm>.input-group-btn>textarea.btn,select[multiple].input-sm,.form-horizontal .form-group-sm select[multiple].form-control,.input-group-sm>select[multiple].form-control,.input-group-sm>select[multiple].input-group-addon,.input-group-sm>.input-group-btn>select[multiple].btn{height:auto}.input-lg,.form-horizontal .form-group-lg .form-control,.input-group-lg>.form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.input-group-lg>.input-group-addon{height:46px;line-height:1.33}.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg,.form-horizontal .form-group-lg select.form-control,.input-group-lg>select.form-control,.input-group-lg>select.input-group-addon,.input-group-lg>.input-group-btn>select.btn{height:46px;line-height:46px}textarea.input-lg,.form-horizontal .form-group-lg textarea.form-control,.input-group-lg>textarea.form-control,.input-group-lg>textarea.input-group-addon,.input-group-lg>.input-group-btn>textarea.btn,select[multiple].input-lg,.form-horizontal .form-group-lg select[multiple].form-control,.input-group-lg>select[multiple].form-control,.input-group-lg>select[multiple].input-group-addon,.input-group-lg>.input-group-btn>select[multiple].btn{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:25px;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center}.input-lg+.form-control-feedback,.form-horizontal .form-group-lg .form-control+.form-control-feedback,.input-group-lg>.form-control+.form-control-feedback,.input-group-lg>.input-group-addon+.form-control-feedback,.input-group-lg>.input-group-btn>.btn+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback,.form-horizontal .form-group-sm .form-control+.form-control-feedback,.input-group-sm>.form-control+.form-control-feedback,.input-group-sm>.input-group-addon+.form-control-feedback,.input-group-sm>.input-group-btn>.btn+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;border-color:#8a6d3b;background-color:#fcf8e3}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#a94442}.has-error .form-control{border-color:#a94442;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.has-error .form-control-feedback{color:#a94442}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}.form-horizontal .form-group:before{content:\" \";display:table}.form-horizontal .form-group:after{content:\" \";display:table;clear:both}.form-horizontal .has-feedback .form-control-feedback{top:0;right:15px}.btn{display:inline-block;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn:focus,.btn:active:focus,.btn.active:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open>.btn-default.dropdown-toggle{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.btn-default.dropdown-toggle{background-image:none}.btn-default.disabled,.btn-default.disabled:hover,.btn-default.disabled:focus,.btn-default.disabled:active,.btn-default.disabled.active,.btn-default[disabled],.btn-default[disabled]:hover,.btn-default[disabled]:focus,.btn-default[disabled]:active,.btn-default[disabled].active,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default:hover,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open>.btn-primary.dropdown-toggle{color:#fff;background-color:#3071a9;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open>.btn-primary.dropdown-toggle{background-image:none}.btn-primary.disabled,.btn-primary.disabled:hover,.btn-primary.disabled:focus,.btn-primary.disabled:active,.btn-primary.disabled.active,.btn-primary[disabled],.btn-primary[disabled]:hover,.btn-primary[disabled]:focus,.btn-primary[disabled]:active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary:hover,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open>.btn-success.dropdown-toggle{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.btn-success.dropdown-toggle{background-image:none}.btn-success.disabled,.btn-success.disabled:hover,.btn-success.disabled:focus,.btn-success.disabled:active,.btn-success.disabled.active,.btn-success[disabled],.btn-success[disabled]:hover,.btn-success[disabled]:focus,.btn-success[disabled]:active,.btn-success[disabled].active,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success:hover,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open>.btn-info.dropdown-toggle{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.btn-info.dropdown-toggle{background-image:none}.btn-info.disabled,.btn-info.disabled:hover,.btn-info.disabled:focus,.btn-info.disabled:active,.btn-info.disabled.active,.btn-info[disabled],.btn-info[disabled]:hover,.btn-info[disabled]:focus,.btn-info[disabled]:active,.btn-info[disabled].active,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info:hover,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open>.btn-warning.dropdown-toggle{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.btn-warning.dropdown-toggle{background-image:none}.btn-warning.disabled,.btn-warning.disabled:hover,.btn-warning.disabled:focus,.btn-warning.disabled:active,.btn-warning.disabled.active,.btn-warning[disabled],.btn-warning[disabled]:hover,.btn-warning[disabled]:focus,.btn-warning[disabled]:active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning:hover,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open>.btn-danger.dropdown-toggle{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.btn-danger.dropdown-toggle{background-image:none}.btn-danger.disabled,.btn-danger.disabled:hover,.btn-danger.disabled:focus,.btn-danger.disabled:active,.btn-danger.disabled.active,.btn-danger[disabled],.btn-danger[disabled]:hover,.btn-danger[disabled]:focus,.btn-danger[disabled]:active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger:hover,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#428bca;font-weight:400;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:hover,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm{padding:5px 10px}.btn-sm,.btn-xs{font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=\"submit\"].btn-block,input[type=\"reset\"].btn-block,input[type=\"button\"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=\"col-\"]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon{white-space:nowrap}.input-group-addon,.input-group-btn{width:1%;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm,.form-horizontal .form-group-sm .input-group-addon.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.input-group-addon.btn{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg,.form-horizontal .form-group-lg .input-group-addon.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.input-group-addon.btn{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=\"radio\"],.input-group-addon input[type=\"checkbox\"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{font-size:0;white-space:nowrap}.input-group-btn,.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;line-height:1.4285714;text-decoration:none;color:#428bca;background-color:#fff;border:1px solid #ddd;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.pagination>li>a:hover,.pagination>li>a:focus,.pagination>li>span:hover,.pagination>li>span:focus{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:hover,.pagination>.active>a:focus,.pagination>.active>span,.pagination>.active>span:hover,.pagination>.active>span:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca;cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#777;background-color:#fff;border-color:#ddd;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.modal-open,.modal{overflow:hidden}.modal{display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate3d(0,-25%,0);transform:translate3d(0,-25%,0);-webkit-transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.4285714px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.4285714}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{content:\" \";display:table}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}.clearfix:before,.clearfix:after{content:\" \";display:table}.clearfix:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.hljs{display:block;overflow-x:auto;padding:.5em;background:#002b36;color:#839496;-webkit-text-size-adjust:none}.hljs-comment,.hljs-template_comment,.diff .hljs-header,.hljs-doctype,.hljs-pi,.lisp .hljs-string,.hljs-javadoc{color:#586e75}.hljs-keyword,.hljs-winutils,.method,.hljs-addition,.css .hljs-tag,.hljs-request,.hljs-status,.nginx .hljs-title{color:#859900}.hljs-number,.hljs-command,.hljs-string,.hljs-tag .hljs-value,.hljs-rules .hljs-value,.hljs-phpdoc,.hljs-dartdoc,.tex .hljs-formula,.hljs-regexp,.hljs-hexcolor,.hljs-link_url{color:#2aa198}.hljs-title,.hljs-localvars,.hljs-chunk,.hljs-decorator,.hljs-built_in,.hljs-identifier,.vhdl .hljs-literal,.hljs-id,.css .hljs-function{color:#268bd2}.hljs-attribute,.hljs-variable,.lisp .hljs-body,.smalltalk .hljs-number,.hljs-constant,.hljs-class .hljs-title,.hljs-parent,.hljs-type,.hljs-link_reference{color:#b58900}.hljs-preprocessor,.hljs-preprocessor .hljs-keyword,.hljs-pragma,.hljs-shebang,.hljs-symbol,.hljs-symbol .hljs-string,.diff .hljs-change,.hljs-special,.hljs-attr_selector,.hljs-subst,.hljs-cdata,.css .hljs-pseudo,.hljs-header{color:#cb4b16}.hljs-deletion,.hljs-important{color:#dc322f}.hljs-link_label{color:#6c71c4}.tex .hljs-formula{background:#073642}*,*:before,*:after{box-sizing:border-box}html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}images{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd{font-size:1em}code,kbd,pre,samp{font-family:monospace,monospace}samp{font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=\"button\"],input[type=\"reset\"],input[type=\"submit\"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=\"checkbox\"],input[type=\"radio\"]{box-sizing:border-box;padding:0}input[type=\"number\"]::-webkit-inner-spin-button,input[type=\"number\"]::-webkit-outer-spin-button{height:auto}input[type=\"search\"]{-webkit-appearance:textfield;box-sizing:content-box}input[type=\"search\"]::-webkit-search-cancel-button,input[type=\"search\"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}.debug{background-color:#ffc0cb!important}.ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ir{background-color:transparent;border:0;overflow:hidden}.ir::before{content:\'\';display:block;height:150%;width:0}html{font-size:.875em;background:#fafafa;color:#373D49}html,body{font-family:Georgia,Cambria,serif;height:100%}body{font-size:1rem;font-weight:400;line-height:2rem}ul,ol{margin-bottom:.83999rem;padding-top:.16001rem}li{-webkit-font-feature-settings:\'kern\' 1,\'onum\' 1,\'liga\' 1;-moz-font-feature-settings:\'kern\' 1,\'onum\' 1,\'liga\' 1;font-feature-settings:\'kern\' 1,\'onum\' 1,\'liga\' 1;margin-left:1rem}li>ul,li>ol{margin-bottom:0}p{padding-top:.66001rem;-webkit-font-feature-settings:\'kern\' 1,\'onum\' 1,\'liga\' 1;-moz-font-feature-settings:\'kern\' 1,\'onum\' 1,\'liga\' 1;font-feature-settings:\'kern\' 1,\'onum\' 1,\'liga\' 1;margin-top:0}p,pre{margin-bottom:1.33999rem}pre{font-size:1rem;padding:.66001rem 9.5px 9.5px;line-height:2rem;background:-webkit-linear-gradient(top,#fff 0,#fff .75rem,#f5f7fa .75rem,#f5f7fa 2.75rem,#fff 2.75rem,#fff 4rem);background:linear-gradient(to bottom,#fff 0,#fff .75rem,#f5f7fa .75rem,#f5f7fa 2.75rem,#fff 2.75rem,#fff 4rem);background-size:100% 4rem;border-color:#D3DAEA}blockquote{margin:0}blockquote p{font-size:1rem;margin-bottom:.33999rem;font-style:italic;padding:.66001rem 1rem 1rem;border-left:3px solid #A0AABF}th,td{padding:12px}h1,h2,h3,h4,h5,h6{font-family:\"Source Sans Pro\",\"Helvetica Neue\",Helvetica,Arial,sans-serif;-webkit-font-feature-settings:\'dlig\' 1,\'liga\' 1,\'lnum\' 1,\'kern\' 1;-moz-font-feature-settings:\'dlig\' 1,\'liga\' 1,\'lnum\' 1,\'kern\' 1;font-feature-settings:\'dlig\' 1,\'liga\' 1,\'lnum\' 1,\'kern\' 1;font-style:normal;font-weight:600;margin-top:0}h1{line-height:3rem;font-size:2.0571429rem;margin-bottom:.21999rem;padding-top:.78001rem}h2{font-size:1.953125rem;margin-bottom:.1835837rem;padding-top:.8164163rem}h2,h3{line-height:3rem}h3{font-size:1.6457143rem;margin-bottom:.07599rem;padding-top:.92401rem}h4{font-size:1.5625rem;margin-bottom:.546865rem;padding-top:.453135rem}h5{font-size:1.25rem;margin-bottom:-.56251rem;padding-top:.56251rem}h6{font-size:1rem;margin-bottom:-.65001rem;padding-top:.65001rem}a{cursor:pointer;color:#35D7BB;text-decoration:none}a:hover,a:focus{border-bottom-color:#35D7BB;color:#dff9f4}img{height:auto;max-width:100%}.g{display:block}.g:after{clear:both;content:\'\';display:table}.g-b{float:left;margin:0;width:100%}.g{margin-left:-16px;margin-right:-16px}.g-b{padding-left:16px;padding-right:16px}.g-b--center{display:block;float:none;margin:0 auto}.g-b--right{float:right}.g-b--1of1{width:100%}.g-b--1of2,.g-b--2of4,.g-b--3of6,.g-b--4of8,.g-b--5of10,.g-b--6of12{width:50%}.g-b--1of3,.g-b--2of6,.g-b--4of12{width:33.333%}.g-b--2of3,.g-b--4of6,.g-b--8of12{width:66.666%}.g-b--1of4,.g-b--2of8,.g-b--3of12{width:25%}.g-b--3of4,.g-b--6of8,.g-b--9of12{width:75%}.g-b--1of5,.g-b--2of10{width:20%}.g-b--2of5,.g-b--4of10{width:40%}.g-b--3of5,.g-b--6of10{width:60%}.g-b--4of5,.g-b--8of10{width:80%}.g-b--1of6,.g-b--2of12{width:16.666%}.g-b--5of6,.g-b--10of12{width:83.333%}.g-b--1of8{width:12.5%}.g-b--3of8{width:37.5%}.g-b--5of8{width:62.5%}.g-b--7of8{width:87.5%}.g-b--1of10{width:10%}.g-b--3of10{width:30%}.g-b--7of10{width:70%}.g-b--9of10{width:90%}.g-b--1of12{width:8.333%}.g-b--5of12{width:41.666%}.g-b--7of12{width:58.333%}.g-b--11of12{width:91.666%}.g-b--push--1of1{margin-left:100%}.g-b--push--1of2,.g-b--push--2of4,.g-b--push--3of6,.g-b--push--4of8,.g-b--push--5of10,.g-b--push--6of12{margin-left:50%}.g-b--push--1of3,.g-b--push--2of6,.g-b--push--4of12{margin-left:33.333%}.g-b--push--2of3,.g-b--push--4of6,.g-b--push--8of12{margin-left:66.666%}.g-b--push--1of4,.g-b--push--2of8,.g-b--push--3of12{margin-left:25%}.g-b--push--3of4,.g-b--push--6of8,.g-b--push--9of12{margin-left:75%}.g-b--push--1of5,.g-b--push--2of10{margin-left:20%}.g-b--push--2of5,.g-b--push--4of10{margin-left:40%}.g-b--push--3of5,.g-b--push--6of10{margin-left:60%}.g-b--push--4of5,.g-b--push--8of10{margin-left:80%}.g-b--push--1of6,.g-b--push--2of12{margin-left:16.666%}.g-b--push--5of6,.g-b--push--10of12{margin-left:83.333%}.g-b--push--1of8{margin-left:12.5%}.g-b--push--3of8{margin-left:37.5%}.g-b--push--5of8{margin-left:62.5%}.g-b--push--7of8{margin-left:87.5%}.g-b--push--1of10{margin-left:10%}.g-b--push--3of10{margin-left:30%}.g-b--push--7of10{margin-left:70%}.g-b--push--9of10{margin-left:90%}.g-b--push--1of12{margin-left:8.333%}.g-b--push--5of12{margin-left:41.666%}.g-b--push--7of12{margin-left:58.333%}.g-b--push--11of12{margin-left:91.666%}.g-b--pull--1of1{margin-right:100%}.g-b--pull--1of2,.g-b--pull--2of4,.g-b--pull--3of6,.g-b--pull--4of8,.g-b--pull--5of10,.g-b--pull--6of12{margin-right:50%}.g-b--pull--1of3,.g-b--pull--2of6,.g-b--pull--4of12{margin-right:33.333%}.g-b--pull--2of3,.g-b--pull--4of6,.g-b--pull--8of12{margin-right:66.666%}.g-b--pull--1of4,.g-b--pull--2of8,.g-b--pull--3of12{margin-right:25%}.g-b--pull--3of4,.g-b--pull--6of8,.g-b--pull--9of12{margin-right:75%}.g-b--pull--1of5,.g-b--pull--2of10{margin-right:20%}.g-b--pull--2of5,.g-b--pull--4of10{margin-right:40%}.g-b--pull--3of5,.g-b--pull--6of10{margin-right:60%}.g-b--pull--4of5,.g-b--pull--8of10{margin-right:80%}.g-b--pull--1of6,.g-b--pull--2of12{margin-right:16.666%}.g-b--pull--5of6,.g-b--pull--10of12{margin-right:83.333%}.g-b--pull--1of8{margin-right:12.5%}.g-b--pull--3of8{margin-right:37.5%}.g-b--pull--5of8{margin-right:62.5%}.g-b--pull--7of8{margin-right:87.5%}.g-b--pull--1of10{margin-right:10%}.g-b--pull--3of10{margin-right:30%}.g-b--pull--7of10{margin-right:70%}.g-b--pull--9of10{margin-right:90%}.g-b--pull--1of12{margin-right:8.333%}.g-b--pull--5of12{margin-right:41.666%}.g-b--pull--7of12{margin-right:58.333%}.g-b--pull--11of12{margin-right:91.666%}.splashscreen{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#373D49;z-index:22}.splashscreen-dillinger{width:260px;height:auto;display:block;margin:0 auto;padding-bottom:3rem}.splashscreen p{font-size:1.25rem;padding-top:.56251rem;font-family:\"Source Sans Pro\",\"Helvetica Neue\",Helvetica,Arial,sans-serif;font-weight:400;text-align:center;max-width:500px;margin:0 auto;color:#FFF}.sp-center{position:relative;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);top:50%}.open-menu>.wrapper{overflow-x:hidden}.page{margin:0 auto;position:relative;top:0;left:0;width:100%;height:100%;z-index:2;-webkit-transition:all .25s ease-in-out;transition:all .25s ease-in-out;background-color:#fff;padding-top:51px;will-change:left}.open-menu .page{left:270px}.title{line-height:1rem;font-size:.8rem;margin-bottom:.77999rem;padding-top:.22001rem;font-weight:500;color:#A0AABF;letter-spacing:1px;text-transform:uppercase;padding-left:16px;padding-right:16px;margin-top:1rem}.split-preview .title{padding-left:0}.title-document{line-height:1rem;font-size:1.25rem;margin-bottom:.89999rem;padding-top:.10001rem;font-weight:400;font-family:\"Ubuntu Mono\",Monaco;color:#373D49;padding-left:16px;padding-right:16px;width:80%;min-width:300px;outline:0;border:none}.icon{display:block;margin:0 auto;width:36px;height:36px;border-radius:3px;text-align:center}.icon svg{display:inline-block;margin-left:auto;margin-right:auto}.icon-preview{background-color:#373D49;line-height:40px}.icon-preview svg{width:19px;height:12px}.icon-settings{background-color:#373D49;line-height:44px}.icon-settings svg{width:18px;height:18px}.icon-link{width:16px;height:16px;line-height:1;margin-right:24px;text-align:right}.navbar{background-color:#373D49;height:51px;width:100%;position:fixed;top:0;left:0;z-index:6;-webkit-transition:all .25s ease-in-out;transition:all .25s ease-in-out;will-change:left}.navbar:after{content:\"\";display:table;clear:both}.open-menu .navbar{left:270px}.navbar-brand{float:left;margin:0 0 0 24px;padding:0;line-height:42px}.navbar-brand svg{width:85px;height:11px}.nav-left{float:left}.nav-right{float:right}.nav-sidebar{width:100%}.menu{list-style:none;margin:0;padding:0}.menu a{border:0;color:#A0AABF;font-family:\"Source Sans Pro\",\"Helvetica Neue\",Helvetica,Arial,sans-serif;outline:none;text-transform:uppercase}.menu a:hover{color:#35D7BB}.menu .menu-item{border:0;display:none;float:left;margin:0;position:relative}.menu .menu-item>a{display:block;font-size:12px;height:51px;letter-spacing:1px;line-height:51px;padding:0 24px}.menu .menu-item--settings,.menu .menu-item--preview,.menu .menu-item--save-to.in-sidebar,.menu .menu-item--import-from.in-sidebar,.menu .menu-item--link-unlink.in-sidebar,.menu .menu-item--documents.in-sidebar{display:block}.menu .menu-item--documents{padding-bottom:1rem}.menu .menu-item.open>a{background-color:#1D212A}.menu .menu-item-icon>a{height:auto;padding:0}.menu .menu-item-icon:hover>a{background-color:transparent}.menu .menu-link.open i{background-color:#1D212A}.menu .menu-link.open g{fill:#35D7BB}.menu .menu-link-preview,.menu .menu-link-settings{margin-top:8px;width:51px}.menu-sidebar{width:100%}.menu-sidebar .menu-item{float:none;margin-bottom:1px;width:100%}.menu-sidebar .menu-item.open>a{background-color:#373D49}.menu-sidebar .open .caret{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.menu-sidebar>.menu-item:hover .dropdown a,.menu-sidebar>.menu-item:hover .settings a{background-color:transparent}.menu-sidebar .menu-link{background-color:#373D49;font-weight:600}.menu-sidebar .menu-link:after{content:\"\";display:table;clear:both}.menu-sidebar .menu-link>span{float:left}.menu-sidebar .menu-link>.caret{float:right;text-align:right;top:22px}.menu-sidebar .dropdown,.menu-sidebar .settings{background-color:transparent;position:static;width:100%}.dropdown{position:absolute;right:0;top:51px;width:188px}.dropdown,.settings{display:none;background-color:#1D212A}.dropdown{padding:0}.dropdown,.settings,.sidebar-list{list-style:none;margin:0}.sidebar-list{padding:0}.dropdown li{margin:32px 0;padding:0 0 0 32px}.dropdown li,.settings li{line-height:1}.sidebar-list li{line-height:1;margin:32px 0;padding:0 0 0 32px}.dropdown a{color:#D0D6E2}.dropdown a,.settings a,.sidebar-list a{display:block;text-transform:none}.sidebar-list a{color:#D0D6E2}.dropdown a:after,.settings a:after,.sidebar-list a:after{content:\"\";display:table;clear:both}.dropdown .icon,.settings .icon,.sidebar-list .icon{float:right}.open .dropdown,.open .settings,.open .sidebar-list{display:block}.open .dropdown.collapse,.open .collapse.settings,.open .sidebar-list.collapse{display:none}.open .dropdown.collapse.in,.open .collapse.in.settings,.open .sidebar-list.collapse.in{display:block}.dropdown .unlinked .icon,.settings .unlinked .icon,.sidebar-list .unlinked .icon{opacity:.3}.dropdown.documents li,.documents.settings li,.sidebar-list.documents li{background-image:url(\"../img/icons/file.svg\");background-position:240px center;background-repeat:no-repeat;background-size:14px 16px;padding:3px 32px}.dropdown.documents li.octocat,.documents.settings li.octocat,.sidebar-list.documents li.octocat{background-image:url(\"../img/icons/octocat.svg\");background-position:234px center;background-size:24px 24px}.dropdown.documents li:last-child,.documents.settings li:last-child,.sidebar-list.documents li:last-child{margin-bottom:1rem}.dropdown.documents li.active a,.documents.settings li.active a,.sidebar-list.documents li.active a{color:#35D7BB}.settings{position:fixed;top:67px;right:16px;border-radius:3px;width:288px;background-color:#373D49;padding:16px;z-index:7}.show-settings .settings{display:block}.settings .has-checkbox{float:left}.settings a{font-size:1.25rem;font-family:\"Source Sans Pro\",\"Helvetica Neue\",Helvetica,Arial,sans-serif;font-weight:400;-webkit-font-smoothing:antialiased;line-height:28px;color:#D0D6E2}.settings a:after{content:\"\";display:table;clear:both}.settings a:hover{color:#35D7BB}.settings li{border-bottom:1px solid #4F535B;margin:0;padding:16px 0}.settings li:last-child{border-bottom:none}.brand{border:none;display:block}.brand:hover g{fill:#35D7BB}.toggle{display:block;float:left;height:16px;padding:25px 16px 26px;width:40px}.toggle span:after,.toggle span:before{content:\'\';left:0;position:absolute;top:-6px}.toggle span:after{top:6px}.toggle span{display:block;position:relative}.toggle span,.toggle span:after,.toggle span:before{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:#D3DAEA;height:2px;-webkit-transition:all .3s;transition:all .3s;width:20px}.open-menu .toggle span{background-color:transparent}.open-menu .toggle span:before{-webkit-transform:rotate(45deg)translate(3px,3px);-ms-transform:rotate(45deg)translate(3px,3px);transform:rotate(45deg)translate(3px,3px)}.open-menu .toggle span:after{-webkit-transform:rotate(-45deg)translate(5px,-6px);-ms-transform:rotate(-45deg)translate(5px,-6px);transform:rotate(-45deg)translate(5px,-6px)}.caret{display:inline-block;width:0;height:0;margin-left:6px;vertical-align:middle;position:relative;top:-1px;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.sidebar{overflow:auto;height:100%;padding-right:15px;padding-bottom:15px;width:285px}.sidebar-wrapper{-webkit-overflow-scrolling:touch;background-color:#2B2F36;left:0;height:100%;overflow-y:hidden;position:fixed;top:0;width:285px;z-index:1}.sidebar-branding{width:160px;padding:0;margin:16px auto}.header{border-bottom:1px solid #E8E8E8;position:relative}.words{line-height:1rem;font-size:.8rem;margin-bottom:.77999rem;padding-top:.22001rem;font-weight:500;font-family:\"Source Sans Pro\",\"Helvetica Neue\",Helvetica,Arial,sans-serif;color:#A0AABF;letter-spacing:1px;text-transform:uppercase;z-index:5;position:absolute;right:16px;top:0}.words span{color:#000}.btn{text-align:center;display:inline-block;width:100%;text-transform:uppercase;font-weight:600;font-family:\"Source Sans Pro\",\"Helvetica Neue\",Helvetica,Arial,sans-serif;font-size:14px;text-shadow:0 1px 0 #1b8b77;padding:16px 24px;background-color:#35D7BB;border-radius:3px;margin:0 auto 16px;line-height:1;color:#fff;-webkit-transition:all .15s linear;transition:all .15s linear;-webkit-font-smoothing:antialiased}.btn--new,.btn--save{display:block;width:238px}.btn--new:hover,.btn--new:focus,.btn--save:hover,.btn--save:focus{color:#fff;border-bottom-color:transparent;box-shadow:0 1px 3px #24b59c;text-shadow:0 1px 0 #24b59c}.btn--save{background-color:#4A5261;text-shadow:0 1px 1px #1e2127}.btn--save:hover,.btn--save:focus{color:#fff;border-bottom-color:transparent;box-shadow:0 1px 5px #08090a;text-shadow:none}.btn--delete{display:block;width:238px;background-color:transparent;font-size:12px;text-shadow:none}.btn--delete:hover,.btn--delete:focus{color:#fff;border-bottom-color:transparent;text-shadow:0 1px 0 #08090a;opacity:.8}.btn--ok,.btn--close{border-top:0;background-color:#4A5261;text-shadow:0 1px 0 #08090a;margin:0}.btn--ok:hover,.btn--ok:focus,.btn--close:hover,.btn--close:focus{color:#fff;background-color:#292d36;text-shadow:none}.overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:rgba(55,61,73,.8);-webkit-transition:all .25s ease-in-out;transition:all .25s ease-in-out;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out;will-change:left,opacity,visibility;z-index:5;opacity:0;visibility:hidden}.show-settings .overlay{visibility:visible;opacity:1}.switch{float:right;line-height:1}.switch input{display:none}.switch small{display:inline-block;cursor:pointer;padding:0 24px 0 0;-webkit-transition:all ease .2s;transition:all ease .2s;background-color:#2B2F36;border-color:#2B2F36}.switch small,.switch small:before{border-radius:30px;box-shadow:inset 0 0 2px 0 #14171F}.switch small:before{display:block;content:\'\';width:28px;height:28px;background:#fff}.switch.checked small{padding-right:0;padding-left:24px;background-color:#35D7BB;box-shadow:none}.modal--dillinger.about .modal-dialog{font-size:1.25rem;max-width:500px}.modal--dillinger .modal-dialog{max-width:600px;width:auto;margin:5rem auto}.modal--dillinger .modal-content{background:#373D49;border-radius:3px;box-shadow:0 2px 5px 0 #2C3B59;color:#fff;font-family:\"Source Sans Pro\",\"Helvetica Neue\",Helvetica,Arial,sans-serif;font-weight:400;padding:2rem}.modal--dillinger ul{list-style-type:disc;margin:1rem 0;padding:0 0 0 1rem}.modal--dillinger li{padding:0;margin:0}.modal--dillinger .modal-header{border:0;padding:0}.modal--dillinger .modal-body{padding:0}.modal--dillinger .modal-footer{border:0;padding:0}.modal--dillinger .close{color:#fff;opacity:1}.modal-backdrop{background-color:#373D49}.pagination--dillinger{padding:0!important;margin:1.5rem 0!important;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-align-content:stretch;-ms-flex-line-pack:stretch;align-content:stretch}.pagination--dillinger,.pagination--dillinger li{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.pagination--dillinger li{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;text-align:center}.pagination--dillinger li:first-child>a,.pagination--dillinger li.disabled>a,.pagination--dillinger li.disabled>a:hover,.pagination--dillinger li.disabled>a:focus,.pagination--dillinger li>a{background-color:transparent;border-color:#4F535B;border-right-color:transparent}.pagination--dillinger li.active>a,.pagination--dillinger li.active>a:hover,.pagination--dillinger li.active>a:focus{border-color:#4A5261;background-color:#4A5261;color:#fff}.pagination--dillinger li>a{float:none;color:#fff;width:100%;display:block;text-align:center;margin:0;border-right-color:transparent;padding:6px}.pagination--dillinger li>a:hover,.pagination--dillinger li>a:focus{border-color:#35D7BB;background-color:#35D7BB;color:#fff}.pagination--dillinger li:last-child a{border-color:#4F535B}.pagination--dillinger li:first-child a{border-right-color:transparent}.diNotify{position:absolute;z-index:9999;left:0;right:0;top:0;margin:0 auto;max-width:400px;text-align:center;-webkit-transition:top .5s ease-in-out,opacity .5s ease-in-out;transition:top .5s ease-in-out,opacity .5s ease-in-out;visibility:hidden}.diNotify-body{-webkit-font-smoothing:antialiased;background-color:#35D7BB;background:#666E7F;border-radius:3px;color:#fff;font-family:\"Source Sans Pro\",\"Helvetica Neue\",Helvetica,Arial,sans-serif;font-weight:400;overflow:hidden;padding:1rem 2rem .5rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:baseline;-webkit-align-items:baseline;-ms-flex-align:baseline;align-items:baseline;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center}.diNotify-icon{display:block;width:16px;height:16px;line-height:16px;position:relative;top:3px}.diNotify-message{padding-left:1rem}.zen-wrapper{position:fixed;top:0;left:0;right:0;bottom:0;width:100%;height:100%;z-index:10;background-color:#FFF;opacity:0;-webkit-transition:opacity .25s ease-in-out;transition:opacity .25s ease-in-out}.zen-wrapper.on{opacity:1}.enter-zen-mode{background-image:url(\"../img/icons/enter-zen.svg\");right:.5rem;top:.5rem;display:none}.enter-zen-mode,.close-zen-mode{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;background-repeat:no-repeat;width:32px;height:32px;display:block;position:absolute}.close-zen-mode{background-image:url(\"../img/icons/exit-zen.svg\");right:1rem;top:1rem}.zen-page{position:relative;top:0;bottom:0;z-index:11;height:100%;width:100%}#zen{font-size:1.25rem;width:300px;height:80%;margin:0 auto;position:relative;top:10%}#zen:before,#zen:after{content:\"\";position:absolute;height:10%;width:100%;z-index:12;pointer-events:none}.split{overflow:scroll;padding:0!important}.split-editor{padding-left:0;padding-right:0;position:relative}.show-preview .split-editor{display:none}.split-preview{background-color:#fff;display:none;top:0;position:relative;z-index:4}.show-preview .split-preview{display:block}#editor{font-size:1rem;font-family:\"Ubuntu Mono\",Monaco;font-weight:400;line-height:2rem;width:100%;height:100%}#editor .ace_gutter{-webkit-font-smoothing:antialiased}#preview{padding:10px}#preview a{color:#A0AABF;text-decoration:underline}.sr-only{visibility:hidden;text-overflow:110%;overflow:hidden;top:-100px;position:absolute}.mnone{margin:0!important}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type=\"radio\"],.form-inline .checkbox input[type=\"checkbox\"]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:7px}.form-horizontal .form-group-lg .control-label{padding-top:14.3px}.form-horizontal .form-group-sm .control-label{padding-top:6px}.modal-dialog{width:600px;margin:30px auto}.modal-content{box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}@media screen and (min-width:27.5em){html{font-size:.875em}body{font-size:1rem}ul,ol{margin-bottom:.83999rem;padding-top:.16001rem}p{padding-top:.66001rem}p,pre{margin-bottom:1.33999rem}pre,blockquote p{font-size:1rem;padding-top:.66001rem}blockquote p{margin-bottom:.33999rem}h1{font-size:2.0571429rem;margin-bottom:.21999rem;padding-top:.78001rem}h2{font-size:1.953125rem;margin-bottom:.1835837rem;padding-top:.8164163rem}h3{font-size:1.6457143rem;margin-bottom:.07599rem;padding-top:.92401rem}h4{font-size:1.5625rem;margin-bottom:.546865rem;padding-top:.453135rem}h5{font-size:1.25rem;margin-bottom:-.56251rem;padding-top:.56251rem}h6{font-size:1rem;margin-bottom:-.65001rem;padding-top:.65001rem}.g{margin-left:-16px;margin-right:-16px}.g-b{padding-left:16px;padding-right:16px}.g-b--m1of1{width:100%}.g-b--m1of2,.g-b--m2of4,.g-b--m3of6,.g-b--m4of8,.g-b--m5of10,.g-b--m6of12{width:50%}.g-b--m1of3,.g-b--m2of6,.g-b--m4of12{width:33.333%}.g-b--m2of3,.g-b--m4of6,.g-b--m8of12{width:66.666%}.g-b--m1of4,.g-b--m2of8,.g-b--m3of12{width:25%}.g-b--m3of4,.g-b--m6of8,.g-b--m9of12{width:75%}.g-b--m1of5,.g-b--m2of10{width:20%}.g-b--m2of5,.g-b--m4of10{width:40%}.g-b--m3of5,.g-b--m6of10{width:60%}.g-b--m4of5,.g-b--m8of10{width:80%}.g-b--m1of6,.g-b--m2of12{width:16.666%}.g-b--m5of6,.g-b--m10of12{width:83.333%}.g-b--m1of8{width:12.5%}.g-b--m3of8{width:37.5%}.g-b--m5of8{width:62.5%}.g-b--m7of8{width:87.5%}.g-b--m1of10{width:10%}.g-b--m3of10{width:30%}.g-b--m7of10{width:70%}.g-b--m9of10{width:90%}.g-b--m1of12{width:8.333%}.g-b--m5of12{width:41.666%}.g-b--m7of12{width:58.333%}.g-b--m11of12{width:91.666%}.g-b--push--m1of1{margin-left:100%}.g-b--push--m1of2,.g-b--push--m2of4,.g-b--push--m3of6,.g-b--push--m4of8,.g-b--push--m5of10,.g-b--push--m6of12{margin-left:50%}.g-b--push--m1of3,.g-b--push--m2of6,.g-b--push--m4of12{margin-left:33.333%}.g-b--push--m2of3,.g-b--push--m4of6,.g-b--push--m8of12{margin-left:66.666%}.g-b--push--m1of4,.g-b--push--m2of8,.g-b--push--m3of12{margin-left:25%}.g-b--push--m3of4,.g-b--push--m6of8,.g-b--push--m9of12{margin-left:75%}.g-b--push--m1of5,.g-b--push--m2of10{margin-left:20%}.g-b--push--m2of5,.g-b--push--m4of10{margin-left:40%}.g-b--push--m3of5,.g-b--push--m6of10{margin-left:60%}.g-b--push--m4of5,.g-b--push--m8of10{margin-left:80%}.g-b--push--m1of6,.g-b--push--m2of12{margin-left:16.666%}.g-b--push--m5of6,.g-b--push--m10of12{margin-left:83.333%}.g-b--push--m1of8{margin-left:12.5%}.g-b--push--m3of8{margin-left:37.5%}.g-b--push--m5of8{margin-left:62.5%}.g-b--push--m7of8{margin-left:87.5%}.g-b--push--m1of10{margin-left:10%}.g-b--push--m3of10{margin-left:30%}.g-b--push--m7of10{margin-left:70%}.g-b--push--m9of10{margin-left:90%}.g-b--push--m1of12{margin-left:8.333%}.g-b--push--m5of12{margin-left:41.666%}.g-b--push--m7of12{margin-left:58.333%}.g-b--push--m11of12{margin-left:91.666%}.g-b--pull--m1of1{margin-right:100%}.g-b--pull--m1of2,.g-b--pull--m2of4,.g-b--pull--m3of6,.g-b--pull--m4of8,.g-b--pull--m5of10,.g-b--pull--m6of12{margin-right:50%}.g-b--pull--m1of3,.g-b--pull--m2of6,.g-b--pull--m4of12{margin-right:33.333%}.g-b--pull--m2of3,.g-b--pull--m4of6,.g-b--pull--m8of12{margin-right:66.666%}.g-b--pull--m1of4,.g-b--pull--m2of8,.g-b--pull--m3of12{margin-right:25%}.g-b--pull--m3of4,.g-b--pull--m6of8,.g-b--pull--m9of12{margin-right:75%}.g-b--pull--m1of5,.g-b--pull--m2of10{margin-right:20%}.g-b--pull--m2of5,.g-b--pull--m4of10{margin-right:40%}.g-b--pull--m3of5,.g-b--pull--m6of10{margin-right:60%}.g-b--pull--m4of5,.g-b--pull--m8of10{margin-right:80%}.g-b--pull--m1of6,.g-b--pull--m2of12{margin-right:16.666%}.g-b--pull--m5of6,.g-b--pull--m10of12{margin-right:83.333%}.g-b--pull--m1of8{margin-right:12.5%}.g-b--pull--m3of8{margin-right:37.5%}.g-b--pull--m5of8{margin-right:62.5%}.g-b--pull--m7of8{margin-right:87.5%}.g-b--pull--m1of10{margin-right:10%}.g-b--pull--m3of10{margin-right:30%}.g-b--pull--m7of10{margin-right:70%}.g-b--pull--m9of10{margin-right:90%}.g-b--pull--m1of12{margin-right:8.333%}.g-b--pull--m5of12{margin-right:41.666%}.g-b--pull--m7of12{margin-right:58.333%}.g-b--pull--m11of12{margin-right:91.666%}.splashscreen p{font-size:1.25rem;margin-bottom:1.43749rem;padding-top:.56251rem}.title{font-size:.8rem;margin-bottom:.77999rem;padding-top:.22001rem}.title-document{margin-bottom:.89999rem;padding-top:.10001rem}.title-document,.settings a{font-size:1.25rem}.words{font-size:.8rem;margin-bottom:.77999rem;padding-top:.22001rem}.modal--dillinger.about .modal-dialog,#zen{font-size:1.25rem}#zen{width:400px}#editor{font-size:1rem}}@media screen and (min-width:46.25em){html{font-size:.875em}body{font-size:1rem}ul,ol{margin-bottom:.83999rem;padding-top:.16001rem}p{padding-top:.66001rem}p,pre{margin-bottom:1.33999rem}pre,blockquote p{font-size:1rem;padding-top:.66001rem}blockquote p{margin-bottom:.33999rem}h1{font-size:2.0571429rem;margin-bottom:.21999rem;padding-top:.78001rem}h2{font-size:1.953125rem;margin-bottom:.1835837rem;padding-top:.8164163rem}h3{font-size:1.6457143rem;margin-bottom:.07599rem;padding-top:.92401rem}h4{font-size:1.5625rem;margin-bottom:.546865rem;padding-top:.453135rem}h5{font-size:1.25rem;margin-bottom:-.56251rem;padding-top:.56251rem}h6{font-size:1rem;margin-bottom:-.65001rem;padding-top:.65001rem}.g{margin-left:-16px;margin-right:-16px}.g-b{padding-left:16px;padding-right:16px}.g-b--t1of1{width:100%}.g-b--t1of2,.g-b--t2of4,.g-b--t3of6,.g-b--t4of8,.g-b--t5of10,.g-b--t6of12{width:50%}.g-b--t1of3,.g-b--t2of6,.g-b--t4of12{width:33.333%}.g-b--t2of3,.g-b--t4of6,.g-b--t8of12{width:66.666%}.g-b--t1of4,.g-b--t2of8,.g-b--t3of12{width:25%}.g-b--t3of4,.g-b--t6of8,.g-b--t9of12{width:75%}.g-b--t1of5,.g-b--t2of10{width:20%}.g-b--t2of5,.g-b--t4of10{width:40%}.g-b--t3of5,.g-b--t6of10{width:60%}.g-b--t4of5,.g-b--t8of10{width:80%}.g-b--t1of6,.g-b--t2of12{width:16.666%}.g-b--t5of6,.g-b--t10of12{width:83.333%}.g-b--t1of8{width:12.5%}.g-b--t3of8{width:37.5%}.g-b--t5of8{width:62.5%}.g-b--t7of8{width:87.5%}.g-b--t1of10{width:10%}.g-b--t3of10{width:30%}.g-b--t7of10{width:70%}.g-b--t9of10{width:90%}.g-b--t1of12{width:8.333%}.g-b--t5of12{width:41.666%}.g-b--t7of12{width:58.333%}.g-b--t11of12{width:91.666%}.g-b--push--t1of1{margin-left:100%}.g-b--push--t1of2,.g-b--push--t2of4,.g-b--push--t3of6,.g-b--push--t4of8,.g-b--push--t5of10,.g-b--push--t6of12{margin-left:50%}.g-b--push--t1of3,.g-b--push--t2of6,.g-b--push--t4of12{margin-left:33.333%}.g-b--push--t2of3,.g-b--push--t4of6,.g-b--push--t8of12{margin-left:66.666%}.g-b--push--t1of4,.g-b--push--t2of8,.g-b--push--t3of12{margin-left:25%}.g-b--push--t3of4,.g-b--push--t6of8,.g-b--push--t9of12{margin-left:75%}.g-b--push--t1of5,.g-b--push--t2of10{margin-left:20%}.g-b--push--t2of5,.g-b--push--t4of10{margin-left:40%}.g-b--push--t3of5,.g-b--push--t6of10{margin-left:60%}.g-b--push--t4of5,.g-b--push--t8of10{margin-left:80%}.g-b--push--t1of6,.g-b--push--t2of12{margin-left:16.666%}.g-b--push--t5of6,.g-b--push--t10of12{margin-left:83.333%}.g-b--push--t1of8{margin-left:12.5%}.g-b--push--t3of8{margin-left:37.5%}.g-b--push--t5of8{margin-left:62.5%}.g-b--push--t7of8{margin-left:87.5%}.g-b--push--t1of10{margin-left:10%}.g-b--push--t3of10{margin-left:30%}.g-b--push--t7of10{margin-left:70%}.g-b--push--t9of10{margin-left:90%}.g-b--push--t1of12{margin-left:8.333%}.g-b--push--t5of12{margin-left:41.666%}.g-b--push--t7of12{margin-left:58.333%}.g-b--push--t11of12{margin-left:91.666%}.g-b--pull--t1of1{margin-right:100%}.g-b--pull--t1of2,.g-b--pull--t2of4,.g-b--pull--t3of6,.g-b--pull--t4of8,.g-b--pull--t5of10,.g-b--pull--t6of12{margin-right:50%}.g-b--pull--t1of3,.g-b--pull--t2of6,.g-b--pull--t4of12{margin-right:33.333%}.g-b--pull--t2of3,.g-b--pull--t4of6,.g-b--pull--t8of12{margin-right:66.666%}.g-b--pull--t1of4,.g-b--pull--t2of8,.g-b--pull--t3of12{margin-right:25%}.g-b--pull--t3of4,.g-b--pull--t6of8,.g-b--pull--t9of12{margin-right:75%}.g-b--pull--t1of5,.g-b--pull--t2of10{margin-right:20%}.g-b--pull--t2of5,.g-b--pull--t4of10{margin-right:40%}.g-b--pull--t3of5,.g-b--pull--t6of10{margin-right:60%}.g-b--pull--t4of5,.g-b--pull--t8of10{margin-right:80%}.g-b--pull--t1of6,.g-b--pull--t2of12{margin-right:16.666%}.g-b--pull--t5of6,.g-b--pull--t10of12{margin-right:83.333%}.g-b--pull--t1of8{margin-right:12.5%}.g-b--pull--t3of8{margin-right:37.5%}.g-b--pull--t5of8{margin-right:62.5%}.g-b--pull--t7of8{margin-right:87.5%}.g-b--pull--t1of10{margin-right:10%}.g-b--pull--t3of10{margin-right:30%}.g-b--pull--t7of10{margin-right:70%}.g-b--pull--t9of10{margin-right:90%}.g-b--pull--t1of12{margin-right:8.333%}.g-b--pull--t5of12{margin-right:41.666%}.g-b--pull--t7of12{margin-right:58.333%}.g-b--pull--t11of12{margin-right:91.666%}.splashscreen-dillinger{width:500px}.splashscreen p{font-size:1.25rem;margin-bottom:1.43749rem;padding-top:.56251rem}.title{font-size:.8rem;margin-bottom:.77999rem;padding-top:.22001rem}.title-document{font-size:1.25rem;margin-bottom:.89999rem;padding-top:.10001rem}.menu .menu-item--save-to,.menu .menu-item--import-from{display:block}.menu .menu-item--preview,.menu .menu-item--save-to.in-sidebar,.menu .menu-item--import-from.in-sidebar{display:none}.settings a{font-size:1.25rem}.words{font-size:.8rem;margin-bottom:.77999rem;padding-top:.22001rem}.modal--dillinger.about .modal-dialog{font-size:1.25rem}.enter-zen-mode{display:block}.close-zen-mode{right:3rem;top:3rem}#zen{font-size:1.25rem;width:500px}.split-editor{border-right:1px solid #E8E8E8;float:left;height:calc(100vh - 130px);-webkit-overflow-scrolling:touch;padding-right:16px;width:50%}.show-preview .split-editor{display:block}.split-preview{display:block;float:right;height:calc(100vh - 130px);-webkit-overflow-scrolling:touch;position:relative;top:0;width:50%}#editor{font-size:1rem}}@media screen and (min-width:62.5em){html{font-size:.875em}body{font-size:1rem}ul,ol{margin-bottom:.83999rem;padding-top:.16001rem}p{padding-top:.66001rem}p,pre{margin-bottom:1.33999rem}pre,blockquote p{font-size:1rem;padding-top:.66001rem}blockquote p{margin-bottom:.33999rem}h1{font-size:2.0571429rem;margin-bottom:.21999rem;padding-top:.78001rem}h2{font-size:1.953125rem;margin-bottom:.1835837rem;padding-top:.8164163rem}h3{font-size:1.6457143rem;margin-bottom:.07599rem;padding-top:.92401rem}h4{font-size:1.5625rem;margin-bottom:.546865rem;padding-top:.453135rem}h5{font-size:1.25rem;margin-bottom:-.56251rem;padding-top:.56251rem}h6{font-size:1rem;margin-bottom:-.65001rem;padding-top:.65001rem}.g{margin-left:-16px;margin-right:-16px}.g-b{padding-left:16px;padding-right:16px}.g-b--d1of1{width:100%}.g-b--d1of2,.g-b--d2of4,.g-b--d3of6,.g-b--d4of8,.g-b--d5of10,.g-b--d6of12{width:50%}.g-b--d1of3,.g-b--d2of6,.g-b--d4of12{width:33.333%}.g-b--d2of3,.g-b--d4of6,.g-b--d8of12{width:66.666%}.g-b--d1of4,.g-b--d2of8,.g-b--d3of12{width:25%}.g-b--d3of4,.g-b--d6of8,.g-b--d9of12{width:75%}.g-b--d1of5,.g-b--d2of10{width:20%}.g-b--d2of5,.g-b--d4of10{width:40%}.g-b--d3of5,.g-b--d6of10{width:60%}.g-b--d4of5,.g-b--d8of10{width:80%}.g-b--d1of6,.g-b--d2of12{width:16.666%}.g-b--d5of6,.g-b--d10of12{width:83.333%}.g-b--d1of8{width:12.5%}.g-b--d3of8{width:37.5%}.g-b--d5of8{width:62.5%}.g-b--d7of8{width:87.5%}.g-b--d1of10{width:10%}.g-b--d3of10{width:30%}.g-b--d7of10{width:70%}.g-b--d9of10{width:90%}.g-b--d1of12{width:8.333%}.g-b--d5of12{width:41.666%}.g-b--d7of12{width:58.333%}.g-b--d11of12{width:91.666%}.g-b--push--d1of1{margin-left:100%}.g-b--push--d1of2,.g-b--push--d2of4,.g-b--push--d3of6,.g-b--push--d4of8,.g-b--push--d5of10,.g-b--push--d6of12{margin-left:50%}.g-b--push--d1of3,.g-b--push--d2of6,.g-b--push--d4of12{margin-left:33.333%}.g-b--push--d2of3,.g-b--push--d4of6,.g-b--push--d8of12{margin-left:66.666%}.g-b--push--d1of4,.g-b--push--d2of8,.g-b--push--d3of12{margin-left:25%}.g-b--push--d3of4,.g-b--push--d6of8,.g-b--push--d9of12{margin-left:75%}.g-b--push--d1of5,.g-b--push--d2of10{margin-left:20%}.g-b--push--d2of5,.g-b--push--d4of10{margin-left:40%}.g-b--push--d3of5,.g-b--push--d6of10{margin-left:60%}.g-b--push--d4of5,.g-b--push--d8of10{margin-left:80%}.g-b--push--d1of6,.g-b--push--d2of12{margin-left:16.666%}.g-b--push--d5of6,.g-b--push--d10of12{margin-left:83.333%}.g-b--push--d1of8{margin-left:12.5%}.g-b--push--d3of8{margin-left:37.5%}.g-b--push--d5of8{margin-left:62.5%}.g-b--push--d7of8{margin-left:87.5%}.g-b--push--d1of10{margin-left:10%}.g-b--push--d3of10{margin-left:30%}.g-b--push--d7of10{margin-left:70%}.g-b--push--d9of10{margin-left:90%}.g-b--push--d1of12{margin-left:8.333%}.g-b--push--d5of12{margin-left:41.666%}.g-b--push--d7of12{margin-left:58.333%}.g-b--push--d11of12{margin-left:91.666%}.g-b--pull--d1of1{margin-right:100%}.g-b--pull--d1of2,.g-b--pull--d2of4,.g-b--pull--d3of6,.g-b--pull--d4of8,.g-b--pull--d5of10,.g-b--pull--d6of12{margin-right:50%}.g-b--pull--d1of3,.g-b--pull--d2of6,.g-b--pull--d4of12{margin-right:33.333%}.g-b--pull--d2of3,.g-b--pull--d4of6,.g-b--pull--d8of12{margin-right:66.666%}.g-b--pull--d1of4,.g-b--pull--d2of8,.g-b--pull--d3of12{margin-right:25%}.g-b--pull--d3of4,.g-b--pull--d6of8,.g-b--pull--d9of12{margin-right:75%}.g-b--pull--d1of5,.g-b--pull--d2of10{margin-right:20%}.g-b--pull--d2of5,.g-b--pull--d4of10{margin-right:40%}.g-b--pull--d3of5,.g-b--pull--d6of10{margin-right:60%}.g-b--pull--d4of5,.g-b--pull--d8of10{margin-right:80%}.g-b--pull--d1of6,.g-b--pull--d2of12{margin-right:16.666%}.g-b--pull--d5of6,.g-b--pull--d10of12{margin-right:83.333%}.g-b--pull--d1of8{margin-right:12.5%}.g-b--pull--d3of8{margin-right:37.5%}.g-b--pull--d5of8{margin-right:62.5%}.g-b--pull--d7of8{margin-right:87.5%}.g-b--pull--d1of10{margin-right:10%}.g-b--pull--d3of10{margin-right:30%}.g-b--pull--d7of10{margin-right:70%}.g-b--pull--d9of10{margin-right:90%}.g-b--pull--d1of12{margin-right:8.333%}.g-b--pull--d5of12{margin-right:41.666%}.g-b--pull--d7of12{margin-right:58.333%}.g-b--pull--d11of12{margin-right:91.666%}.splashscreen-dillinger{width:700px}.splashscreen p{font-size:1.25rem;margin-bottom:1.43749rem;padding-top:.56251rem}.title{font-size:.8rem;margin-bottom:.77999rem;padding-top:.22001rem}.title-document{font-size:1.25rem;margin-bottom:.89999rem;padding-top:.10001rem}.menu .menu-item--export-as{display:block}.menu .menu-item--preview{display:none}.settings a{font-size:1.25rem}.words{font-size:.8rem;margin-bottom:.77999rem;padding-top:.22001rem}.modal--dillinger.about .modal-dialog,#zen{font-size:1.25rem}#zen{width:700px}#editor{font-size:1rem}}@media screen and (min-width:87.5em){html{font-size:.875em}body{font-size:1rem}ul,ol{margin-bottom:.83999rem;padding-top:.16001rem}p{padding-top:.66001rem}p,pre{margin-bottom:1.33999rem}pre,blockquote p{font-size:1rem;padding-top:.66001rem}blockquote p{margin-bottom:.33999rem}h1{font-size:2.0571429rem;margin-bottom:.21999rem;padding-top:.78001rem}h2{font-size:1.953125rem;margin-bottom:.1835837rem;padding-top:.8164163rem}h3{font-size:1.6457143rem;margin-bottom:.07599rem;padding-top:.92401rem}h4{font-size:1.5625rem;margin-bottom:.546865rem;padding-top:.453135rem}h5{font-size:1.25rem;margin-bottom:-.56251rem;padding-top:.56251rem}h6{font-size:1rem;margin-bottom:-.65001rem;padding-top:.65001rem}.splashscreen-dillinger{width:800px}.splashscreen p{font-size:1.25rem;margin-bottom:1.43749rem;padding-top:.56251rem}.title{font-size:.8rem;margin-bottom:.77999rem;padding-top:.22001rem}.title-document{margin-bottom:.89999rem;padding-top:.10001rem}.title-document,.settings a{font-size:1.25rem}.words{font-size:.8rem;margin-bottom:.77999rem;padding-top:.22001rem}.modal--dillinger.about .modal-dialog,#zen{font-size:1.25rem}#editor{font-size:1rem}}</style></head><body id=\"preview\">\r\n<p>In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library, ArrayFire-Rust - Rust bindings for ArrayFire. The wrapper itself has been a work in progress for the past few months and we think now it is ready for it’s first release.</p>\r\n<h4><a id=\"How_to_use_arrayfire_from_cratesio_2\"></a>How to use arrayfire from <a href=\"http://crates.io\">crates.io</a></h4>\r\n<p>To use the rust bindings for ArrayFire from <strong><a href=\"http://crates.io\">crates.io</a></strong>, the following requirements are to be met first.</p>\r\n<ol>\r\n<li>Download and install ArrayFire binaries based on your operating system.</li>\r\n<li>Set the evironment variable <code>AF_PATH</code> to point to ArrayFire installation root folder.</li>\r\n<li>Make sure you add the path to library files to your path environment variables.\r\n<ul>\r\n<li>On Linux &amp; OSX: do <code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib</code></li>\r\n<li>On Windows: Add <code>%AF_PATH%\\lib</code> to your PATH environment variable.</li>\r\n</ul>\r\n</li>\r\n<li>Do <code>cargo new --bin helloworld &amp;&amp; helloworld</code></li>\r\n<li>Edit <code>Cargo.toml</code> to add the line <code>arrayfire = &quot;3.2.0&quot;</code> to the <code>[dependencies]</code> section.</li>\r\n<li>Add the following sample rust code to your source file <code>helloworld/src/main.rs</code> file<pre><code class=\"language-rust\"><span class=\"hljs-keyword\">extern</span> <span class=\"hljs-keyword\">crate</span> arrayfire <span class=\"hljs-keyword\">as</span> af;\r\n<span class=\"hljs-keyword\">use</span> af::*; <span class=\"hljs-comment\">// Ideally, you should use only names you are about to use, for example purposes * is fine.</span>\r\n\r\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">fn</span> <span class=\"hljs-title\">main</span></span>() {\r\n    <span class=\"hljs-keyword\">let</span> num_rows: <span class=\"hljs-keyword\">u64</span> = <span class=\"hljs-number\">5</span>;\r\n    <span class=\"hljs-keyword\">let</span> num_cols: <span class=\"hljs-keyword\">u64</span> = <span class=\"hljs-number\">3</span>;\r\n    <span class=\"hljs-keyword\">let</span> dims = Dim4::new(&amp;[num_rows, num_cols, <span class=\"hljs-number\">1</span>, <span class=\"hljs-number\">1</span>]);\r\n    <span class=\"hljs-built_in\">println!</span>(<span class=\"hljs-string\">\"Create a 5-by-3 matrix of random floats on the GPU\"</span>);\r\n    <span class=\"hljs-keyword\">let</span> a = <span class=\"hljs-keyword\">match</span> randu(dims, Aftype::F32) {\r\n        <span class=\"hljs-built_in\">Ok</span>(value) =&gt; value,\r\n        <span class=\"hljs-built_in\">Err</span>(error) =&gt; <span class=\"hljs-built_in\">panic!</span>(<span class=\"hljs-string\">\"{}\"</span>, error),\r\n    };\r\n    print(&amp;a);\r\n}\r\n</code></pre>\r\n</li>\r\n<li>Do <code>cargo run</code> and you should see output similar to the one below. Depending on the type of acceleration (GPU - {NVIDIA | AMD}/CPU) devices you have on your machine, the device information will vary as the default device priority is to use any CUDA compatible device available, if not use OpenCL compatbile device and fallback to CPU if no GPUs are available.<pre><code class=\"language-bash\">ArrayFire v3.<span class=\"hljs-number\">2.0</span> (CUDA, <span class=\"hljs-number\">64</span>-bit Mac OSX, build d8d4b38)\r\nPlatform: CUDA Toolkit <span class=\"hljs-number\">7</span>, Driver: CUDA Driver Version: <span class=\"hljs-number\">7000</span>\r\n[<span class=\"hljs-number\">0</span>] GeForce GT <span class=\"hljs-number\">750</span>M, <span class=\"hljs-number\">2048</span> MB, CUDA Compute <span class=\"hljs-number\">3.0</span>\r\nCreate a <span class=\"hljs-number\">5</span>-by-<span class=\"hljs-number\">3</span> matrix of random floats on the GPU\r\n[<span class=\"hljs-number\">5</span> <span class=\"hljs-number\">3</span> <span class=\"hljs-number\">1</span> <span class=\"hljs-number\">1</span>]\r\n    <span class=\"hljs-number\">0.7402</span>     <span class=\"hljs-number\">0.4464</span>     <span class=\"hljs-number\">0.7762</span>\r\n    <span class=\"hljs-number\">0.9210</span>     <span class=\"hljs-number\">0.6673</span>     <span class=\"hljs-number\">0.2948</span>\r\n    <span class=\"hljs-number\">0.0390</span>     <span class=\"hljs-number\">0.1099</span>     <span class=\"hljs-number\">0.7140</span>\r\n    <span class=\"hljs-number\">0.9690</span>     <span class=\"hljs-number\">0.4702</span>     <span class=\"hljs-number\">0.3585</span>\r\n    <span class=\"hljs-number\">0.9251</span>     <span class=\"hljs-number\">0.5132</span>     <span class=\"hljs-number\">0.6814</span>\r\n</code></pre>\r\n</li>\r\n</ol>\r\n<h4><a id=\"Documentation_44\"></a>Documentation</h4>\r\n<p>You can find the documentation for all the functions and macros available in the crate over <a href=\"http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html\">here</a>. You can also look at the ArrayFire native API documentation over <a href=\"http://sandbox.arrayfire.com/docs/group__func__categories.htm\">here</a> which are categorized into different domains.</p>\r\n<h4><a id=\"Example_Project_47\"></a>Example Project</h4>\r\n<p><a href=\"https://github.com/jramapuram/hal\">hal</a> project is one of the initial adaptors of our rust wrapper for ArrayFire to enable use of GPUs from Rust via ArrayFire.</p>\r\n<h4><a id=\"Credits_50\"></a>Credits</h4>\r\n<p>We would like to thank Jason Ramapuram for helping us in writing and reviewing the rust bindings. We would also like to thank the users from rust community who provided their invaluable feedback while working on the bindings for ArrayFire.</p>\r\n\r\n</body></html>','ArrayFire from Rust','','inherit','open','closed','','8769-revision-v1','','','2015-12-11 00:31:44','2015-12-11 00:31:44','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8780,17729,'2015-12-11 00:32:22','2015-12-11 00:32:22','\r\n<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Untitled Document.md</title><style></style></head><body id=\"preview\">\r\n<p>In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library, ArrayFire-Rust - Rust bindings for ArrayFire. The wrapper itself has been a work in progress for the past few months and we think now it is ready for it’s first release.</p>\r\n<h4><a id=\"How_to_use_arrayfire_from_cratesio_2\"></a>How to use arrayfire from <a href=\"http://crates.io\">crates.io</a></h4>\r\n<p>To use the rust bindings for ArrayFire from <strong><a href=\"http://crates.io\">crates.io</a></strong>, the following requirements are to be met first.</p>\r\n<ol>\r\n<li>Download and install ArrayFire binaries based on your operating system.</li>\r\n<li>Set the evironment variable <code>AF_PATH</code> to point to ArrayFire installation root folder.</li>\r\n<li>Make sure you add the path to library files to your path environment variables.\r\n<ul>\r\n<li>On Linux &amp; OSX: do <code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib</code></li>\r\n<li>On Windows: Add <code>%AF_PATH%\\lib</code> to your PATH environment variable.</li>\r\n</ul>\r\n</li>\r\n<li>Do <code>cargo new --bin helloworld &amp;&amp; helloworld</code></li>\r\n<li>Edit <code>Cargo.toml</code> to add the line <code>arrayfire = &quot;3.2.0&quot;</code> to the <code>[dependencies]</code> section.</li>\r\n<li>Add the following sample rust code to your source file <code>helloworld/src/main.rs</code> file<pre><code class=\"language-rust\"><span class=\"hljs-keyword\">extern</span> <span class=\"hljs-keyword\">crate</span> arrayfire <span class=\"hljs-keyword\">as</span> af;\r\n<span class=\"hljs-keyword\">use</span> af::*; <span class=\"hljs-comment\">// Ideally, you should use only names you are about to use, for example purposes * is fine.</span>\r\n\r\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">fn</span> <span class=\"hljs-title\">main</span></span>() {\r\n    <span class=\"hljs-keyword\">let</span> num_rows: <span class=\"hljs-keyword\">u64</span> = <span class=\"hljs-number\">5</span>;\r\n    <span class=\"hljs-keyword\">let</span> num_cols: <span class=\"hljs-keyword\">u64</span> = <span class=\"hljs-number\">3</span>;\r\n    <span class=\"hljs-keyword\">let</span> dims = Dim4::new(&amp;[num_rows, num_cols, <span class=\"hljs-number\">1</span>, <span class=\"hljs-number\">1</span>]);\r\n    <span class=\"hljs-built_in\">println!</span>(<span class=\"hljs-string\">\"Create a 5-by-3 matrix of random floats on the GPU\"</span>);\r\n    <span class=\"hljs-keyword\">let</span> a = <span class=\"hljs-keyword\">match</span> randu(dims, Aftype::F32) {\r\n        <span class=\"hljs-built_in\">Ok</span>(value) =&gt; value,\r\n        <span class=\"hljs-built_in\">Err</span>(error) =&gt; <span class=\"hljs-built_in\">panic!</span>(<span class=\"hljs-string\">\"{}\"</span>, error),\r\n    };\r\n    print(&amp;a);\r\n}\r\n</code></pre>\r\n</li>\r\n<li>Do <code>cargo run</code> and you should see output similar to the one below. Depending on the type of acceleration (GPU - {NVIDIA | AMD}/CPU) devices you have on your machine, the device information will vary as the default device priority is to use any CUDA compatible device available, if not use OpenCL compatbile device and fallback to CPU if no GPUs are available.<pre><code class=\"language-bash\">ArrayFire v3.<span class=\"hljs-number\">2.0</span> (CUDA, <span class=\"hljs-number\">64</span>-bit Mac OSX, build d8d4b38)\r\nPlatform: CUDA Toolkit <span class=\"hljs-number\">7</span>, Driver: CUDA Driver Version: <span class=\"hljs-number\">7000</span>\r\n[<span class=\"hljs-number\">0</span>] GeForce GT <span class=\"hljs-number\">750</span>M, <span class=\"hljs-number\">2048</span> MB, CUDA Compute <span class=\"hljs-number\">3.0</span>\r\nCreate a <span class=\"hljs-number\">5</span>-by-<span class=\"hljs-number\">3</span> matrix of random floats on the GPU\r\n[<span class=\"hljs-number\">5</span> <span class=\"hljs-number\">3</span> <span class=\"hljs-number\">1</span> <span class=\"hljs-number\">1</span>]\r\n    <span class=\"hljs-number\">0.7402</span>     <span class=\"hljs-number\">0.4464</span>     <span class=\"hljs-number\">0.7762</span>\r\n    <span class=\"hljs-number\">0.9210</span>     <span class=\"hljs-number\">0.6673</span>     <span class=\"hljs-number\">0.2948</span>\r\n    <span class=\"hljs-number\">0.0390</span>     <span class=\"hljs-number\">0.1099</span>     <span class=\"hljs-number\">0.7140</span>\r\n    <span class=\"hljs-number\">0.9690</span>     <span class=\"hljs-number\">0.4702</span>     <span class=\"hljs-number\">0.3585</span>\r\n    <span class=\"hljs-number\">0.9251</span>     <span class=\"hljs-number\">0.5132</span>     <span class=\"hljs-number\">0.6814</span>\r\n</code></pre>\r\n</li>\r\n</ol>\r\n<h4><a id=\"Documentation_44\"></a>Documentation</h4>\r\n<p>You can find the documentation for all the functions and macros available in the crate over <a href=\"http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html\">here</a>. You can also look at the ArrayFire native API documentation over <a href=\"http://sandbox.arrayfire.com/docs/group__func__categories.htm\">here</a> which are categorized into different domains.</p>\r\n<h4><a id=\"Example_Project_47\"></a>Example Project</h4>\r\n<p><a href=\"https://github.com/jramapuram/hal\">hal</a> project is one of the initial adaptors of our rust wrapper for ArrayFire to enable use of GPUs from Rust via ArrayFire.</p>\r\n<h4><a id=\"Credits_50\"></a>Credits</h4>\r\n<p>We would like to thank Jason Ramapuram for helping us in writing and reviewing the rust bindings. We would also like to thank the users from rust community who provided their invaluable feedback while working on the bindings for ArrayFire.</p>\r\n\r\n</body></html>','ArrayFire from Rust','','inherit','open','closed','','8769-revision-v1','','','2015-12-11 00:32:22','2015-12-11 00:32:22','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8781,17729,'2015-12-11 00:34:29','2015-12-11 00:34:29','\r\n<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Untitled Document.md</title><style></style></head><body id=\"preview\">\r\n<p>In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library, ArrayFire-Rust - Rust bindings for ArrayFire. The wrapper itself has been a work in progress for the past few months and we think now it is ready for it’s first release.</p>\r\n<h4><a id=\"How_to_use_arrayfire_from_cratesio_2\"></a>How to use arrayfire from <a href=\"http://crates.io\">crates.io</a></h4>\r\n<p>To use the rust bindings for ArrayFire from <strong><a href=\"http://crates.io\">crates.io</a></strong>, the following requirements are to be met first.</p>\r\n<ol>\r\n<li>Download and install ArrayFire binaries based on your operating system.</li>\r\n<li>Set the evironment variable <code>AF_PATH</code> to point to ArrayFire installation root folder.</li>\r\n<li>Make sure you add the path to library files to your path environment variables.\r\n<ul>\r\n<li>On Linux &amp; OSX: do <code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib</code></li>\r\n<li>On Windows: Add <code>%AF_PATH%\\lib</code> to your PATH environment variable.</li>\r\n</ul>\r\n</li>\r\n<li>Do <code>cargo new --bin helloworld &amp;&amp; helloworld</code></li>\r\n<li>Edit <code>Cargo.toml</code> to add the line <code>arrayfire = &quot;3.2.0&quot;</code> to the <code>[dependencies]</code> section.</li>\r\n<li>Add the following sample rust code to your source file <code>helloworld/src/main.rs</code> file<pre><code class=\"language-rust\">\r\n    extern crate arrayfire as af;\r\n    use af::*; // Ideally, you should use only names you are about to use, for example purposes * is fine.\r\n    \r\n    fn main() {\r\n        let num_rows: u64 = 5;\r\n        let num_cols: u64 = 3;\r\n        let dims = Dim4::new(&[num_rows, num_cols, 1, 1]);\r\n        println!(\"Create a 5-by-3 matrix of random floats on the GPU\");\r\n        let a = match randu(dims, Aftype::F32) {\r\n            Ok(value) => value,\r\n            Err(error) => panic!(\"{}\", error),\r\n        };\r\n        print(&a);\r\n    }\r\n</code></pre>\r\n</li>\r\n<li>Do <code>cargo run</code> and you should see output similar to the one below. Depending on the type of acceleration (GPU - {NVIDIA | AMD}/CPU) devices you have on your machine, the device information will vary as the default device priority is to use any CUDA compatible device available, if not use OpenCL compatbile device and fallback to CPU if no GPUs are available.<pre><code class=\"language-bash\">ArrayFire v3.<span class=\"hljs-number\">2.0</span> (CUDA, <span class=\"hljs-number\">64</span>-bit Mac OSX, build d8d4b38)\r\nPlatform: CUDA Toolkit <span class=\"hljs-number\">7</span>, Driver: CUDA Driver Version: <span class=\"hljs-number\">7000</span>\r\n[<span class=\"hljs-number\">0</span>] GeForce GT <span class=\"hljs-number\">750</span>M, <span class=\"hljs-number\">2048</span> MB, CUDA Compute <span class=\"hljs-number\">3.0</span>\r\nCreate a <span class=\"hljs-number\">5</span>-by-<span class=\"hljs-number\">3</span> matrix of random floats on the GPU\r\n[<span class=\"hljs-number\">5</span> <span class=\"hljs-number\">3</span> <span class=\"hljs-number\">1</span> <span class=\"hljs-number\">1</span>]\r\n    <span class=\"hljs-number\">0.7402</span>     <span class=\"hljs-number\">0.4464</span>     <span class=\"hljs-number\">0.7762</span>\r\n    <span class=\"hljs-number\">0.9210</span>     <span class=\"hljs-number\">0.6673</span>     <span class=\"hljs-number\">0.2948</span>\r\n    <span class=\"hljs-number\">0.0390</span>     <span class=\"hljs-number\">0.1099</span>     <span class=\"hljs-number\">0.7140</span>\r\n    <span class=\"hljs-number\">0.9690</span>     <span class=\"hljs-number\">0.4702</span>     <span class=\"hljs-number\">0.3585</span>\r\n    <span class=\"hljs-number\">0.9251</span>     <span class=\"hljs-number\">0.5132</span>     <span class=\"hljs-number\">0.6814</span>\r\n</code></pre>\r\n</li>\r\n</ol>\r\n<h4><a id=\"Documentation_44\"></a>Documentation</h4>\r\n<p>You can find the documentation for all the functions and macros available in the crate over <a href=\"http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html\">here</a>. You can also look at the ArrayFire native API documentation over <a href=\"http://sandbox.arrayfire.com/docs/group__func__categories.htm\">here</a> which are categorized into different domains.</p>\r\n<h4><a id=\"Example_Project_47\"></a>Example Project</h4>\r\n<p><a href=\"https://github.com/jramapuram/hal\">hal</a> project is one of the initial adaptors of our rust wrapper for ArrayFire to enable use of GPUs from Rust via ArrayFire.</p>\r\n<h4><a id=\"Credits_50\"></a>Credits</h4>\r\n<p>We would like to thank Jason Ramapuram for helping us in writing and reviewing the rust bindings. We would also like to thank the users from rust community who provided their invaluable feedback while working on the bindings for ArrayFire.</p>\r\n\r\n</body></html>','ArrayFire from Rust','','inherit','open','closed','','8769-revision-v1','','','2015-12-11 00:34:29','2015-12-11 00:34:29','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8782,17729,'2015-12-11 00:35:16','2015-12-11 00:35:16','\r\n<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Untitled Document.md</title><style></style></head><body id=\"preview\">\r\n<p>In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library, ArrayFire-Rust - Rust bindings for ArrayFire. The wrapper itself has been a work in progress for the past few months and we think now it is ready for it’s first release.</p>\r\n<h4><a id=\"How_to_use_arrayfire_from_cratesio_2\"></a>How to use arrayfire from <a href=\"http://crates.io\">crates.io</a></h4>\r\n<p>To use the rust bindings for ArrayFire from <strong><a href=\"http://crates.io\">crates.io</a></strong>, the following requirements are to be met first.</p>\r\n<ol>\r\n<li>Download and install ArrayFire binaries based on your operating system.</li>\r\n<li>Set the evironment variable <code>AF_PATH</code> to point to ArrayFire installation root folder.</li>\r\n<li>Make sure you add the path to library files to your path environment variables.\r\n<ul>\r\n<li>On Linux &amp; OSX: do <code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib</code></li>\r\n<li>On Windows: Add <code>%AF_PATH%\\lib</code> to your PATH environment variable.</li>\r\n</ul>\r\n</li>\r\n<li>Do <code>cargo new --bin helloworld &amp;&amp; helloworld</code></li>\r\n<li>Edit <code>Cargo.toml</code> to add the line <code>arrayfire = &quot;3.2.0&quot;</code> to the <code>[dependencies]</code> section.</li>\r\n<li>Add the following sample rust code to your source file <code>helloworld/src/main.rs</code> file<pre><code class=\"language-rust\">\r\nextern crate arrayfire as af;\r\nuse af::*; // Ideally, you should use only names you are about to use, for example purposes * is fine.\r\n    \r\nfn main() {\r\n    let num_rows: u64 = 5;\r\n    let num_cols: u64 = 3;\r\n    let dims = Dim4::new(&[num_rows, num_cols, 1, 1]);\r\n    println!(\"Create a 5-by-3 matrix of random floats on the GPU\");\r\n    let a = match randu(dims, Aftype::F32) {\r\n        Ok(value) => value,\r\n        Err(error) => panic!(\"{}\", error),\r\n    };\r\n    print(&a);\r\n}\r\n</code></pre>\r\n</li>\r\n<li>Do <code>cargo run</code> and you should see output similar to the one below. Depending on the type of acceleration (GPU - {NVIDIA | AMD}/CPU) devices you have on your machine, the device information will vary as the default device priority is to use any CUDA compatible device available, if not use OpenCL compatbile device and fallback to CPU if no GPUs are available.<pre><code class=\"language-bash\">ArrayFire v3.<span class=\"hljs-number\">2.0</span> (CUDA, <span class=\"hljs-number\">64</span>-bit Mac OSX, build d8d4b38)\r\nPlatform: CUDA Toolkit <span class=\"hljs-number\">7</span>, Driver: CUDA Driver Version: <span class=\"hljs-number\">7000</span>\r\n[<span class=\"hljs-number\">0</span>] GeForce GT <span class=\"hljs-number\">750</span>M, <span class=\"hljs-number\">2048</span> MB, CUDA Compute <span class=\"hljs-number\">3.0</span>\r\nCreate a <span class=\"hljs-number\">5</span>-by-<span class=\"hljs-number\">3</span> matrix of random floats on the GPU\r\n[<span class=\"hljs-number\">5</span> <span class=\"hljs-number\">3</span> <span class=\"hljs-number\">1</span> <span class=\"hljs-number\">1</span>]\r\n    <span class=\"hljs-number\">0.7402</span>     <span class=\"hljs-number\">0.4464</span>     <span class=\"hljs-number\">0.7762</span>\r\n    <span class=\"hljs-number\">0.9210</span>     <span class=\"hljs-number\">0.6673</span>     <span class=\"hljs-number\">0.2948</span>\r\n    <span class=\"hljs-number\">0.0390</span>     <span class=\"hljs-number\">0.1099</span>     <span class=\"hljs-number\">0.7140</span>\r\n    <span class=\"hljs-number\">0.9690</span>     <span class=\"hljs-number\">0.4702</span>     <span class=\"hljs-number\">0.3585</span>\r\n    <span class=\"hljs-number\">0.9251</span>     <span class=\"hljs-number\">0.5132</span>     <span class=\"hljs-number\">0.6814</span>\r\n</code></pre>\r\n</li>\r\n</ol>\r\n<h4><a id=\"Documentation_44\"></a>Documentation</h4>\r\n<p>You can find the documentation for all the functions and macros available in the crate over <a href=\"http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html\">here</a>. You can also look at the ArrayFire native API documentation over <a href=\"http://sandbox.arrayfire.com/docs/group__func__categories.htm\">here</a> which are categorized into different domains.</p>\r\n<h4><a id=\"Example_Project_47\"></a>Example Project</h4>\r\n<p><a href=\"https://github.com/jramapuram/hal\">hal</a> project is one of the initial adaptors of our rust wrapper for ArrayFire to enable use of GPUs from Rust via ArrayFire.</p>\r\n<h4><a id=\"Credits_50\"></a>Credits</h4>\r\n<p>We would like to thank Jason Ramapuram for helping us in writing and reviewing the rust bindings. We would also like to thank the users from rust community who provided their invaluable feedback while working on the bindings for ArrayFire.</p>\r\n\r\n</body></html>','ArrayFire from Rust','','inherit','open','closed','','8769-revision-v1','','','2015-12-11 00:35:16','2015-12-11 00:35:16','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8783,17729,'2015-12-11 00:37:02','2015-12-11 00:37:02','<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Untitled Document.md</title><style></style></head><body id=\"preview\">\r\n<p>In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library, ArrayFire-Rust - Rust bindings for ArrayFire. The wrapper itself has been a work in progress for the past few months and we think now it is ready for it’s first release.</p>\r\n<h4><a id=\"How_to_use_arrayfire_from_cratesio_2\"></a>How to use arrayfire from <a href=\"http://crates.io\">crates.io</a></h4>\r\n<p>To use the rust bindings for ArrayFire from <strong><a href=\"http://crates.io\">crates.io</a></strong>, the following requirements are to be met first.</p>\r\n<ol>\r\n<li>Download and install ArrayFire binaries based on your operating system.</li>\r\n<li>Set the evironment variable <code>AF_PATH</code> to point to ArrayFire installation root folder.</li>\r\n<li>Make sure you add the path to library files to your path environment variables.\r\n<ul>\r\n<li>On Linux &amp; OSX: do <code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib</code></li>\r\n<li>On Windows: Add <code>%AF_PATH%\\lib</code> to your PATH environment variable.</li>\r\n</ul>\r\n</li>\r\n<li>Do <code>cargo new --bin helloworld &amp;&amp; helloworld</code></li>\r\n<li>Edit <code>Cargo.toml</code> to add the line <code>arrayfire = &quot;3.2.0&quot;</code> to the <code>[dependencies]</code> section.</li>\r\n<li>Add the following sample rust code to your source file <code>helloworld/src/main.rs</code> file<pre><code class=\"language-rust\">\r\nextern crate arrayfire as af;\r\nuse af::*; // Ideally, you should use only names you are about to use, for example purposes * is fine.\r\n    \r\nfn main() {\r\n    let num_rows: u64 = 5;\r\n    let num_cols: u64 = 3;\r\n    let dims = Dim4::new(&[num_rows, num_cols, 1, 1]);\r\n    println!(\"Create a 5-by-3 matrix of random floats on the GPU\");\r\n    let a = match randu(dims, Aftype::F32) {\r\n        Ok(value) => value,\r\n        Err(error) => panic!(\"{}\", error),\r\n    };\r\n    print(&a);\r\n}\r\n</code></pre>\r\n</li>\r\n<li>Do <code>cargo run</code> and you should see output similar to the one below. Depending on the type of acceleration (GPU - {NVIDIA | AMD}/CPU) devices you have on your machine, the device information will vary as the default device priority is to use any CUDA compatible device available, if not use OpenCL compatbile device and fallback to CPU if no GPUs are available.<pre>\r\n<code class=\"language-bash\">\r\nArrayFire v3.2.0 (CUDA, 64-bit Mac OSX, build d8d4b38)\r\nPlatform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000\r\n[0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0\r\nCreate a 5-by-3 matrix of random floats on the GPU\r\n[5 3 1 1]\r\n    0.7402     0.4464     0.7762\r\n    0.9210     0.6673     0.2948\r\n    0.0390     0.1099     0.7140\r\n    0.9690     0.4702     0.3585\r\n    0.9251     0.5132     0.6814\r\n</code></pre>\r\n</li>\r\n</ol>\r\n<h4><a id=\"Documentation_44\"></a>Documentation</h4>\r\n<p>You can find the documentation for all the functions and macros available in the crate over <a href=\"http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html\">here</a>. You can also look at the ArrayFire native API documentation over <a href=\"http://sandbox.arrayfire.com/docs/group__func__categories.htm\">here</a> which are categorized into different domains.</p>\r\n<h4><a id=\"Example_Project_47\"></a>Example Project</h4>\r\n<p><a href=\"https://github.com/jramapuram/hal\">hal</a> project is one of the initial adaptors of our rust wrapper for ArrayFire to enable use of GPUs from Rust via ArrayFire.</p>\r\n<h4><a id=\"Credits_50\"></a>Credits</h4>\r\n<p>We would like to thank Jason Ramapuram for helping us in writing and reviewing the rust bindings. We would also like to thank the users from rust community who provided their invaluable feedback while working on the bindings for ArrayFire.</p>\r\n\r\n</body></html>','ArrayFire from Rust','','inherit','open','closed','','8769-revision-v1','','','2015-12-11 00:37:02','2015-12-11 00:37:02','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8785,18528,'2015-12-11 15:58:24','2015-12-11 15:58:24','&nbsp;\n\nIn this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library: ArrayFire-Rust - Rust bindings for ArrayFire. We have been working on the wrapper and using it in daily production within the company for the last few months and now regard it stable enough for public distribution.\n<h4><a id=\"How_to_use_arrayfire_from_cratesio_2\"></a>How to use ArrayFire from <a href=\"http://crates.io\">crates.io</a></h4>\nTo use the rust bindings for ArrayFire from <strong><a href=\"http://crates.io\">crates.io</a></strong>, the following requirements are to be met first:\n<ol>\n	<li>Download and install ArrayFire binaries based on your operating system.</li>\n	<li>If you are on Linux or OSX, set the environment variable <code>AF_PATH</code> to point to ArrayFire installation root folder. (This is automatically set for you on Windows.)</li>\n	<li>Make sure you add the path to library files to your path environment variables.\n<ul>\n	<li>On Linux &amp; OSX: do <code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib</code></li>\n	<li>On Windows: Add <code>%AF_PATH%\\lib</code> to your PATH environment variable.</li>\n</ul>\n</li>\n	<li>Do <code>cargo new --bin helloworld &amp;&amp; helloworld</code></li>\n	<li>Edit <code>Cargo.toml</code> to add the line <code>arrayfire = \"3.2.0\"</code> to the <code>[dependencies]</code> section.</li>\n	<li>Add the following sample rust code to your source file <code>helloworld/src/main.rs</code> file\n<pre><code class=\"language-rust\">\nextern crate arrayfire as af;\nuse af::*; // Ideally, you should use only names you are about to use, for example purposes * is fine.\n    \nfn main() {\n    let num_rows: u64 = 5;\n    let num_cols: u64 = 3;\n    let dims = Dim4::new(&amp;[num_rows, num_cols, 1, 1]);\n    println!(\"Create a 5-by-3 matrix of random floats on the GPU\");\n    let a = match randu(dims, Aftype::F32) {\n        Ok(value) =&gt; value,\n        Err(error) =&gt; panic!(\"{}\", error),\n    };\n    print(&amp;a);\n}\n</code></pre>\n</li>\n	<li>Do <code>cargo run</code> and you should see output similar to the one below. Depending on the type of acceleration (GPU - {NVIDIA | AMD}/CPU) devices you have on your machine, the device information will vary as the default device priority is to use any CUDA compatible device available, if not use OpenCL compatbile device and fallback to CPU if no GPUs are available.\n<pre><code class=\"language-bash\">\nArrayFire v3.2.0 (CUDA, 64-bit Mac OSX, build d8d4b38)\nPlatform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000\n[0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0\nCreate a 5-by-3 matrix of random floats on the GPU\n[5 3 1 1]\n    0.7402     0.4464     0.7762\n    0.9210     0.6673     0.2948\n    0.0390     0.1099     0.7140\n    0.9690     0.4702     0.3585\n    0.9251     0.5132     0.6814\n</code></pre>\n</li>\n</ol>\n<h4><a id=\"Documentation_44\"></a>Documentation</h4>\nYou can find the documentation for all the functions and macros available in the crate over <a href=\"http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html\">here</a>. You can also look at the ArrayFire C/C++ API documentation <a href=\"http://sandbox.arrayfire.com/docs/group__func__categories.htm\">on ArrayFire.com</a> which categorizes ArrayFire functions into several specific domains.\n<h4><a id=\"Example_Project_47\"></a>Example Project</h4>\n<a href=\"https://github.com/jramapuram/hal\">hal</a> project is one of the initial adaptors of our rust wrapper for ArrayFire to enable use of GPUs from Rust via ArrayFire.\n<h4><a id=\"Credits_50\"></a>Credits</h4>\nWe would like to thank <a href=\"https://github.com/jramapuram\" target=\"_blank\">Jason Ramapuram</a> for helping us in writing and reviewing the rust bindings. We would also like to thank the <a href=\"https://users.rust-lang.org/\" target=\"_blank\">users from rust community</a> who provided their invaluable feedback while working on the bindings for ArrayFire.\n\n&nbsp;','ArrayFire for Rust','','inherit','open','closed','','8769-autosave-v1','','','2015-12-11 15:58:24','2015-12-11 15:58:24','',8769,'http://sandbox.arrayfire.com/8769-autosave-v1/',0,'revision','',0),(8786,18528,'2015-12-11 15:54:55','2015-12-11 15:54:55','&nbsp;\r\n\r\nIn this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library: ArrayFire-Rust - Rust bindings for ArrayFire. We have been working on the wrapper and using it in daily production within the company for the last few months and now regard it stable enough for public distribution.\r\n<h4><a id=\"How_to_use_arrayfire_from_cratesio_2\"></a>How to use ArrayFire from <a href=\"http://crates.io\">crates.io</a></h4>\r\nTo use the rust bindings for ArrayFire from <strong><a href=\"http://crates.io\">crates.io</a></strong>, the following requirements are to be met first:\r\n<ol>\r\n	<li>Download and install ArrayFire binaries based on your operating system.</li>\r\n	<li>If you are on Linux or OSX, set the environment variable <code>AF_PATH</code> to point to ArrayFire installation root folder. (This is automatically set for you on Windows.)</li>\r\n	<li>Make sure you add the path to library files to your path environment variables.\r\n<ul>\r\n	<li>On Linux &amp; OSX: do <code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib</code></li>\r\n	<li>On Windows: Add <code>%AF_PATH%\\lib</code> to your PATH environment variable.</li>\r\n</ul>\r\n</li>\r\n	<li>Do <code>cargo new --bin helloworld &amp;&amp; helloworld</code></li>\r\n	<li>Edit <code>Cargo.toml</code> to add the line <code>arrayfire = \"3.2.0\"</code> to the <code>[dependencies]</code> section.</li>\r\n	<li>Add the following sample rust code to your source file <code>helloworld/src/main.rs</code> file\r\n<pre><code class=\"language-rust\">\r\nextern crate arrayfire as af;\r\nuse af::*; // Ideally, you should use only names you are about to use, for example purposes * is fine.\r\n    \r\nfn main() {\r\n    let num_rows: u64 = 5;\r\n    let num_cols: u64 = 3;\r\n    let dims = Dim4::new(&amp;[num_rows, num_cols, 1, 1]);\r\n    println!(\"Create a 5-by-3 matrix of random floats on the GPU\");\r\n    let a = match randu(dims, Aftype::F32) {\r\n        Ok(value) =&gt; value,\r\n        Err(error) =&gt; panic!(\"{}\", error),\r\n    };\r\n    print(&amp;a);\r\n}\r\n</code></pre>\r\n</li>\r\n	<li>Do <code>cargo run</code> and you should see output similar to the one below. Depending on the type of acceleration (GPU - {NVIDIA | AMD}/CPU) devices you have on your machine, the device information will vary as the default device priority is to use any CUDA compatible device available, if not use OpenCL compatbile device and fallback to CPU if no GPUs are available.\r\n<pre><code class=\"language-bash\">\r\nArrayFire v3.2.0 (CUDA, 64-bit Mac OSX, build d8d4b38)\r\nPlatform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000\r\n[0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0\r\nCreate a 5-by-3 matrix of random floats on the GPU\r\n[5 3 1 1]\r\n    0.7402     0.4464     0.7762\r\n    0.9210     0.6673     0.2948\r\n    0.0390     0.1099     0.7140\r\n    0.9690     0.4702     0.3585\r\n    0.9251     0.5132     0.6814\r\n</code></pre>\r\n</li>\r\n</ol>\r\n<h4><a id=\"Documentation_44\"></a>Documentation</h4>\r\nYou can find the documentation for all the functions and macros available in the crate over <a href=\"http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html\">here</a>. You can also look at the ArrayFire C/C++ API documentation <a href=\"http://sandbox.arrayfire.com/docs/group__func__categories.htm\">on ArrayFire.com</a> which categorizes ArrayFire functions into several specific domains.\r\n<h4><a id=\"Example_Project_47\"></a>Example Project</h4>\r\n<a href=\"https://github.com/jramapuram/hal\">hal</a> project is one of the initial adaptors of our rust wrapper for ArrayFire to enable use of GPUs from Rust via ArrayFire.\r\n<h4><a id=\"Credits_50\"></a>Credits</h4>\r\nWe would like to thank <a href=\"https://github.com/jramapuram\">Jason Ramapuram</a> for helping us in writing and reviewing the rust bindings. We would also like to thank the users from rust community who provided their invaluable feedback while working on the bindings for ArrayFire.\r\n\r\n&nbsp;','ArrayFire from Rust','','inherit','open','closed','','8769-revision-v1','','','2015-12-11 15:54:55','2015-12-11 15:54:55','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8787,18528,'2015-12-11 15:59:24','2015-12-11 15:59:24','&nbsp;\r\n\r\nIn this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library: ArrayFire-Rust - Rust bindings for ArrayFire. We have been working on the wrapper and using it in daily production within the company for the last few months and now regard it stable enough for public distribution.\r\n<h4><a id=\"How_to_use_arrayfire_from_cratesio_2\"></a>How to use ArrayFire from <a href=\"http://crates.io\">crates.io</a></h4>\r\nTo use the rust bindings for ArrayFire from <strong><a href=\"http://crates.io\">crates.io</a></strong>, the following requirements are to be met first:\r\n<ol>\r\n	<li>Download and install ArrayFire binaries based on your operating system.</li>\r\n	<li>If you are on Linux or OSX, set the environment variable <code>AF_PATH</code> to point to ArrayFire installation root folder. (This is automatically set for you on Windows.)</li>\r\n	<li>Make sure you add the path to library files to your path environment variables.\r\n<ul>\r\n	<li>On Linux &amp; OSX: do <code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib</code></li>\r\n	<li>On Windows: Add <code>%AF_PATH%\\lib</code> to your PATH environment variable.</li>\r\n</ul>\r\n</li>\r\n	<li>Do <code>cargo new --bin helloworld &amp;&amp; helloworld</code></li>\r\n	<li>Edit <code>Cargo.toml</code> to add the line <code>arrayfire = \"3.2.0\"</code> to the <code>[dependencies]</code> section.</li>\r\n	<li>Add the following sample rust code to your source file <code>helloworld/src/main.rs</code> file\r\n<pre><code class=\"language-rust\">\r\nextern crate arrayfire as af;\r\nuse af::*; // Ideally, you should use only names you are about to use, for example purposes * is fine.\r\n    \r\nfn main() {\r\n    let num_rows: u64 = 5;\r\n    let num_cols: u64 = 3;\r\n    let dims = Dim4::new(&amp;[num_rows, num_cols, 1, 1]);\r\n    println!(\"Create a 5-by-3 matrix of random floats on the GPU\");\r\n    let a = match randu(dims, Aftype::F32) {\r\n        Ok(value) =&gt; value,\r\n        Err(error) =&gt; panic!(\"{}\", error),\r\n    };\r\n    print(&amp;a);\r\n}\r\n</code></pre>\r\n</li>\r\n	<li>Do <code>cargo run</code> and you should see output similar to the one below. Depending on the type of acceleration (GPU - {NVIDIA | AMD}/CPU) devices you have on your machine, the device information will vary as the default device priority is to use any CUDA compatible device available, if not use OpenCL compatbile device and fallback to CPU if no GPUs are available.\r\n<pre><code class=\"language-bash\">\r\nArrayFire v3.2.0 (CUDA, 64-bit Mac OSX, build d8d4b38)\r\nPlatform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000\r\n[0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0\r\nCreate a 5-by-3 matrix of random floats on the GPU\r\n[5 3 1 1]\r\n    0.7402     0.4464     0.7762\r\n    0.9210     0.6673     0.2948\r\n    0.0390     0.1099     0.7140\r\n    0.9690     0.4702     0.3585\r\n    0.9251     0.5132     0.6814\r\n</code></pre>\r\n</li>\r\n</ol>\r\n<h4><a id=\"Documentation_44\"></a>Documentation</h4>\r\nYou can find the documentation for all the functions and macros available in the crate over <a href=\"http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html\">here</a>. You can also look at the ArrayFire C/C++ API documentation <a href=\"http://sandbox.arrayfire.com/docs/group__func__categories.htm\">on ArrayFire.com</a> which categorizes ArrayFire functions into several specific domains.\r\n<h4><a id=\"Example_Project_47\"></a>Example Project</h4>\r\n<a href=\"https://github.com/jramapuram/hal\">hal</a> project is one of the initial adaptors of our rust wrapper for ArrayFire to enable use of GPUs from Rust via ArrayFire.\r\n<h4><a id=\"Credits_50\"></a>Credits</h4>\r\nWe would like to thank <a href=\"https://github.com/jramapuram\" target=\"_blank\">Jason Ramapuram</a> for helping us in writing and reviewing the rust bindings. We would also like to thank the <a href=\"https://users.rust-lang.org/\" target=\"_blank\">users from rust community</a> who provided their invaluable feedback while working on the bindings for ArrayFire.\r\n\r\n&nbsp;','Rust wrapper for ArrayFire','','inherit','open','closed','','8769-revision-v1','','','2015-12-11 15:59:24','2015-12-11 15:59:24','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8788,18528,'2015-12-11 15:59:44','2015-12-11 15:59:44','In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library: ArrayFire-Rust - Rust bindings for ArrayFire. We have been working on the wrapper and using it in daily production within the company for the last few months and now regard it stable enough for public distribution.\r\n<h4><a id=\"How_to_use_arrayfire_from_cratesio_2\"></a>How to use ArrayFire from <a href=\"http://crates.io\">crates.io</a></h4>\r\nTo use the rust bindings for ArrayFire from <strong><a href=\"http://crates.io\">crates.io</a></strong>, the following requirements are to be met first:\r\n<ol>\r\n	<li>Download and install ArrayFire binaries based on your operating system.</li>\r\n	<li>If you are on Linux or OSX, set the environment variable <code>AF_PATH</code> to point to ArrayFire installation root folder. (This is automatically set for you on Windows.)</li>\r\n	<li>Make sure you add the path to library files to your path environment variables.\r\n<ul>\r\n	<li>On Linux &amp; OSX: do <code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib</code></li>\r\n	<li>On Windows: Add <code>%AF_PATH%\\lib</code> to your PATH environment variable.</li>\r\n</ul>\r\n</li>\r\n	<li>Do <code>cargo new --bin helloworld &amp;&amp; helloworld</code></li>\r\n	<li>Edit <code>Cargo.toml</code> to add the line <code>arrayfire = \"3.2.0\"</code> to the <code>[dependencies]</code> section.</li>\r\n	<li>Add the following sample rust code to your source file <code>helloworld/src/main.rs</code> file\r\n<pre><code class=\"language-rust\">\r\nextern crate arrayfire as af;\r\nuse af::*; // Ideally, you should use only names you are about to use, for example purposes * is fine.\r\n    \r\nfn main() {\r\n    let num_rows: u64 = 5;\r\n    let num_cols: u64 = 3;\r\n    let dims = Dim4::new(&amp;[num_rows, num_cols, 1, 1]);\r\n    println!(\"Create a 5-by-3 matrix of random floats on the GPU\");\r\n    let a = match randu(dims, Aftype::F32) {\r\n        Ok(value) =&gt; value,\r\n        Err(error) =&gt; panic!(\"{}\", error),\r\n    };\r\n    print(&amp;a);\r\n}\r\n</code></pre>\r\n</li>\r\n	<li>Do <code>cargo run</code> and you should see output similar to the one below. Depending on the type of acceleration (GPU - {NVIDIA | AMD}/CPU) devices you have on your machine, the device information will vary as the default device priority is to use any CUDA compatible device available, if not use OpenCL compatbile device and fallback to CPU if no GPUs are available.\r\n<pre><code class=\"language-bash\">\r\nArrayFire v3.2.0 (CUDA, 64-bit Mac OSX, build d8d4b38)\r\nPlatform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000\r\n[0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0\r\nCreate a 5-by-3 matrix of random floats on the GPU\r\n[5 3 1 1]\r\n    0.7402     0.4464     0.7762\r\n    0.9210     0.6673     0.2948\r\n    0.0390     0.1099     0.7140\r\n    0.9690     0.4702     0.3585\r\n    0.9251     0.5132     0.6814\r\n</code></pre>\r\n</li>\r\n</ol>\r\n<h4><a id=\"Documentation_44\"></a>Documentation</h4>\r\nYou can find the documentation for all the functions and macros available in the crate over <a href=\"http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html\">here</a>. You can also look at the ArrayFire C/C++ API documentation <a href=\"http://sandbox.arrayfire.com/docs/group__func__categories.htm\">on ArrayFire.com</a> which categorizes ArrayFire functions into several specific domains.\r\n<h4><a id=\"Example_Project_47\"></a>Example Project</h4>\r\n<a href=\"https://github.com/jramapuram/hal\">hal</a> project is one of the initial adaptors of our rust wrapper for ArrayFire to enable use of GPUs from Rust via ArrayFire.\r\n<h4><a id=\"Credits_50\"></a>Credits</h4>\r\nWe would like to thank <a href=\"https://github.com/jramapuram\" target=\"_blank\">Jason Ramapuram</a> for helping us in writing and reviewing the rust bindings. We would also like to thank the <a href=\"https://users.rust-lang.org/\" target=\"_blank\">users from rust community</a> who provided their invaluable feedback while working on the bindings for ArrayFire.\r\n\r\n&nbsp;','Rust wrapper for ArrayFire','','inherit','open','closed','','8769-revision-v1','','','2015-12-11 15:59:44','2015-12-11 15:59:44','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8789,17729,'2016-06-08 01:08:17','2016-06-08 05:08:17','In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library: ArrayFire-Rust - Rust bindings for ArrayFire. We have been working on the wrapper and using it in daily production within the company for the last few months and now regard it stable enough for public distribution.\n<h4><a id=\"How_to_use_arrayfire_from_cratesio_2\"></a>How to use ArrayFire from <a href=\"http://crates.io\">crates.io</a></h4>\nTo use the rust bindings for ArrayFire from <strong><a href=\"http://crates.io\">crates.io</a></strong>, the following requirements are to be met first:\n<ol>\n	<li>Download and install ArrayFire binaries based on your operating system.</li>\n	<li>If you are on Linux or OSX, set the environment variable <code>AF_PATH</code> to point to ArrayFire installation root folder. (This is automatically set for you on Windows.)</li>\n	<li>Make sure you add the path to library files to your path environment variables.\n<ul>\n	<li>On Linux &amp; OSX: do <code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib</code></li>\n	<li>On Windows: Add <code>%AF_PATH%\\lib</code> to your PATH environment variable.</li>\n</ul>\n</li>\n	<li>Run <code>cargo new --bin helloworld &amp;&amp; helloworld</code></li>\n	<li>Edit <code>Cargo.toml</code> to add the line <code>arrayfire = \"3.3.0\"</code> to the <code>[dependencies]</code> section.</li>\n	<li>Add the following sample rust code to your source file <code>helloworld/src/main.rs</code>.\n<pre><code class=\"language-rust\">\nextern crate arrayfire as af;\nuse af::*; // Ideally, you should use only names you are about to use, for example purposes * is fine.\n    \nfn main() {\n    let num_rows: u64 = 5;\n    let num_cols: u64 = 3;\n    let dims = Dim4::new(&[num_rows, num_cols, 1, 1]);\n    println!(\"Create a 5-by-3 matrix of random floats on the GPU\");\n    let a = randu::<f32>(dims);\n    print(&a);\n}\n</code></pre>\n</li>\n	<li>Run <code>cargo run</code> and you should see output similar to the one below.\n<pre><code class=\"language-bash\">\nCreate a 5-by-3 matrix of random floats on the GPU\n[5 3 1 1]\n    0.7402     0.4464     0.7762\n    0.9210     0.6673     0.2948\n    0.0390     0.1099     0.7140\n    0.9690     0.4702     0.3585\n    0.9251     0.5132     0.6814\n</code></pre>\n</li>\n</ol>\n<h4><a id=\"Documentation_44\"></a>Documentation</h4>\nYou can find the documentation for all the functions and macros available in the crate over <a href=\"http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html\">here</a>. You can also look at the ArrayFire C/C++ API documentation <a href=\"http://sandbox.arrayfire.com/docs/group__func__categories.htm\">on ArrayFire.com</a> which categorizes ArrayFire functions into several specific domains.\n<h4><a id=\"Example_Project_47\"></a>Example Project</h4>\n<a href=\"https://github.com/jramapuram/hal\">hal</a> project is one of the initial adaptors of our rust wrapper for ArrayFire to enable use of GPUs from Rust via ArrayFire.\n<h4><a id=\"Credits_50\"></a>Credits</h4>\nWe would like to thank <a href=\"https://github.com/jramapuram\" target=\"_blank\">Jason Ramapuram</a> for helping us in writing and reviewing the rust bindings. We would also like to thank the <a href=\"https://users.rust-lang.org/\" target=\"_blank\">users from rust community</a> who provided their invaluable feedback while working on the bindings for ArrayFire.\n\n&nbsp;','Rust wrapper for ArrayFire','','inherit','open','closed','','8769-autosave-v1','','','2016-06-08 01:08:17','2016-06-08 05:08:17','',8769,'http://sandbox.arrayfire.com/8769-autosave-v1/',0,'revision','',0),(8790,17729,'2015-12-11 21:18:07','2015-12-11 21:18:07','In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library: ArrayFire-Rust - Rust bindings for ArrayFire. We have been working on the wrapper and using it in daily production within the company for the last few months and now regard it stable enough for public distribution.\r\n<h4><a id=\"How_to_use_arrayfire_from_cratesio_2\"></a>How to use ArrayFire from <a href=\"http://crates.io\">crates.io</a></h4>\r\nTo use the rust bindings for ArrayFire from <strong><a href=\"http://crates.io\">crates.io</a></strong>, the following requirements are to be met first:\r\n<ol>\r\n	<li>Download and install ArrayFire binaries based on your operating system.</li>\r\n	<li>If you are on Linux or OSX, set the environment variable <code>AF_PATH</code> to point to ArrayFire installation root folder. (This is automatically set for you on Windows.)</li>\r\n	<li>Make sure you add the path to library files to your path environment variables.\r\n<ul>\r\n	<li>On Linux &amp; OSX: do <code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib</code></li>\r\n	<li>On Windows: Add <code>%AF_PATH%\\lib</code> to your PATH environment variable.</li>\r\n</ul>\r\n</li>\r\n	<li>Do <code>cargo new --bin helloworld &amp;&amp; helloworld</code></li>\r\n	<li>Edit <code>Cargo.toml</code> to add the line <code>arrayfire = \"3.2.0\"</code> to the <code>[dependencies]</code> section.</li>\r\n	<li>Add the following sample rust code to your source file <code>helloworld/src/main.rs</code> file\r\n<pre><code class=\"language-rust\">\r\nextern crate arrayfire as af;\r\nuse af::*; // Ideally, you should use only names you are about to use, for example purposes * is fine.\r\n    \r\nfn main() {\r\n    let num_rows: u64 = 5;\r\n    let num_cols: u64 = 3;\r\n    let dims = Dim4::new(&[num_rows, num_cols, 1, 1]);\r\n    println!(\"Create a 5-by-3 matrix of random floats on the GPU\");\r\n    let a = match randu(dims, Aftype::F32) {\r\n        Ok(value) => value,\r\n        Err(error) => panic!(\"{}\", error),\r\n    };\r\n    print(&a);\r\n}\r\n</code></pre>\r\n</li>\r\n	<li>Do <code>cargo run</code> and you should see output similar to the one below. Depending on the type of acceleration (GPU - {NVIDIA | AMD}/CPU) devices you have on your machine, the device information will vary as the default device priority is to use any CUDA compatible device available, if not use OpenCL compatbile device and fallback to CPU if no GPUs are available.\r\n<pre><code class=\"language-bash\">\r\nArrayFire v3.2.0 (CUDA, 64-bit Mac OSX, build d8d4b38)\r\nPlatform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000\r\n[0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0\r\nCreate a 5-by-3 matrix of random floats on the GPU\r\n[5 3 1 1]\r\n    0.7402     0.4464     0.7762\r\n    0.9210     0.6673     0.2948\r\n    0.0390     0.1099     0.7140\r\n    0.9690     0.4702     0.3585\r\n    0.9251     0.5132     0.6814\r\n</code></pre>\r\n</li>\r\n</ol>\r\n<h4><a id=\"Documentation_44\"></a>Documentation</h4>\r\nYou can find the documentation for all the functions and macros available in the crate over <a href=\"http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html\">here</a>. You can also look at the ArrayFire C/C++ API documentation <a href=\"http://sandbox.arrayfire.com/docs/group__func__categories.htm\">on ArrayFire.com</a> which categorizes ArrayFire functions into several specific domains.\r\n<h4><a id=\"Example_Project_47\"></a>Example Project</h4>\r\n<a href=\"https://github.com/jramapuram/hal\">hal</a> project is one of the initial adaptors of our rust wrapper for ArrayFire to enable use of GPUs from Rust via ArrayFire.\r\n<h4><a id=\"Credits_50\"></a>Credits</h4>\r\nWe would like to thank <a href=\"https://github.com/jramapuram\" target=\"_blank\">Jason Ramapuram</a> for helping us in writing and reviewing the rust bindings. We would also like to thank the <a href=\"https://users.rust-lang.org/\" target=\"_blank\">users from rust community</a> who provided their invaluable feedback while working on the bindings for ArrayFire.\r\n\r\n&nbsp;','Rust wrapper for ArrayFire','','inherit','open','closed','','8769-revision-v1','','','2015-12-11 21:18:07','2015-12-11 21:18:07','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8791,17729,'2015-12-11 21:23:57','2015-12-11 21:23:57','In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library: ArrayFire-Rust - Rust bindings for ArrayFire. We have been working on the wrapper and using it in daily production within the company for the last few months and now regard it stable enough for public distribution.\r\n<h4><a id=\"How_to_use_arrayfire_from_cratesio_2\"></a>How to use ArrayFire from <a href=\"http://crates.io\">crates.io</a></h4>\r\nTo use the rust bindings for ArrayFire from <strong><a href=\"http://crates.io\">crates.io</a></strong>, the following requirements are to be met first:\r\n<ol>\r\n	<li>Download and install ArrayFire binaries based on your operating system.</li>\r\n	<li>If you are on Linux or OSX, set the environment variable <code>AF_PATH</code> to point to ArrayFire installation root folder. (This is automatically set for you on Windows.)</li>\r\n	<li>Make sure you add the path to library files to your path environment variables.\r\n<ul>\r\n	<li>On Linux &amp; OSX: do <code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib</code></li>\r\n	<li>On Windows: Add <code>%AF_PATH%\\lib</code> to your PATH environment variable.</li>\r\n</ul>\r\n</li>\r\n	<li>Run <code>cargo new --bin helloworld &amp;&amp; helloworld</code></li>\r\n	<li>Edit <code>Cargo.toml</code> to add the line <code>arrayfire = \"3.2.0\"</code> to the <code>[dependencies]</code> section.</li>\r\n	<li>Add the following sample rust code to your source file <code>helloworld/src/main.rs</code>.\r\n<pre><code class=\"language-rust\">\r\nextern crate arrayfire as af;\r\nuse af::*; // Ideally, you should use only names you are about to use, for example purposes * is fine.\r\n    \r\nfn main() {\r\n    let num_rows: u64 = 5;\r\n    let num_cols: u64 = 3;\r\n    let dims = Dim4::new(&[num_rows, num_cols, 1, 1]);\r\n    println!(\"Create a 5-by-3 matrix of random floats on the GPU\");\r\n    let a = match randu(dims, Aftype::F32) {\r\n        Ok(value) => value,\r\n        Err(error) => panic!(\"{}\", error),\r\n    };\r\n    print(&a);\r\n}\r\n</code></pre>\r\n</li>\r\n	<li>Run <code>cargo run</code> and you should see output similar to the one below. Depending on the type of acceleration (GPU - {NVIDIA | AMD}/CPU) devices you have on your machine, the device information will vary as the default device priority is to use any CUDA compatible device available, if not use OpenCL compatbile device and fallback to CPU if no GPUs are available.\r\n<pre><code class=\"language-bash\">\r\nArrayFire v3.2.0 (CUDA, 64-bit Mac OSX, build d8d4b38)\r\nPlatform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000\r\n[0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0\r\nCreate a 5-by-3 matrix of random floats on the GPU\r\n[5 3 1 1]\r\n    0.7402     0.4464     0.7762\r\n    0.9210     0.6673     0.2948\r\n    0.0390     0.1099     0.7140\r\n    0.9690     0.4702     0.3585\r\n    0.9251     0.5132     0.6814\r\n</code></pre>\r\n</li>\r\n</ol>\r\n<h4><a id=\"Documentation_44\"></a>Documentation</h4>\r\nYou can find the documentation for all the functions and macros available in the crate over <a href=\"http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html\">here</a>. You can also look at the ArrayFire C/C++ API documentation <a href=\"http://sandbox.arrayfire.com/docs/group__func__categories.htm\">on ArrayFire.com</a> which categorizes ArrayFire functions into several specific domains.\r\n<h4><a id=\"Example_Project_47\"></a>Example Project</h4>\r\n<a href=\"https://github.com/jramapuram/hal\">hal</a> project is one of the initial adaptors of our rust wrapper for ArrayFire to enable use of GPUs from Rust via ArrayFire.\r\n<h4><a id=\"Credits_50\"></a>Credits</h4>\r\nWe would like to thank <a href=\"https://github.com/jramapuram\" target=\"_blank\">Jason Ramapuram</a> for helping us in writing and reviewing the rust bindings. We would also like to thank the <a href=\"https://users.rust-lang.org/\" target=\"_blank\">users from rust community</a> who provided their invaluable feedback while working on the bindings for ArrayFire.\r\n\r\n&nbsp;','Rust wrapper for ArrayFire','','inherit','open','closed','','8769-revision-v1','','','2015-12-11 21:23:57','2015-12-11 21:23:57','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8792,17729,'2015-12-11 21:24:59','2015-12-11 21:24:59','In this post, we would like to introduce our latest &amp; newest language bindings for ArrayFire library: ArrayFire-Rust - Rust bindings for ArrayFire. We have been working on the wrapper and using it in daily production within the company for the last few months and now regard it stable enough for public distribution.\r\n<h4><a id=\"How_to_use_arrayfire_from_cratesio_2\"></a>How to use ArrayFire from <a href=\"http://crates.io\">crates.io</a></h4>\r\nTo use the rust bindings for ArrayFire from <strong><a href=\"http://crates.io\">crates.io</a></strong>, the following requirements are to be met first:\r\n<ol>\r\n	<li>Download and install ArrayFire binaries based on your operating system.</li>\r\n	<li>If you are on Linux or OSX, set the environment variable <code>AF_PATH</code> to point to ArrayFire installation root folder. (This is automatically set for you on Windows.)</li>\r\n	<li>Make sure you add the path to library files to your path environment variables.\r\n<ul>\r\n	<li>On Linux &amp; OSX: do <code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib</code></li>\r\n	<li>On Windows: Add <code>%AF_PATH%\\lib</code> to your PATH environment variable.</li>\r\n</ul>\r\n</li>\r\n	<li>Run <code>cargo new --bin helloworld &amp;&amp; helloworld</code></li>\r\n	<li>Edit <code>Cargo.toml</code> to add the line <code>arrayfire = \"3.2.0\"</code> to the <code>[dependencies]</code> section.</li>\r\n	<li>Add the following sample rust code to your source file <code>helloworld/src/main.rs</code>.\r\n<pre><code class=\"language-rust\">\r\nextern crate arrayfire as af;\r\nuse af::*; // Ideally, you should use only names you are about to use, for example purposes * is fine.\r\n    \r\nfn main() {\r\n    let num_rows: u64 = 5;\r\n    let num_cols: u64 = 3;\r\n    let dims = Dim4::new(&[num_rows, num_cols, 1, 1]);\r\n    println!(\"Create a 5-by-3 matrix of random floats on the GPU\");\r\n    let a = match randu(dims, Aftype::F32) {\r\n        Ok(value) => value,\r\n        Err(error) => panic!(\"{}\", error),\r\n    };\r\n    print(&a);\r\n}\r\n</code></pre>\r\n</li>\r\n	<li>Run <code>cargo run</code> and you should see output similar to the one below. Depending on the type of acceleration (GPU - {NVIDIA | AMD}/CPU) devices you have on your machine, the device information will vary as the default device priority is to use any CUDA compatible device available, if not then try to find any OpenCL compatbile device and then fallback to CPU if no GPUs are available.\r\n<pre><code class=\"language-bash\">\r\nArrayFire v3.2.0 (CUDA, 64-bit Mac OSX, build d8d4b38)\r\nPlatform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000\r\n[0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0\r\nCreate a 5-by-3 matrix of random floats on the GPU\r\n[5 3 1 1]\r\n    0.7402     0.4464     0.7762\r\n    0.9210     0.6673     0.2948\r\n    0.0390     0.1099     0.7140\r\n    0.9690     0.4702     0.3585\r\n    0.9251     0.5132     0.6814\r\n</code></pre>\r\n</li>\r\n</ol>\r\n<h4><a id=\"Documentation_44\"></a>Documentation</h4>\r\nYou can find the documentation for all the functions and macros available in the crate over <a href=\"http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html\">here</a>. You can also look at the ArrayFire C/C++ API documentation <a href=\"http://sandbox.arrayfire.com/docs/group__func__categories.htm\">on ArrayFire.com</a> which categorizes ArrayFire functions into several specific domains.\r\n<h4><a id=\"Example_Project_47\"></a>Example Project</h4>\r\n<a href=\"https://github.com/jramapuram/hal\">hal</a> project is one of the initial adaptors of our rust wrapper for ArrayFire to enable use of GPUs from Rust via ArrayFire.\r\n<h4><a id=\"Credits_50\"></a>Credits</h4>\r\nWe would like to thank <a href=\"https://github.com/jramapuram\" target=\"_blank\">Jason Ramapuram</a> for helping us in writing and reviewing the rust bindings. We would also like to thank the <a href=\"https://users.rust-lang.org/\" target=\"_blank\">users from rust community</a> who provided their invaluable feedback while working on the bindings for ArrayFire.\r\n\r\n&nbsp;','Rust wrapper for ArrayFire','','inherit','open','closed','','8769-revision-v1','','','2015-12-11 21:24:59','2015-12-11 21:24:59','',8769,'http://sandbox.arrayfire.com/8769-revision-v1/',0,'revision','',0),(8796,17729,'2015-12-18 23:00:29','2015-12-18 23:00:29','[content_band inner_container=\"true\" no_margin=\"true\" border=\"bottom\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"] [custom_headline type=\"left\" level=\"h3\" ]About[/custom_headline]ArrayFire is the software shop for CUDA and OpenCL. Since 2007, ArrayFire has offered the most productive solutions for accelerating code using GPUs. Today, ArrayFire delivers products which are used to accelerate C, C++, and Fortran codes on CUDA GPUs and OpenCL devices. ArrayFire has thousands of customers. These customers come from a wide range of industries, including defense and intelligence, life science, oil and gas, finance, manufacturing, media, and others.\r\n\r\nArrayFire has had success accelerating numerous application types, including math and numerical algorithms, image processing, signal processing, statistics, optimization, and more. Many ArrayFire customers are realizing 100X speed-up with much less effort than is typically required to accelerate code.[/column][column type=\"one-half\" last=\"true\" fade=\"true\"][image src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/dj-Flame.png\"] [/column]\r\n<div id=\"contact\"></div>\r\n[line][column type=\"one-third\"][custom_headline type=\"center\" level=\"h5\" accent=\"false\"]Email[/custom_headline]\r\n<p style=\"text-align: center;\">Sales: sales@arrayfire.com\r\nSupport: support@arrayfire.com\r\nCareers: jobs@arrayfire.com[/column]</p>\r\n[column type=\"one-third\"][custom_headline type=\"center\" level=\"h5\" accent=\"false\"]Phone[/custom_headline]\r\n<p style=\"text-align: center;\">Sales: +1 (800) 570-1941 x 1\r\nTechnical Support: +1 (800) 570-1941 x 2 [/column]</p>\r\n[column type=\"one-third\" last=\"true\"][custom_headline type=\"center\" level=\"h5\" accent=\"false\"]Headquarters[/custom_headline]\r\n<p style=\"text-align: center;\">3405 Piedmont Rd NE STE 100\r\nAtlanta, GA 30305[/column] [/content_band]</p>\r\n[content_band bg_color=\"#f2f2f2\" inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\" ][column type=\"full\"][custom_headline type=\"left\" level=\"h3\" ]Careers[/custom_headline]As a global leader in GPU computing software, our business opportunities are always expanding. We are constantly searching for talented, qualified individuals to join the ArrayFire team. ArrayFire is committed to providing employees with the opportunity to grow and learn, the freedom to express ideas and contribute to new developments, and the motivation to succeed. To start the application process, simply email us your resume and let us know which position(s) you\'re interested in.[/column]\r\n\r\n[line][column type=\"one-third\"][promo image=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/little-boba-fett.png\" alt=\"Alt Text\"][custom_headline type=\"left\" level=\"h5\"  class=\"mtn\"]Software Engineer - Atlanta, GA[/custom_headline]\r\n\r\n<strong>Responsibilities:</strong> Develop in C/C++, Fortran, CUDA, and OpenCL. Respond to forum posts and customer support tickets.\r\n\r\n<strong>Qualifications</strong>: A background in any of high-performance computing, operating systems, or compilers. Several years of C/C++ and at least one year of CUDA or similar technology. Familiarity with Fortran is a plus. Undergraduate or graduate work in CS or related field. [/promo][/column]\r\n\r\n[column type=\"one-third\"][promo image=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/uncle-sam.png\" alt=\"Alt Text\"] [custom_headline type=\"left\" level=\"h5\"  class=\"mtn\"]Application Engineer - Atlanta, GA[/custom_headline]\r\n\r\n<strong>Responsibilities: </strong>Work closely with customers to develop software solutions using our products. Develop technical marketing materials including demos, webinars, tutorials, etc. Respond to forum posts and customer support tickets.\r\n\r\n<strong>Qualifications:</strong> Undergraduate or graduate work in CS or related field. Strong programming skills in C/C++. Excellent communication skills.[/promo][/column]\r\n\r\n[column type=\"one-third\" last=\"true\"][promo image=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/i-see-pride-i-see-power.png\" alt=\"Alt Text\"][custom_headline type=\"left\" level=\"h5\" class=\"mtn\"]Web/Dev Engineer - Atlanta, GA[/custom_headline]\r\n\r\n<strong>Responsibilities: </strong>Develop PHP/MySQL backend infrastructure with basic HTML/CSS/JavaScript frontend work. Developing lightweight webapps for system monitoring. Maintaining Wordpress and SalesForce integration. Maintaining server/cluster infrastructure.\r\n\r\n<strong>Qualifications:</strong> Strong PHP and MySQL experience. Very comfortable at a shell prompt. Proficient in HTML, CSS, and JavaScript. Familiarity with Wordpress or SalesForce is a plus.[/promo][/column]\r\n\r\n[/content_band]','Company','','inherit','open','closed','','329-revision-v1','','','2015-12-18 23:00:29','2015-12-18 23:00:29','',329,'http://sandbox.arrayfire.com/329-revision-v1/',0,'revision','',0),(8797,1,'2015-12-24 04:53:34','2015-12-24 04:53:34','','Order &ndash; December 24, 2015 @ 04:53 AM','','wc-completed','open','closed','order_567b7a4902fa2','order-dec-24-2015-0453-am','','','2015-12-24 04:53:36','2015-12-24 04:53:36','',0,'http://sandbox.arrayfire.com/?post_type=shop_order&#038;p=8797',0,'shop_order','',4),(8804,11,'2016-01-04 15:08:01','2016-01-04 15:08:01','[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"10px\" padding_bottom=\"40px\"]\r\n[custom_headline type=\"left\" level=\"h2\"]\r\nArrayFire Installers\r\n[/custom_headline]\r\n[custom_headline type=\"left\" level=\"h5\"]\r\nEach download contains both CUDA and OpenCL files.\r\n[/custom_headline]\r\n[gap size=\"4%\"]\r\n\r\n[column type=\"one-fourth\"][button  block=\"true\" onclick=\"&lt;!-- Google Code for ArrayFire Download (Windows) Conversion Page\r\nIn your html page, add the snippet and call\r\ngoog_report_conversion when someone clicks on the\r\nchosen link or button. --&gt;\r\n&lt;script type=\"text/javascript\"&gt;\r\n/* &lt;!&amp;#91;CDATA&amp;#91; */\r\ngoog_snippet_vars = function() {\r\nvar w = window;\r\nw.google_conversion_id = 1021026651;\r\nw.google_conversion_label = \"18VJCJjPql4Q28Lu5gM\";\r\nw.google_remarketing_only = false;\r\n}\r\n// DO NOT CHANGE THE CODE BELOW.\r\ngoog_report_conversion = function(url) {\r\ngoog_snippet_vars();\r\nwindow.google_conversion_format = \"3\";\r\nwindow.google_is_call = true;\r\nvar opt = new Object();\r\nopt.onload_callback = function() {\r\nif (typeof(url) != \'undefined\') {\r\nwindow.location = url;\r\n}\r\n}\r\nvar conv_handler = window&amp;#91;\'google_trackConversion\'&amp;#93;;\r\nif (typeof(conv_handler) == \'function\') {\r\nconv_handler(opt);\r\n}\r\n}\r\n/* &amp;#93;&amp;#93;&gt; */\r\n&lt;/script&gt;\r\n&lt;script type=\"text/javascript\"\r\nsrc=\"//www.googleadservices.com/pagead/conversion_async.js\"&gt;\r\n&lt;/script&gt;\" class=\"center-text\" type=\"flat\" shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/windows-installer\" size=\"regular\" ]Windows, v3.2.2\r\n(64-bit)[/button][/column] [column type=\"one-fourth\"][button block=\"true\" type=\"flat\"  shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/linux-x86_64-installer\" size=\"regular\" ]Linux, v3.2.2\r\n(64-bit)[/button][/column][column type=\"one-fourth\"][button  block=\"true\" type=\"flat\"  shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/osx-installer\" size=\"regular\" ]Mac OSX, v3.2.2\r\n(64-bit)[/button][/column] [column type=\"one-fourth\" last=\"true\"][button block=\"true\"  type=\"flat\"  shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/linux-armv7l-installer\" size=\"regular\" ]Tegra K1 v3.2.2\r\n(32-bit)[/button][/column][gap size=\"9%\"]\r\n\r\nCheck out our GitHub repository to <a href=\"https://github.com/arrayfire/arrayfire\">build from the source</a>.\r\n\r\nLooking for an older installer? <a href=\"http://sandbox.arrayfire.com/installer_archive\">Try here</a>.[/content_band]\r\n<p style=\"text-align: left;\">[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"10px\" padding_bottom=\"40px\" bg_color=\"#f1f1f1\"][column type=\"one-half\"][gap size=\"8%\"]<img class=\"aligncenter wp-image-5156\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/02/mobile_Exported1-e1395437261846.png\" alt=\"mobile_Exported\" width=\"233\" height=\"311\" />[/column][column type=\"one-half\" last=\"true\"]\r\n[custom_headline type=\"left\" level=\"h2\"]\r\nGreat. What now?\r\n[/custom_headline]</p>\r\n<p style=\"text-align: left;\">[gap size=\"5%\"]</p>\r\n<p style=\"text-align: left;\">Welcome to ArrayFire! You\'ve got an awesome library there—learn more about its features and functions on <a href=\"http://www.sandbox.arrayfire.com/docs/index.htm\">our documentation</a>.</p>\r\n<p style=\"text-align: left;\">In addition to our <a href=\"https://groups.google.com/forum/#!forum/arrayfire-users\">ArrayFire user group</a> and <a href=\"http://sandbox.arrayfire.com/blog/\">our blog</a>, we offer a plethora of <a href=\"http://sandbox.arrayfire.com/support/\">support options</a> to fit your needs.</p>\r\n<p style=\"text-align: left;\">Got a job that needs closer attention? Hire us! Our engineers are acceleration wizards. Check out our <a href=\"http://sandbox.arrayfire.com/consulting/\">consulting offerings</a>, or set up a free <a href=\"http://meetme.so/arrayfire\">technical consultation</a> with us today![/column]</p>\r\n<p style=\"text-align: left;\">[/content_band]</p>\r\n<p style=\"text-align: center;\"></p>','Download','','inherit','open','closed','','5931-revision-v1','','','2016-01-04 15:08:01','2016-01-04 15:08:01','',5931,'http://sandbox.arrayfire.com/5931-revision-v1/',0,'revision','',0),(8807,17795,'2016-01-05 13:55:52','2016-01-05 18:55:52','[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"]\r\n\r\n[gap size=\"5%\"][custom_headline type=\"left\" level=\"h2\" class=\"mtn\"]Partner Program[/custom_headline]\r\n\r\nThe Partner Program is designed to promote the development and sale of products and services to maximize the productivity of scientists, analysts, and engineers working on technical computing problems that can leverage GPU technology. As our partner, you benefit from a tight working relationship with ArrayFire staff and our other partners, while your customers benefit from the integration of your products and solutions with ArrayFire.\r\n\r\nThe ArrayFire Partner Program is built upon the belief that the purpose of a viable partnership includes a market opportunity, a joint product or service which matches that opportunity, and a strategy to market, sell, and support the joint offering. Therefore, ArrayFire includes programs and activities centered around technical and go-to-market resources that allow the partnership to work hand in hand to develop the solution and properly communicate the solution value into the market while providing the highest level of customer satisfaction.[/column][column type=\"one-half\" last=\"true\"][gap size=\"5%\"]<img class=\"aligncenter  wp-image-5018\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/hq-vehicles-972x1024.png\" alt=\"hq vehicles\" width=\"450\" height=\"473\" />[/column][/content_band]\r\n\r\n[content_band bg_color=\"#f2f2f2\" inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"][gap size=\"10%\"]<img class=\"aligncenter wp-image-4993 \" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/amd_logo_low_res.png\" alt=\"\" width=\"747\" height=\"178\" />[/column][column type=\"one-half\" last=\"true\"]\r\n\r\n[custom_headline type=\"left\" level=\"h2\"]AMD[/custom_headline]\r\n\r\n<span style=\"line-height: 1.5;\"><a href=\"http://developer.amd.com/\">AMD</a> makes OpenCL-capable devices. It serves the high performance computing market with its Opteron™ CPUs &amp; APUs as well as its Radeon™ FirePro™ GPUs.[gap size=\"8%\"]</span>\r\n\r\n[/column]\r\n\r\n[/content_band]\r\n\r\n[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"]\r\n\r\n[custom_headline type=\"left\" level=\"h2\"]Intel[/custom_headline]\r\n\r\n<span style=\"line-height: 1.5;\"><a href=\"http://www.intel.com/content/www/us/en/high-performance-computing/high-performance-xeon-phi-coprocessor-brief.html\">Intel</a> makes OpenCL-capable devices. It serves the high performance computing market with its Intel® Xeon™ CPUs (and integrated GPUs) and Intel® Xeon Phi™ coprocessor.[gap size=\"8%\"]</span>\r\n\r\n[/column][column type=\"one-half\" last=\"true\"]\r\n<img class=\"aligncenter wp-image-5003 size-full\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/Intel_Logo_Capture.png\" alt=\"\" width=\"371\" height=\"265\" />[/column][/content_band]\r\n\r\n[content_band bg_color=\"#f2f2f2\" inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"]\r\n<img class=\"aligncenter wp-image-7071 \" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/11/lbg_nvidia1-1024x193.png\" alt=\"\" width=\"742\" height=\"140\" />[/column]\r\n\r\n[custom_headline type=\"left\" level=\"h2\"]NVIDIA[/custom_headline]\r\n\r\n<span style=\"line-height: 1.5;\"><a href=\"http://www.nvidia.com/object/cuda_home.html\">NVIDIA</a> makes CUDA-capable GPUs. It serves the high performance computing market with its Tesla™ GPUs.[gap size=\"8%\"]</span>\r\n\r\n[/column][column type=\"one-half\" last=\"true\"][gap size=\"10%\"]\r\n\r\n[/content_band]\r\n\r\n[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"][gap size=\"22%\"]\r\n[custom_headline type=\"left\" level=\"h2\"]Xilinx[/custom_headline]\r\n\r\nThe SDAccel™ Development Environment is a member of the Xilinx SDx™ family that combines the industry’s first architecturally optimizing compiler supporting any combination of OpenCL™, C, and C++ kernels, along with libraries and development boards for the first complete CPU/GPU-like development and run-time experience for FPGAs.\r\n\r\nArrayFire is an SDAccel-certified Xilinx Alliance Member.\r\n\r\nTo access the capabilities of SDAccel contact your local <a href=\"http://www.xilinx.com/about/contact.html\" target=\"_blank\">Xilinx sales representative or Xilinx authorized distributor</a>. To learn more visit <a href=\"http://www.xilinx.com/sdaccel\" target=\"_blank\">www.xilinx.com/sdaccel</a>. [gap size=\"8%\"]\r\n\r\n[/column]\r\n<img class=\"aligncenter size-large wp-image-8245\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/05/xilinx_alliance-1024x332.png\" alt=\"xilinx_alliance\" width=\"742\" height=\"241\" />[/column][column type=\"one-half\" last=\"true\"]\r\n[/content_band]','Partner Program','','inherit','open','closed','','187-revision-v1','','','2016-01-05 13:55:52','2016-01-05 18:55:52','',187,'http://sandbox.arrayfire.com/187-revision-v1/',0,'revision','',0),(8808,17795,'2016-01-05 14:00:12','2016-01-05 19:00:12','[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"]\r\n\r\n[gap size=\"5%\"][custom_headline type=\"left\" level=\"h2\" class=\"mtn\"]Partner Program[/custom_headline]\r\n\r\nThe Partner Program is designed to promote the development and sale of products and services to maximize the productivity of scientists, analysts, and engineers working on technical computing problems that can leverage GPU technology. As our partner, you benefit from a tight working relationship with ArrayFire staff and our other partners, while your customers benefit from the integration of your products and solutions with ArrayFire.\r\n\r\nThe ArrayFire Partner Program is built upon the belief that the purpose of a viable partnership includes a market opportunity, a joint product or service which matches that opportunity, and a strategy to market, sell, and support the joint offering. Therefore, ArrayFire includes programs and activities centered around technical and go-to-market resources that allow the partnership to work hand in hand to develop the solution and properly communicate the solution value into the market while providing the highest level of customer satisfaction.[/column][column type=\"one-half\" last=\"true\"][gap size=\"5%\"]<img class=\"aligncenter  wp-image-5018\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/hq-vehicles-972x1024.png\" alt=\"hq vehicles\" width=\"450\" height=\"473\" />[/column][/content_band]\r\n\r\n[content_band bg_color=\"#f2f2f2\" inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"][gap size=\"10%\"]<img class=\"aligncenter wp-image-4993 \" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/amd_logo_low_res.png\" alt=\"\" width=\"747\" height=\"178\" />[/column][column type=\"one-half\" last=\"true\"]\r\n\r\n[custom_headline type=\"left\" level=\"h2\"]AMD[/custom_headline]\r\n\r\n<span style=\"line-height: 1.5;\"><a href=\"http://developer.amd.com/\">AMD</a> makes OpenCL-capable devices. It serves the high performance computing market with its Opteron™ CPUs &amp; APUs as well as its Radeon™ FirePro™ GPUs.[gap size=\"8%\"]</span>\r\n\r\n[/column]\r\n\r\n[/content_band]\r\n\r\n[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"]\r\n\r\n[custom_headline type=\"left\" level=\"h2\"]Intel[/custom_headline]\r\n\r\n<span style=\"line-height: 1.5;\"><a href=\"http://www.intel.com/content/www/us/en/high-performance-computing/high-performance-xeon-phi-coprocessor-brief.html\">Intel</a> makes OpenCL-capable devices. It serves the high performance computing market with its Intel® Xeon™ CPUs (and integrated GPUs) and Intel® Xeon Phi™ coprocessor.[gap size=\"8%\"]</span>\r\n\r\n[/column][column type=\"one-half\" last=\"true\"]\r\n<img class=\"aligncenter wp-image-5003 size-full\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/Intel_Logo_Capture.png\" alt=\"\" width=\"371\" height=\"265\" />[/column][/content_band]\r\n\r\n[content_band bg_color=\"#f2f2f2\" inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"][gap size=\"10%\"]<img class=\"aligncenter wp-image-7071 \" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/11/lbg_nvidia1-1024x193.png\" alt=\"\" width=\"742\" height=\"140\" />[/column][column type=\"one-half\" last=\"true\"]\r\n\r\n[custom_headline type=\"left\" level=\"h2\"]NVIDIA[/custom_headline]\r\n\r\n<span style=\"line-height: 1.5;\"><a href=\"http://www.nvidia.com/object/cuda_home.html\">NVIDIA</a> makes CUDA-capable GPUs. It serves the high performance computing market with its Tesla™ GPUs.[gap size=\"8%\"]</span>\r\n\r\n[/column]\r\n\r\n[/content_band]\r\n\r\n[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"][gap size=\"22%\"]\r\n[custom_headline type=\"left\" level=\"h2\"]Xilinx[/custom_headline]\r\n\r\nThe SDAccel™ Development Environment is a member of the Xilinx SDx™ family that combines the industry’s first architecturally optimizing compiler supporting any combination of OpenCL™, C, and C++ kernels, along with libraries and development boards for the first complete CPU/GPU-like development and run-time experience for FPGAs.\r\n\r\nArrayFire is an SDAccel-certified Xilinx Alliance Member.\r\n\r\nTo access the capabilities of SDAccel contact your local <a href=\"http://www.xilinx.com/about/contact.html\" target=\"_blank\">Xilinx sales representative or Xilinx authorized distributor</a>. To learn more visit <a href=\"http://www.xilinx.com/sdaccel\" target=\"_blank\">www.xilinx.com/sdaccel</a>. [gap size=\"8%\"]\r\n\r\n[/column]\r\n<img class=\"aligncenter size-large wp-image-8245\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/05/xilinx_alliance-1024x332.png\" alt=\"xilinx_alliance\" width=\"742\" height=\"241\" />[/column][column type=\"one-half\" last=\"true\"]\r\n[/content_band]','Partner Program','','inherit','open','closed','','187-revision-v1','','','2016-01-05 14:00:12','2016-01-05 19:00:12','',187,'http://sandbox.arrayfire.com/187-revision-v1/',0,'revision','',0),(8809,17795,'2016-01-05 14:10:34','2016-01-05 19:10:34','[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"]\r\n\r\n[gap size=\"5%\"][custom_headline type=\"left\" level=\"h2\" class=\"mtn\"]Partner Program[/custom_headline]\r\n\r\nThe Partner Program is designed to promote the development and sale of products and services to maximize the productivity of scientists, analysts, and engineers working on technical computing problems that can leverage GPU technology. As our partner, you benefit from a tight working relationship with ArrayFire staff and our other partners, while your customers benefit from the integration of your products and solutions with ArrayFire.\r\n\r\nThe ArrayFire Partner Program is built upon the belief that the purpose of a viable partnership includes a market opportunity, a joint product or service which matches that opportunity, and a strategy to market, sell, and support the joint offering. Therefore, ArrayFire includes programs and activities centered around technical and go-to-market resources that allow the partnership to work hand in hand to develop the solution and properly communicate the solution value into the market while providing the highest level of customer satisfaction.[/column][column type=\"one-half\" last=\"true\"][gap size=\"5%\"]<img class=\"aligncenter  wp-image-5018\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/hq-vehicles-972x1024.png\" alt=\"hq vehicles\" width=\"450\" height=\"473\" />[/column][/content_band]\r\n\r\n[content_band bg_color=\"#f2f2f2\" inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"][gap size=\"22%\"]<img class=\"aligncenter size-large wp-image-8245\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/05/xilinx_alliance-1024x332.png\" alt=\"xilinx_alliance\" width=\"742\" height=\"241\" />[/column][column type=\"one-half\" last=\"true\"]\r\n\r\n[custom_headline type=\"left\" level=\"h2\"]Xilinx[/custom_headline]\r\n\r\nThe SDAccel™ Development Environment is a member of the Xilinx SDx™ family that combines the industry’s first architecturally optimizing compiler supporting any combination of OpenCL™, C, and C++ kernels, along with libraries and development boards for the first complete CPU/GPU-like development and run-time experience for FPGAs.\r\n\r\nArrayFire is an SDAccel-certified Xilinx Alliance Member.\r\n\r\nTo access the capabilities of SDAccel contact your local <a href=\"http://www.xilinx.com/about/contact.html\" target=\"_blank\">Xilinx sales representative or Xilinx authorized distributor</a>. To learn more visit <a href=\"http://www.xilinx.com/sdaccel\" target=\"_blank\">www.xilinx.com/sdaccel</a>. [gap size=\"8%\"]\r\n\r\n[/column]\r\n\r\n[/content_band][content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"]\r\n\r\n[custom_headline type=\"left\" level=\"h2\"]NVIDIA[/custom_headline]\r\n\r\n<span style=\"line-height: 1.5;\"><a href=\"http://www.nvidia.com/object/cuda_home.html\">NVIDIA</a> makes CUDA-capable GPUs. It serves the high performance computing market with its Tesla™ GPUs.[gap size=\"8%\"]</span>\r\n\r\n[/column][column type=\"one-half\" last=\"true\"][gap size=\"10%\"]\r\n\r\n<img class=\"aligncenter wp-image-7071 \" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/11/lbg_nvidia1-1024x193.png\" alt=\"\" width=\"742\" height=\"140\" />[/column]\r\n\r\n[/content_band]\r\n\r\n[content_band bg_color=\"#f2f2f2\" inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"][gap size=\"10%\"]<img class=\"aligncenter wp-image-4993 \" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/amd_logo_low_res.png\" alt=\"\" width=\"747\" height=\"178\" />[/column][column type=\"one-half\" last=\"true\"]\r\n\r\n[custom_headline type=\"left\" level=\"h2\"]AMD[/custom_headline]\r\n\r\n<span style=\"line-height: 1.5;\"><a href=\"http://developer.amd.com/\">AMD</a> makes OpenCL-capable devices. It serves the high performance computing market with its Opteron™ CPUs &amp; APUs as well as its Radeon™ FirePro™ GPUs.[gap size=\"8%\"]</span>\r\n\r\n[/column]\r\n\r\n[/content_band]\r\n\r\n[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"]\r\n\r\n[custom_headline type=\"left\" level=\"h2\"]Intel[/custom_headline]\r\n\r\n<span style=\"line-height: 1.5;\"><a href=\"http://www.intel.com/content/www/us/en/high-performance-computing/high-performance-xeon-phi-coprocessor-brief.html\">Intel</a> makes OpenCL-capable devices. It serves the high performance computing market with its Intel® Xeon™ CPUs (and integrated GPUs) and Intel® Xeon Phi™ coprocessor.[gap size=\"8%\"]</span>\r\n\r\n[/column][column type=\"one-half\" last=\"true\"]\r\n<img class=\"aligncenter wp-image-5003 size-full\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/Intel_Logo_Capture.png\" alt=\"\" width=\"371\" height=\"265\" />[/column][/content_band]','Partner Program','','inherit','open','closed','','187-revision-v1','','','2016-01-05 14:10:34','2016-01-05 19:10:34','',187,'http://sandbox.arrayfire.com/187-revision-v1/',0,'revision','',0),(8810,17795,'2016-01-05 14:18:20','2016-01-05 19:18:20','[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"]\r\n\r\n[gap size=\"5%\"][custom_headline type=\"left\" level=\"h2\" class=\"mtn\"]Partner Program[/custom_headline]\r\n\r\nThe Partner Program is designed to promote the development and sale of products and services to maximize the productivity of scientists, analysts, and engineers working on technical computing problems that can leverage GPU technology. As our partner, you benefit from a tight working relationship with ArrayFire staff and our other partners, while your customers benefit from the integration of your products and solutions with ArrayFire.\r\n\r\nThe ArrayFire Partner Program is built upon the belief that the purpose of a viable partnership includes a market opportunity, a joint product or service which matches that opportunity, and a strategy to market, sell, and support the joint offering. Therefore, ArrayFire includes programs and activities centered around technical and go-to-market resources that allow the partnership to work hand in hand to develop the solution and properly communicate the solution value into the market while providing the highest level of customer satisfaction.[/column][column type=\"one-half\" last=\"true\"][gap size=\"5%\"]<img class=\"aligncenter  wp-image-5018\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/hq-vehicles-972x1024.png\" alt=\"hq vehicles\" width=\"450\" height=\"473\" />[/column][/content_band]\r\n\r\n[content_band bg_color=\"#f2f2f2\" inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"][gap size=\"10%\"]<img class=\"aligncenter wp-image-4993 \" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/amd_logo_low_res.png\" alt=\"\" width=\"747\" height=\"178\" />[/column][column type=\"one-half\" last=\"true\"]\r\n\r\n[custom_headline type=\"left\" level=\"h2\"]AMD[/custom_headline]\r\n\r\n<span style=\"line-height: 1.5;\"><a href=\"http://developer.amd.com/\">AMD</a> makes OpenCL-capable devices. It serves the high performance computing market with its Opteron™ CPUs &amp; APUs as well as its Radeon™ FirePro™ GPUs.[gap size=\"8%\"]</span>\r\n\r\n[/column]\r\n\r\n[/content_band]\r\n\r\n[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"]\r\n\r\n[custom_headline type=\"left\" level=\"h2\"]Intel[/custom_headline]\r\n\r\n<span style=\"line-height: 1.5;\"><a href=\"http://www.intel.com/content/www/us/en/high-performance-computing/high-performance-xeon-phi-coprocessor-brief.html\">Intel</a> makes OpenCL-capable devices. It serves the high performance computing market with its Intel® Xeon™ CPUs (and integrated GPUs) and Intel® Xeon Phi™ coprocessor.[gap size=\"8%\"]</span>\r\n\r\n[/column][column type=\"one-half\" last=\"true\"]\r\n<img class=\"aligncenter wp-image-5003 size-full\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/01/Intel_Logo_Capture.png\" alt=\"\" width=\"371\" height=\"265\" />[/column][/content_band]\r\n\r\n[content_band bg_color=\"#f2f2f2\" inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"][gap size=\"10%\"]<img class=\"aligncenter wp-image-7071 \" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/11/lbg_nvidia1-1024x193.png\" alt=\"\" width=\"742\" height=\"140\" />[/column][column type=\"one-half\" last=\"true\"]\r\n\r\n[custom_headline type=\"left\" level=\"h2\"]NVIDIA[/custom_headline]\r\n\r\n<span style=\"line-height: 1.5;\"><a href=\"http://www.nvidia.com/object/cuda_home.html\">NVIDIA</a> makes CUDA-capable GPUs. It serves the high performance computing market with its Tesla™ GPUs.[gap size=\"8%\"]</span>\r\n\r\n[/column]\r\n\r\n[/content_band]\r\n\r\n[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"40px\" padding_bottom=\"40px\"][column type=\"one-half\"]\r\n\r\n[custom_headline type=\"left\" level=\"h2\"]Xilinx[/custom_headline]\r\n\r\nThe SDAccel™ Development Environment is a member of the Xilinx SDx™ family that combines the industry’s first architecturally optimizing compiler supporting any combination of OpenCL™, C, and C++ kernels, along with libraries and development boards for the first complete CPU/GPU-like development and run-time experience for FPGAs.\r\n\r\nArrayFire is an SDAccel-certified Xilinx Alliance Member.\r\n\r\nTo access the capabilities of SDAccel contact your local <a href=\"http://www.xilinx.com/about/contact.html\" target=\"_blank\">Xilinx sales representative or Xilinx authorized distributor</a>. To learn more visit <a href=\"http://www.xilinx.com/sdaccel\" target=\"_blank\">www.xilinx.com/sdaccel</a>. [gap size=\"8%\"]\r\n\r\n[/column][column type=\"one-half\" last=\"true\"][gap size=\"22%\"]\r\n<img class=\"aligncenter size-large wp-image-8245\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/05/xilinx_alliance-1024x332.png\" alt=\"xilinx_alliance\" width=\"742\" height=\"241\" />[/column]\r\n[/content_band]\r\n','Partner Program','','inherit','open','closed','','187-revision-v1','','','2016-01-05 14:18:20','2016-01-05 19:18:20','',187,'http://sandbox.arrayfire.com/187-revision-v1/',0,'revision','',0),(8811,1,'2016-01-25 21:07:24','2016-01-26 02:07:24','','Order &ndash; January 25, 2016 @ 09:07 PM','','wc-completed','open','closed','order_56a6d3a1e7ae6','order-jan-26-2016-0202-am','','','2016-01-25 21:07:25','2016-01-26 02:07:25','',0,'http://sandbox.arrayfire.com/?post_type=shop_order&#038;p=8811',0,'shop_order','',5),(8813,11,'2016-02-29 10:08:02','2016-02-29 15:08:02','[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"10px\" padding_bottom=\"40px\"]\r\n[custom_headline type=\"left\" level=\"h2\"]\r\nArrayFire Installers\r\n[/custom_headline]\r\n[custom_headline type=\"left\" level=\"h5\"]\r\nEach download contains both CUDA and OpenCL files.\r\n[/custom_headline]\r\n[gap size=\"4%\"]\r\n\r\n[column type=\"one-fourth\"][button  block=\"true\" onclick=\"&lt;!-- Google Code for ArrayFire Download (Windows) Conversion Page\r\nIn your html page, add the snippet and call\r\ngoog_report_conversion when someone clicks on the\r\nchosen link or button. --&gt;\r\n&lt;script type=\"text/javascript\"&gt;\r\n/* &lt;!&amp;#91;CDATA&amp;#91; */\r\ngoog_snippet_vars = function() {\r\nvar w = window;\r\nw.google_conversion_id = 1021026651;\r\nw.google_conversion_label = \"18VJCJjPql4Q28Lu5gM\";\r\nw.google_remarketing_only = false;\r\n}\r\n// DO NOT CHANGE THE CODE BELOW.\r\ngoog_report_conversion = function(url) {\r\ngoog_snippet_vars();\r\nwindow.google_conversion_format = \"3\";\r\nwindow.google_is_call = true;\r\nvar opt = new Object();\r\nopt.onload_callback = function() {\r\nif (typeof(url) != \'undefined\') {\r\nwindow.location = url;\r\n}\r\n}\r\nvar conv_handler = window&amp;#91;\'google_trackConversion\'&amp;#93;;\r\nif (typeof(conv_handler) == \'function\') {\r\nconv_handler(opt);\r\n}\r\n}\r\n/* &amp;#93;&amp;#93;&gt; */\r\n&lt;/script&gt;\r\n&lt;script type=\"text/javascript\"\r\nsrc=\"//www.googleadservices.com/pagead/conversion_async.js\"&gt;\r\n&lt;/script&gt;\" class=\"center-text\" type=\"flat\" shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/windows-installer\" size=\"regular\" ]Windows, v3.3.0\r\n(64-bit)[/button][/column] [column type=\"one-fourth\"][button block=\"true\" type=\"flat\"  shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/linux-x86_64-installer\" size=\"regular\" ]Linux, v3.3.0\r\n(64-bit)[/button][/column][column type=\"one-fourth\"][button  block=\"true\" type=\"flat\"  shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/osx-installer\" size=\"regular\" ]Mac OSX, v3.3.0\r\n(64-bit)[/button][/column] [column type=\"one-fourth\" last=\"true\"][button block=\"true\"  type=\"flat\"  shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/linux-armv7l-installer\" size=\"regular\" ]Tegra K1 v3.3.0\r\n(32-bit)[/button][/column][gap size=\"9%\"]\r\n\r\nCheck out our GitHub repository to <a href=\"https://github.com/arrayfire/arrayfire\">build from the source</a>.\r\n\r\nLooking for an older installer? <a href=\"http://sandbox.arrayfire.com/installer_archive\">Try here</a>.[/content_band]\r\n<p style=\"text-align: left;\">[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"10px\" padding_bottom=\"40px\" bg_color=\"#f1f1f1\"][column type=\"one-half\"][gap size=\"8%\"]<img class=\"aligncenter wp-image-5156\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/02/mobile_Exported1-e1395437261846.png\" alt=\"mobile_Exported\" width=\"233\" height=\"311\" />[/column][column type=\"one-half\" last=\"true\"]\r\n[custom_headline type=\"left\" level=\"h2\"]\r\nGreat. What now?\r\n[/custom_headline]</p>\r\n<p style=\"text-align: left;\">[gap size=\"5%\"]</p>\r\n<p style=\"text-align: left;\">Welcome to ArrayFire! You\'ve got an awesome library there—learn more about its features and functions on <a href=\"http://www.sandbox.arrayfire.com/docs/index.htm\">our documentation</a>.</p>\r\n<p style=\"text-align: left;\">In addition to our <a href=\"https://groups.google.com/forum/#!forum/arrayfire-users\">ArrayFire user group</a> and <a href=\"http://sandbox.arrayfire.com/blog/\">our blog</a>, we offer a plethora of <a href=\"http://sandbox.arrayfire.com/support/\">support options</a> to fit your needs.</p>\r\n<p style=\"text-align: left;\">Got a job that needs closer attention? Hire us! Our engineers are acceleration wizards. Check out our <a href=\"http://sandbox.arrayfire.com/consulting/\">consulting offerings</a>, or set up a free <a href=\"http://meetme.so/arrayfire\">technical consultation</a> with us today![/column]</p>\r\n<p style=\"text-align: left;\">[/content_band]</p>\r\n<p style=\"text-align: center;\"></p>','Download','','inherit','open','closed','','5931-revision-v1','','','2016-02-29 10:08:02','2016-02-29 15:08:02','',5931,'http://sandbox.arrayfire.com/5931-revision-v1/',0,'revision','',0),(8814,11,'2016-03-17 15:12:41','2016-03-17 19:12:41','[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"10px\" padding_bottom=\"40px\"]\r\n[custom_headline type=\"left\" level=\"h2\"]\r\nArrayFire Installers\r\n[/custom_headline]\r\n[custom_headline type=\"left\" level=\"h5\"]\r\nEach download contains both CUDA and OpenCL files.\r\n[/custom_headline]\r\n[gap size=\"4%\"]\r\n\r\n[column type=\"one-fourth\"][button  block=\"true\" onclick=\"&lt;!-- Google Code for ArrayFire Download (Windows) Conversion Page\r\nIn your html page, add the snippet and call\r\ngoog_report_conversion when someone clicks on the\r\nchosen link or button. --&gt;\r\n&lt;script type=\"text/javascript\"&gt;\r\n/* &lt;!&amp;#91;CDATA&amp;#91; */\r\ngoog_snippet_vars = function() {\r\nvar w = window;\r\nw.google_conversion_id = 1021026651;\r\nw.google_conversion_label = \"18VJCJjPql4Q28Lu5gM\";\r\nw.google_remarketing_only = false;\r\n}\r\n// DO NOT CHANGE THE CODE BELOW.\r\ngoog_report_conversion = function(url) {\r\ngoog_snippet_vars();\r\nwindow.google_conversion_format = \"3\";\r\nwindow.google_is_call = true;\r\nvar opt = new Object();\r\nopt.onload_callback = function() {\r\nif (typeof(url) != \'undefined\') {\r\nwindow.location = url;\r\n}\r\n}\r\nvar conv_handler = window&amp;#91;\'google_trackConversion\'&amp;#93;;\r\nif (typeof(conv_handler) == \'function\') {\r\nconv_handler(opt);\r\n}\r\n}\r\n/* &amp;#93;&amp;#93;&gt; */\r\n&lt;/script&gt;\r\n&lt;script type=\"text/javascript\"\r\nsrc=\"//www.googleadservices.com/pagead/conversion_async.js\"&gt;\r\n&lt;/script&gt;\" class=\"center-text\" type=\"flat\" shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/windows-installer\" size=\"regular\" ]Windows, v3.3.1\r\n(64-bit)[/button][/column] [column type=\"one-fourth\"][button block=\"true\" type=\"flat\"  shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/linux-x86_64-installer\" size=\"regular\" ]Linux, v3.3.1\r\n(64-bit)[/button][/column][column type=\"one-fourth\"][button  block=\"true\" type=\"flat\"  shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/osx-installer\" size=\"regular\" ]Mac OSX, v3.3.1\r\n(64-bit)[/button][/column] [column type=\"one-fourth\" last=\"true\"][button block=\"true\"  type=\"flat\"  shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/linux-armv7l-installer\" size=\"regular\" ]Tegra K1 v3.3.1\r\n(32-bit)[/button][/column][gap size=\"9%\"]\r\n\r\nCheck out our GitHub repository to <a href=\"https://github.com/arrayfire/arrayfire\">build from the source</a>.\r\n\r\nLooking for an older installer? <a href=\"http://sandbox.arrayfire.com/installer_archive\">Try here</a>.[/content_band]\r\n<p style=\"text-align: left;\">[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"10px\" padding_bottom=\"40px\" bg_color=\"#f1f1f1\"][column type=\"one-half\"][gap size=\"8%\"]<img class=\"aligncenter wp-image-5156\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/02/mobile_Exported1-e1395437261846.png\" alt=\"mobile_Exported\" width=\"233\" height=\"311\" />[/column][column type=\"one-half\" last=\"true\"]\r\n[custom_headline type=\"left\" level=\"h2\"]\r\nGreat. What now?\r\n[/custom_headline]</p>\r\n<p style=\"text-align: left;\">[gap size=\"5%\"]</p>\r\n<p style=\"text-align: left;\">Welcome to ArrayFire! You\'ve got an awesome library there—learn more about its features and functions on <a href=\"http://www.sandbox.arrayfire.com/docs/index.htm\">our documentation</a>.</p>\r\n<p style=\"text-align: left;\">In addition to our <a href=\"https://groups.google.com/forum/#!forum/arrayfire-users\">ArrayFire user group</a> and <a href=\"http://sandbox.arrayfire.com/blog/\">our blog</a>, we offer a plethora of <a href=\"http://sandbox.arrayfire.com/support/\">support options</a> to fit your needs.</p>\r\n<p style=\"text-align: left;\">Got a job that needs closer attention? Hire us! Our engineers are acceleration wizards. Check out our <a href=\"http://sandbox.arrayfire.com/consulting/\">consulting offerings</a>, or set up a free <a href=\"http://meetme.so/arrayfire\">technical consultation</a> with us today![/column]</p>\r\n<p style=\"text-align: left;\">[/content_band]</p>\r\n<p style=\"text-align: center;\"></p>','Download','','inherit','open','closed','','5931-revision-v1','','','2016-03-17 15:12:41','2016-03-17 19:12:41','',5931,'http://sandbox.arrayfire.com/5931-revision-v1/',0,'revision','',0),(8816,11,'2016-03-25 15:03:25','2016-03-25 19:03:25','A lot of ArrayFire users have been interested in the usage of ArrayFire in partnership with OpenGL for graphics computation. In the long run, we do plan to expand further on the interoperablilty and make it easier through ArrayFire. For now, we have developed a small example to expand on the usage of the CUDA-OpenGL interop API to assist in the interop operations between ArrayFire and OpenGL.\r\n\r\nSome of the advantage of direct ArrayFire-OpenGL interop are:\r\n<ul>\r\n	<li><strong>Faster data transfers</strong>: Since the OpenGL buffers as well as ArrayFire data reside on the GPU, we can use a direct device to device copy rather than using the CPU as an intermediate and the relatively slow PCIe interface.</li>\r\n	<li><strong>Offscreen rendering</strong>: It is commonly known that rendering to screen is a slow process. Using the API shown in this example, we can render directly of off screen framebuffers and retrieve the data in ArrayFire.</li>\r\n	<li><strong>Transform feedback</strong>: This example also shows the usage of Transform feedback buffers in OpenGL. Transform feedback buffers allow the user to retrieve data from in-between the rendering pipeline, for example getting back the transformed vertices after the operations in vertex shaders.</li>\r\n</ul>\r\nSince a lot of data transfers to CPU are eliminated, we can do a lot more processing faster.\r\n\r\nLet us now discuss the example. This example is relatively simple and renders a single triangle.\r\n<h2>Code Walkthrough</h2>\r\nThe code for this example can be found at our <a href=\"https://github.com/arrayfire/ArrayFire-OpenGL-Interop\">github page</a>.\r\n\r\nThe code relies upon the following libraries:\r\n<ul>\r\n	<li>ArrayFire 2.0</li>\r\n	<li>CUDA-OpenGL Interop (CUDA 5.5)</li>\r\n	<li>GLFW 3</li>\r\n	<li>GLEW (1.x, latest version recommended)</li>\r\n</ul>\r\nLet us walk through the example step by step. Please note that any steps that do not contribute to the interop and are just common OpenGL code will not be covered in this blog.\r\n<h3>Initialization</h3>\r\n<pre>int device = argc &gt; 1? atoi(argv[1]):0;\r\naf::deviceset(device);\r\naf::info();\r\n\r\nint width = 400, height = 300, channels = 4;\r\nint num_triangles = 1, num_vertices = 3;\r\n\r\narray af_indices = array(3, indices);\r\narray af_vertices = array(3, num_vertices, vertices);	//3 floats per vertex, 3 vertices\r\narray af_colors = array(3, num_vertices, colors);		//3 floats per color, 3 colors\r\narray af_image = constant(0.0, height, width, channels);\r\narray pkd_image = constant(0.0, channels, width, height);\r\narray af_project = constant(-1.0, 3, num_vertices);</pre>\r\nThis section initializes ArrayFire and create arrays for the basic data structure. Since ArrayFire stores data as column major, we decided that the arrays will have each vertex as one column, ie. if you had an array of 10 vertices with 3 coordinates each, then your array would have dimensions 3x10.\r\n\r\nMost of the array names are self explanatory. <em>pkd_image</em> is used to store the packed image data returned by OpenGL through the framebuffer. <em>af_image</em> is used to store the returned image in the ArrayFire format (unpacked). <em>af_project</em> stores the result of the projection returned after the vertex shader stage (using transform feedback). The size of project is same as the vertex buffer.\r\n<pre>bool onscreen = true;			//Change to false for offscreen renderering\r\ninit_glfw(width, height, channels, onscreen);</pre>\r\nThe <strong>onscreen</strong> flag is a useful one. When it is set to true, the render happens on the GLFW window. Although not a part of the code, it is possible to retrieve the rendered image back into ArrayFire. However, turning this flag to false results in offscreen rendering. This means rendering is done directly to a software framebuffer rather than to the screen, hence it is faster. It also allows the rendered image to be retrieved back into ArrayFire. If you wish to display this image then the ArrayFire image() function can be used (will be discussed a little later).\r\n\r\ninit_glfw is used to initialize the GLFW and GLEW context.\r\n<h3>Initialize Buffers</h3>\r\n<pre>GLuint vertex_b = 0;\r\ncudaGraphicsResource_t vertex_cuda;\r\ncreate_buffer(vertex_b, GL_ARRAY_BUFFER, &amp;vertex_cuda, 3 * num_vertices * sizeof(float), GL_DYNAMIC_DRAW);</pre>\r\nThese lines are an abstraction to create the OpenGL buffers and bind them to their respective CUDA Graphics Resource object.\r\n<pre>void create_buffer(GLuint&amp; buffer, GLenum buffer_target, cudaGraphicsResource_t* cuda_resource, const unsigned size, GLenum buffer_usage, const void* data = NULL)\r\n{\r\n    glGenBuffers(1, &amp;buffer);\r\n    glBindBuffer(buffer_target, buffer);\r\n    glBufferData(buffer_target, size, data, buffer_usage);\r\n    CUDA(cudaGraphicsGLRegisterBuffer(cuda_resource, buffer, cudaGraphicsRegisterFlagsNone));\r\n    glBindBuffer(buffer_target, 0);\r\n}</pre>\r\nThis section of code shows the creation and registering of the OpenGL buffer with CUDA. The buffer generation and bindings are done exactly as in regular OpenGL. The <em>cudaGraphicsGLRegisterBuffer</em> registers the buffer with CUDA. If using a texture or renderbuffer or the like, then use <em>cudaGraphicsGLRegisterImage</em>.\r\n<pre>// Render Buffer\r\nGLuint render_b = 0;\r\ncudaGraphicsResource_t render_cuda;\r\ncreate_buffer(render_b, GL_RGBA32F, width, height, &amp;render_cuda);\r\n\r\n// Depth Buffer - for off screen rendering\r\nGLuint depth_b = 0;\r\ncreate_buffer(depth_b, GL_DEPTH_COMPONENT, width, height);</pre>\r\nIn the code above, the framebuffer and depthbuffer are initialized which can now be used for off screen rendering.\r\n<h3>Framebuffer, Transform Feedback and Shader Loading</h3>\r\n<pre>//Required for framebuffer copy\r\nGLuint frame_b = 0;\r\nbind_framebuffer(render_b, depth_b, frame_b);\r\n\r\n// Initialize shaders\r\ninit_program(\"shader.vert\", \"shader.frag\");\r\n\r\n// Initialize transform feedback\r\ninit_projection(transform_b, project_b);</pre>\r\nThis section of the code is used to initialize depth and framebuffers for off screen rendering.  It also loads and compiles the shaders and initializes the transform feedback buffers.\r\n<h3>Render Loop</h3>\r\n<pre>while(!glfwWindowShouldClose(window))</pre>\r\nGLFW allows the user to control to render loop. So we use a simple while loop with a GLFW terminating condition.\r\n<h3>Copy Data to OpenGL Buffers</h3>\r\n<pre>float* d_vertices = af_vertices.device&lt;float&gt;();\r\ncopy_from_device_pointer(vertex_cuda,\r\n			 d_vertices,\r\n			 GL_ARRAY_BUFFER,\r\n			 3 * num_vertices * sizeof(float));</pre>\r\nIn the render loop, we first copy the vertex and color data to their respective OpenGL buffers. In the copy_from_device_pointer function, we have:\r\n<pre>template&lt;typename T&gt;\r\nvoid copy_from_device_pointer(cudaGraphicsResource_t cuda_resource,\r\n                              T&amp; d_ptr,\r\n                              GLuint buffer_target,\r\n                              const unsigned size)\r\n{\r\n    CUDA(cudaGraphicsMapResources(1, &amp;cuda_resource));\r\n    bool is_mapped = true;\r\n    if (buffer_target == GL_RENDERBUFFER) {\r\n        cudaArray* array_ptr = NULL;\r\n        CUDA(cudaGraphicsSubResourceGetMappedArray(&amp;array_ptr, cuda_resource, 0, 0));\r\n        CUDA(cudaMemcpyToArray(array_ptr, 0, 0, d_ptr, size, cudaMemcpyDeviceToDevice));\r\n    } else {\r\n        T* opengl_ptr = NULL;\r\n        CUDA(cudaGraphicsResourceGetMappedPointer((void**)&amp;opengl_ptr, (size_t*)&amp;size, cuda_resource));\r\n        CUDA(cudaMemcpy(opengl_ptr, d_ptr, size, cudaMemcpyDeviceToDevice));\r\n    }\r\n    unmap_resource(cuda_resource, is_mapped);\r\n}</pre>\r\nIn this function, we first \"map\" the cuda resource of the buffer using the <a title=\"cudaGraphicsMapResources\" href=\"http://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__INTEROP.html#group__CUDART__INTEROP_1gb7064fb72e54d89d0666e192b45d35cc\" target=\"_blank\">cudaGraphicsMapResources</a> function, ie. enable the buffer for access by CUDA. This allows CUDA to copy memory to and from the buffer. Once completed, we must unmap the resources.\r\n<h3>Other Memory Copying Notes</h3>\r\nIf using a renderbuffer or texture, the memory needs to be copied using CUDA textures of cudaArrays and then using the cudaMemcpy(To/From)Array function. If using other buffers like GL_ARRAY_BUFFER, we can simply get the pointer using the <a title=\"cudaGraphicsResourceGetMappedPointer\" href=\"http://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__INTEROP.html#group__CUDART__INTEROP_1ge7f893864a3d38a630e71a99f5a4e17f\" target=\"_blank\">cudaGraphicsResourceGetMappedPointer</a> function and then copy it using the cudaMemcpyDeviceToDevice flag.\r\n\r\nCopying from OpenGL buffers to CUDA is also done in the same way. See the copy_to_device_pointer() function in the code.\r\n\r\nIn the code that follows the memory copies, we call the render function which renders the data to screen or framebuffer. It uses relatively well know OpenGL calls and hence I will not be covering it in the blog. Any questions can be asked on the <a title=\"ArrayFire Forums\" href=\"http://forums.accelereyes.com/forums/viewforum.php?f=17\" target=\"_blank\">ArrayFire forums</a>. Once the rendering is complete, we copy the transform feedback memory and the framebuffer memory back to ArrayFire.\r\n\r\n<span style=\"line-height: 1.5em;\">On exit, delete the buffers and exit.</span>\r\n<h2>Compile and Run</h2>\r\n<h3>Linux</h3>\r\nOn Linux, the Makefile is provided. In the Makefile, please update the paths to ArrayFire (AF_PATH), CUDA and GLFW (GLFW_LIB_PATH).\r\n\r\nAs is, the makefile assumes that CUDA, GLFW and GLEW is installed in the default locations.\r\n\r\nTo compile and run:\r\n<pre>$make\r\n$./cugl_interop</pre>\r\n<h3>Windows</h3>\r\nOn Windows, you can create a CUDA project in Visual Studio. Then add the locations of the include and library directories of ArrayFire, GLFW and GLEW in the project properties. The code is OS-independent and should run without any modifications.\r\n<h2>Output</h2>\r\nThe output, in case of onscreen rendering should be a rotating triangle. A sample screenshot is shown below.\r\n\r\n<a href=\"http://blog.accelereyes.com/blog/wp-content/uploads/2014/01/ArrayFire-CUDA-OpenGL-Interop.png\"><img class=\"size-medium wp-image-4675 aligncenter\" alt=\"ArrayFire CUDA OpenGL Interop\" src=\"http://blog.accelereyes.com/blog/wp-content/uploads/2014/01/ArrayFire-CUDA-OpenGL-Interop-279x300.png\" width=\"279\" height=\"300\" /></a>\r\n\r\nHere are some useful resources to look up:\r\n<ul>\r\n	<li><a href=\"http://3dgep.com/?p=2082\">OpenGL Interoperability with CUDA by Jeremiah van Oosten</a></li>\r\n	<li><a href=\"http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#graphics-interoperability\">CUDA Graphics Interoperability (Programming Guide)</a></li>\r\n	<li><a href=\"http://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__INTEROP.html#group__CUDART__INTEROP\">CUDA Runtime Graphics Interop API</a></li>\r\n	<li><a href=\"http://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__OPENGL.html#group__CUDART__OPENGL\">CUDA Runtime OpenGL Interop API</a></li>\r\n</ul>\r\nPlease feel free to ask any questions about this interop example on the <a title=\"ArrayFire Forums\" href=\"http://forums.accelereyes.com/forums/viewforum.php?f=17\" target=\"_blank\">ArrayFire forums</a>. We are working on a larger, more extensible interop code that we will release upon request.\r\n\r\n<span style=\"line-height: 1.5em;\"><strong>Known issues:</strong> The ArrayFire graphics API is known to not work as intended when using external OpenGL context. It is advised that visualizations be limited. If they still do not work, the <em>saveimage</em> function can be a fallback, albeit a last resort fallback.</span>\r\n\r\n<strong>Github Link</strong>: <a href=\"https://github.com/arrayfire/ArrayFire-OpenGL-Interop\">https://github.com/arrayfire/ArrayFire-OpenGL-Interop</a>','ArrayFire-OpenGL Interop using CUDA','','inherit','open','closed','','4649-autosave-v1','','','2016-03-25 15:03:25','2016-03-25 19:03:25','',4649,'http://sandbox.arrayfire.com/4649-autosave-v1/',0,'revision','',0),(8817,11,'2016-03-25 15:03:41','2016-03-25 19:03:41','A lot of ArrayFire users have been interested in the usage of ArrayFire in partnership with OpenGL for graphics computation. In the long run, we do plan to expand further on the interoperablilty and make it easier through ArrayFire. For now, we have developed a small example to expand on the usage of the CUDA-OpenGL interop API to assist in the interop operations between ArrayFire and OpenGL.\r\n\r\nSome of the advantage of direct ArrayFire-OpenGL interop are:\r\n<ul>\r\n	<li><strong>Faster data transfers</strong>: Since the OpenGL buffers as well as ArrayFire data reside on the GPU, we can use a direct device to device copy rather than using the CPU as an intermediate and the relatively slow PCIe interface.</li>\r\n	<li><strong>Offscreen rendering</strong>: It is commonly known that rendering to screen is a slow process. Using the API shown in this example, we can render directly of off screen framebuffers and retrieve the data in ArrayFire.</li>\r\n	<li><strong>Transform feedback</strong>: This example also shows the usage of Transform feedback buffers in OpenGL. Transform feedback buffers allow the user to retrieve data from in-between the rendering pipeline, for example getting back the transformed vertices after the operations in vertex shaders.</li>\r\n</ul>\r\nSince a lot of data transfers to CPU are eliminated, we can do a lot more processing faster.\r\n\r\nLet us now discuss the example. This example is relatively simple and renders a single triangle.\r\n<h2>Code Walkthrough</h2>\r\nThe code for this example can be found at our <a href=\"https://github.com/arrayfire/ArrayFire-OpenGL-Interop\">github page</a>.\r\n\r\nThe code relies upon the following libraries:\r\n<ul>\r\n	<li>ArrayFire 2.0</li>\r\n	<li>CUDA-OpenGL Interop (CUDA 5.5)</li>\r\n	<li>GLFW 3</li>\r\n	<li>GLEW (1.x, latest version recommended)</li>\r\n</ul>\r\nLet us walk through the example step by step. Please note that any steps that do not contribute to the interop and are just common OpenGL code will not be covered in this blog.\r\n<h3>Initialization</h3>\r\n<pre>int device = argc &gt; 1? atoi(argv[1]):0;\r\naf::deviceset(device);\r\naf::info();\r\n\r\nint width = 400, height = 300, channels = 4;\r\nint num_triangles = 1, num_vertices = 3;\r\n\r\narray af_indices = array(3, indices);\r\narray af_vertices = array(3, num_vertices, vertices);	//3 floats per vertex, 3 vertices\r\narray af_colors = array(3, num_vertices, colors);		//3 floats per color, 3 colors\r\narray af_image = constant(0.0, height, width, channels);\r\narray pkd_image = constant(0.0, channels, width, height);\r\narray af_project = constant(-1.0, 3, num_vertices);</pre>\r\nThis section initializes ArrayFire and create arrays for the basic data structure. Since ArrayFire stores data as column major, we decided that the arrays will have each vertex as one column, ie. if you had an array of 10 vertices with 3 coordinates each, then your array would have dimensions 3x10.\r\n\r\nMost of the array names are self explanatory. <em>pkd_image</em> is used to store the packed image data returned by OpenGL through the framebuffer. <em>af_image</em> is used to store the returned image in the ArrayFire format (unpacked). <em>af_project</em> stores the result of the projection returned after the vertex shader stage (using transform feedback). The size of project is same as the vertex buffer.\r\n<pre>bool onscreen = true;			//Change to false for offscreen renderering\r\ninit_glfw(width, height, channels, onscreen);</pre>\r\nThe <strong>onscreen</strong> flag is a useful one. When it is set to true, the render happens on the GLFW window. Although not a part of the code, it is possible to retrieve the rendered image back into ArrayFire. However, turning this flag to false results in offscreen rendering. This means rendering is done directly to a software framebuffer rather than to the screen, hence it is faster. It also allows the rendered image to be retrieved back into ArrayFire. If you wish to display this image then the ArrayFire image() function can be used (will be discussed a little later).\r\n\r\ninit_glfw is used to initialize the GLFW and GLEW context.\r\n<h3>Initialize Buffers</h3>\r\n<pre>GLuint vertex_b = 0;\r\ncudaGraphicsResource_t vertex_cuda;\r\ncreate_buffer(vertex_b, GL_ARRAY_BUFFER, &amp;vertex_cuda, 3 * num_vertices * sizeof(float), GL_DYNAMIC_DRAW);</pre>\r\nThese lines are an abstraction to create the OpenGL buffers and bind them to their respective CUDA Graphics Resource object.\r\n<pre>void create_buffer(GLuint&amp; buffer, GLenum buffer_target, cudaGraphicsResource_t* cuda_resource, const unsigned size, GLenum buffer_usage, const void* data = NULL)\r\n{\r\n    glGenBuffers(1, &amp;buffer);\r\n    glBindBuffer(buffer_target, buffer);\r\n    glBufferData(buffer_target, size, data, buffer_usage);\r\n    CUDA(cudaGraphicsGLRegisterBuffer(cuda_resource, buffer, cudaGraphicsRegisterFlagsNone));\r\n    glBindBuffer(buffer_target, 0);\r\n}</pre>\r\nThis section of code shows the creation and registering of the OpenGL buffer with CUDA. The buffer generation and bindings are done exactly as in regular OpenGL. The <em>cudaGraphicsGLRegisterBuffer</em> registers the buffer with CUDA. If using a texture or renderbuffer or the like, then use <em>cudaGraphicsGLRegisterImage</em>.\r\n<pre>// Render Buffer\r\nGLuint render_b = 0;\r\ncudaGraphicsResource_t render_cuda;\r\ncreate_buffer(render_b, GL_RGBA32F, width, height, &amp;render_cuda);\r\n\r\n// Depth Buffer - for off screen rendering\r\nGLuint depth_b = 0;\r\ncreate_buffer(depth_b, GL_DEPTH_COMPONENT, width, height);</pre>\r\nIn the code above, the framebuffer and depthbuffer are initialized which can now be used for off screen rendering.\r\n<h3>Framebuffer, Transform Feedback and Shader Loading</h3>\r\n<pre>//Required for framebuffer copy\r\nGLuint frame_b = 0;\r\nbind_framebuffer(render_b, depth_b, frame_b);\r\n\r\n// Initialize shaders\r\ninit_program(\"shader.vert\", \"shader.frag\");\r\n\r\n// Initialize transform feedback\r\ninit_projection(transform_b, project_b);</pre>\r\nThis section of the code is used to initialize depth and framebuffers for off screen rendering.  It also loads and compiles the shaders and initializes the transform feedback buffers.\r\n<h3>Render Loop</h3>\r\n<pre>while(!glfwWindowShouldClose(window))</pre>\r\nGLFW allows the user to control to render loop. So we use a simple while loop with a GLFW terminating condition.\r\n<h3>Copy Data to OpenGL Buffers</h3>\r\n<pre>float* d_vertices = af_vertices.device&lt;float&gt;();\r\ncopy_from_device_pointer(vertex_cuda,\r\n			 d_vertices,\r\n			 GL_ARRAY_BUFFER,\r\n			 3 * num_vertices * sizeof(float));</pre>\r\nIn the render loop, we first copy the vertex and color data to their respective OpenGL buffers. In the copy_from_device_pointer function, we have:\r\n<pre>template&lt;typename T&gt;\r\nvoid copy_from_device_pointer(cudaGraphicsResource_t cuda_resource,\r\n                              T&amp; d_ptr,\r\n                              GLuint buffer_target,\r\n                              const unsigned size)\r\n{\r\n    CUDA(cudaGraphicsMapResources(1, &amp;cuda_resource));\r\n    bool is_mapped = true;\r\n    if (buffer_target == GL_RENDERBUFFER) {\r\n        cudaArray* array_ptr = NULL;\r\n        CUDA(cudaGraphicsSubResourceGetMappedArray(&amp;array_ptr, cuda_resource, 0, 0));\r\n        CUDA(cudaMemcpyToArray(array_ptr, 0, 0, d_ptr, size, cudaMemcpyDeviceToDevice));\r\n    } else {\r\n        T* opengl_ptr = NULL;\r\n        CUDA(cudaGraphicsResourceGetMappedPointer((void**)&amp;opengl_ptr, (size_t*)&amp;size, cuda_resource));\r\n        CUDA(cudaMemcpy(opengl_ptr, d_ptr, size, cudaMemcpyDeviceToDevice));\r\n    }\r\n    unmap_resource(cuda_resource, is_mapped);\r\n}</pre>\r\nIn this function, we first \"map\" the cuda resource of the buffer using the <a title=\"cudaGraphicsMapResources\" href=\"http://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__INTEROP.html#group__CUDART__INTEROP_1gb7064fb72e54d89d0666e192b45d35cc\" target=\"_blank\">cudaGraphicsMapResources</a> function, ie. enable the buffer for access by CUDA. This allows CUDA to copy memory to and from the buffer. Once completed, we must unmap the resources.\r\n<h3>Other Memory Copying Notes</h3>\r\nIf using a renderbuffer or texture, the memory needs to be copied using CUDA textures of cudaArrays and then using the cudaMemcpy(To/From)Array function. If using other buffers like GL_ARRAY_BUFFER, we can simply get the pointer using the <a title=\"cudaGraphicsResourceGetMappedPointer\" href=\"http://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__INTEROP.html#group__CUDART__INTEROP_1ge7f893864a3d38a630e71a99f5a4e17f\" target=\"_blank\">cudaGraphicsResourceGetMappedPointer</a> function and then copy it using the cudaMemcpyDeviceToDevice flag.\r\n\r\nCopying from OpenGL buffers to CUDA is also done in the same way. See the copy_to_device_pointer() function in the code.\r\n\r\nIn the code that follows the memory copies, we call the render function which renders the data to screen or framebuffer. It uses relatively well know OpenGL calls and hence I will not be covering it in the blog. Any questions can be asked on the <a title=\"ArrayFire Forums\" href=\"http://forums.accelereyes.com/forums/viewforum.php?f=17\" target=\"_blank\">ArrayFire forums</a>. Once the rendering is complete, we copy the transform feedback memory and the framebuffer memory back to ArrayFire.\r\n\r\n<span style=\"line-height: 1.5em;\">On exit, delete the buffers and exit.</span>\r\n<h2>Compile and Run</h2>\r\n<h3>Linux</h3>\r\nOn Linux, the Makefile is provided. In the Makefile, please update the paths to ArrayFire (AF_PATH), CUDA and GLFW (GLFW_LIB_PATH).\r\n\r\nAs is, the makefile assumes that CUDA, GLFW and GLEW is installed in the default locations.\r\n\r\nTo compile and run:\r\n<pre>$make\r\n$./cugl_interop</pre>\r\n<h3>Windows</h3>\r\nOn Windows, you can create a CUDA project in Visual Studio. Then add the locations of the include and library directories of ArrayFire, GLFW and GLEW in the project properties. The code is OS-independent and should run without any modifications.\r\n<h2>Output</h2>\r\nThe output, in case of onscreen rendering should be a rotating triangle. A sample screenshot is shown below.\r\n\r\n<a href=\"http://blog.accelereyes.com/blog/wp-content/uploads/2014/01/ArrayFire-CUDA-OpenGL-Interop.png\"><img class=\"size-medium wp-image-4675 aligncenter\" alt=\"ArrayFire CUDA OpenGL Interop\" src=\"http://blog.accelereyes.com/blog/wp-content/uploads/2014/01/ArrayFire-CUDA-OpenGL-Interop-279x300.png\" width=\"279\" height=\"300\" /></a>\r\n\r\nHere are some useful resources to look up:\r\n<ul>\r\n	<li><a href=\"http://3dgep.com/?p=2082\">OpenGL Interoperability with CUDA by Jeremiah van Oosten</a></li>\r\n	<li><a href=\"http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#graphics-interoperability\">CUDA Graphics Interoperability (Programming Guide)</a></li>\r\n	<li><a href=\"http://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__INTEROP.html#group__CUDART__INTEROP\">CUDA Runtime Graphics Interop API</a></li>\r\n	<li><a href=\"http://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__OPENGL.html#group__CUDART__OPENGL\">CUDA Runtime OpenGL Interop API</a></li>\r\n</ul>\r\nPlease feel free to ask any questions about this interop example on the <a title=\"ArrayFire Forums\" href=\"http://forums.accelereyes.com/forums/viewforum.php?f=17\" target=\"_blank\">ArrayFire forums</a>. We are working on a larger, more extensible interop code that we will release upon request.\r\n\r\n<span style=\"line-height: 1.5em;\"><strong>Known issues:</strong> The ArrayFire graphics API is known to not work as intended when using external OpenGL context. It is advised that visualizations be limited. If they still do not work, the <em>saveimage</em> function can be a fallback, albeit a last resort fallback.</span>\r\n\r\n<strong>Github Link</strong>: <a href=\"https://github.com/arrayfire/ArrayFire-OpenGL-Interop\">https://github.com/arrayfire/ArrayFire-OpenGL-Interop</a>','ArrayFire-OpenGL Interop using CUDA','','inherit','open','closed','','4649-revision-v1','','','2016-03-25 15:03:41','2016-03-25 19:03:41','',4649,'http://sandbox.arrayfire.com/4649-revision-v1/',0,'revision','',0),(8820,6,'2016-03-31 17:34:21','2016-03-31 21:34:21','<img class=\"aligncenter size-full wp-image-8002\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2015/03/GTC-15-Header.png\" alt=\"GTC 15 Header\" width=\"974\" height=\"330\" />\r\n\r\nGTC is quickly approaching and we want to see you there!\r\n\r\n<strong>When: March 17-20</strong>\r\n<strong>Where: San Jose, California</strong>\r\n<strong>ArrayFire Booth: 713</strong>\r\n\r\nGTC is the world\'s premier GPU developer conference. Connect with experts from NVIDIA and other leaders in high performance computing. At GTC you\'ll discover what\'s next in GPU breakthroughs, and gain useful insights in over 500 sessions and hands-on labs covering a diverse range of application domains.\r\n\r\nArrayFire will be out in full force at GTC, and we invite you to join us at our CUDA tutorials, hands-on lab, and talks presented by our knowledgeable and experienced GPU developers. Visit the <a href=\"https://registration.gputechconf.com/form/session-listing\">GTC Session Catalog</a> for more details—you don\'t want to miss out!\r\n<h3>ArrayFire Tutorials at GTC</h3>\r\n<h5>S5797 - Introduction to GPU Computing Using the ArrayFire Acceleration Library</h5>\r\n<h6>Presented by Umar Arshad - Tuesday March 17 at 1:00 PM</h6>\r\nNew to GPU computing and don\'t know where to start? Are you an expert in GPU computing and tired of writing your kernels from scratch? If that is the case, this tutorial is perfect for you! In this tutorial we will introduce you to a simple and intuitive API that will make GPU computing highly productive and stress free. Last November, the ArrayFire library was open-source and made available to the general public. In this talk we will walk you through the installation process, introduce the ArrayFire API, and show several applications that have been developed using the API.\r\n<h5>S5796 - Image Learning and Computer Vision in CUDA</h5>\r\n<h6>Presented by Peter Andreas Entschev - Tuesday March 17 at 3:00 PM</h6>\r\nAnalyzing a massive data set? Need fast results? Need computer vision algorithms? Not sure when and where to start? The answer is here and now! In this tutorial we will give you the tools to bring your favorite computer vision algorithm to life. In this tutorial we will go over key challenges for implementing computer vision and machine learning algorithms on the GPU. We will walk you through several computer vision algorithms for the GPU (ORB, Fast, SIFT) and give you the hands experience to implement you own algorithms.\r\n<h5>S5803 - Simplified Machine Learning Programming for CUDA</h5>\r\n<h6>Presented by Umar Arshad - Wednesday March 18 at 9:30 AM</h6>\r\nLooking for a simplified way to program machine learning algorithms? This tutorial will give you hands on experience implementing Deep Belief Networks using ArrayFire and other CUDA tools. Learn the best practices for implementing parallel versions of popular algorithms on GPUs. Instead of reinventing the wheel, you will learn where to find and how to use excellent versions of these algorithms already available in CUDA and ArrayFire libraries. You will walk away equipped with the best tools and knowledge for implementing accelerated machine learning algorithms.\r\n<h5>S5804 - Application Development for Mobile Devices: A Case Study for the Tegra K1</h5>\r\n<h6>Presented by Oded Green - Wednesday March 18 at 2:00 PM</h6>\r\nEmbedded systems are ubiquitous in today\'s world. The Tegra K1 is a front-runner for low-power efficient high performance embedded systems. In this tutorial we will share with you our experience in developing applications for the Tegra K1. We will show how the ArrayFire library and its simple API can be used to deploy stable applications for the Tegra K1 in a quick manner. Specifically, we will cover the zero-copy capabilities of CUDA and show how ArrayFire leverages that capability to efficiently run a very large number of algorithms in real-time. Using ArrayFire\'s graphic package it is easy to create stunning visuals using Tegra\'s OpenGL 4.4 capability, this too will be discussed in today\'s tutorial.\r\n<h3>ArrayFire Hands-on Lab at GTC</h3>\r\n<h5>S5722 - Hands-on Lab: Deep Belief Networks Using ArrayFire</h5>\r\n<h6>Presented by Umar Arshad - Wednesday March 18 at 3:30 PM</h6>\r\nWorking on image processing, computer vision, or machine learning? This tutorial will give you hands on experience implementing Deep Belief Networks using ArrayFire and other CUDA tools. Deep Belief Networks are a specialized neural network that can be efficiently optimized on the GPU. Learn the best practices for implementing parallel versions of popular algorithms on GPUs. Instead of reinventing the wheel, you will learn where to find and how to use excellent versions of these algorithms already available in CUDA and ArrayFire libraries. You will walk away equipped with the best tools and knowledge for implementing accelerated image processing and machine learning. As we\'ll be using GPUs hosted in the cloud, all you are required to bring is a laptop with a modern browser.\r\n<h3>ArrayFire Talks at GTC</h3>\r\n<h5>S5205 - Real-Time and High Resolution Feature Tracking and Object Recognition</h5>\r\n<h6>Presented by Peter Andreas Entschev - Tuesday March 17 at 3:00 PM</h6>\r\nThis session will cover real-time feature tracking and object recognition in high resolution videos using GPUs and productive software libraries including ArrayFire. Feature tracking and object recognition are computer vision problems that have challenged researchers for decades. Over the last 15 years, numerous approaches were proposed to solve these problems, some of the most important being SIFT, SURF and ORB. Traditionally, these approaches are so computationally complex that processing more than a few frames per second is impossible. Using an NVIDIA K20 GPU with ORB, we are able to process about 30 frames per second on images in the order of Ultra HD resolution. Multiple quality and timing benchmarks will be presented, covering some of the most robust feature tracking methods.\r\n<h5>S5176 - Fast Triangle Counting for Social Network Analytics on the K40</h5>\r\n<h6>Presented by Oded Green - Wednesday March 18 at 4:30 PM</h6>\r\nIn this session we will explore a new approach for counting triangles in networks that partitions the work at multiple parallel granularties. This new approach is highly scalable and is appropriate for both sparse and dense networks.\r\n\r\n<hr />\r\n\r\n<h5>Schedule a Meeting with Us</h5>\r\nDo you want to meet with us personally? Schedule a time to sit down with ArrayFire engineers and account representatives using our <a href=\"http://www.meetme.so/arrayfire\">online scheduler</a>.\r\n<h5>Get a GTC 2015 20% Discount</h5>\r\nWe have 20% discount coupons available for GTC registrations. If you\'re interested, please contact sales@arrayfire.com for more information.\r\n\r\nWe look forward to seeing everyone at GTC!','Visit ArrayFire at GTC 2015','','inherit','open','closed','','8000-autosave-v1','','','2016-03-31 17:34:21','2016-03-31 21:34:21','',8000,'http://sandbox.arrayfire.com/8000-autosave-v1/',0,'revision','',0),(8821,6,'2016-03-31 17:40:51','2016-03-31 21:40:51','<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2016/03/GTC_2016_Banner2.jpg\"><img class=\"alignnone wp-image-8822 size-full\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2016/03/GTC_2016_Banner2.jpg\" alt=\"GTC_2016_Banner2\" width=\"700\" height=\"250\" /></a>\r\n\r\nGTC is quickly approaching and we want to see you there!\r\n\r\n<strong>When: April 4-7</strong>\r\n<strong>Where: San Jose, California</strong>\r\n<strong>ArrayFire Booth: 103</strong>\r\n\r\nGTC is the world\'s premier GPU developer conference. Connect with experts from NVIDIA and other leaders in high performance computing. At GTC you\'ll discover what\'s next in GPU breakthroughs and gain useful insights in hundreds of sessions and hands-on labs covering a diverse range of application domains.\r\n\r\nWe invite you to attend the following talk presented by one of our knowledgeable and experienced GPU developers.\r\n<h5><strong>Real-Time Visualization of CUDA® Data Using ArrayFire Forge</strong></h5>\r\n<h6>Presented by Brian Kloppenborg - Wednesday April 6 at 3:30 pm (Room 211B)</h6>\r\nWe will debut ArrayFire Forge, our new general-purpose data visualization library for GPUs. ArrayFire Forge is a data visualization library that is written specifically for use with GPU-accelerated applications. By using interoperability with OpenGL, Forge enables developers to create real-time, responsive, and stunning visualizations in 2D and 3D. Forge is an open-source project and distributed on GitHub.\r\n\r\nVisit the <a href=\"https://mygtc.gputechconf.com/form/session-listing\">GTC Session Catalog</a> for more details—you don\'t want to miss out!\r\n<h5>Schedule a Meeting with Us</h5>\r\nDo you want to meet with us personally? We\'d love to chat! Schedule a time to sit down with ArrayFire engineers and account representatives using our <a href=\"http://www.meetme.so/arrayfire\">online scheduler</a>.\r\n\r\nWe look forward to seeing everyone at GTC!','Visit ArrayFire at GTC 2016','','publish','open','closed','','visit-arrayfire-at-gtc-2016','','','2016-03-31 17:40:51','2016-03-31 21:40:51','',0,'http://sandbox.arrayfire.com/?p=8821',0,'post','',2),(8822,6,'2016-03-31 17:10:29','2016-03-31 21:10:29','','GTC_2016_Banner2','','inherit','open','closed','','gtc_2016_banner2','','','2016-03-31 17:10:29','2016-03-31 21:10:29','',8821,'http://sandbox.arrayfire.com/wp-content/uploads/2016/03/GTC_2016_Banner2.jpg',0,'attachment','image/jpeg',0),(8823,6,'2016-03-31 17:29:45','2016-03-31 21:29:45','<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2016/03/GTC_2016_Banner2.jpg\"><img class=\"alignnone wp-image-8822 size-full\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2016/03/GTC_2016_Banner2.jpg\" alt=\"GTC_2016_Banner2\" width=\"700\" height=\"250\" /></a>\r\n\r\n&nbsp;\r\n\r\nGTC is quickly approaching and we want to see you there!\r\n\r\n<strong>When: April 4-7</strong>\r\n<strong>Where: San Jose, California</strong>\r\n<strong>ArrayFire Booth: 103</strong>\r\n\r\nGTC is the world\'s premier GPU developer conference. Connect with experts from NVIDIA and other leaders in high performance computing. At GTC you\'ll discover what\'s next in GPU breakthroughs, and gain useful insights in hundreds of sessions and hands-on labs covering a diverse range of application domains.\r\n\r\nWe invite you to attend a talk presented by one of our knowledgeable and experienced GPU developers.\r\n<h3><strong>Real-Time Visualization of CUDA® Data Using ArrayFire Forge</strong></h3>\r\n<h5>Presented by Brian Kloppenborg - Wednesday April 6 at 3:30 pm (Room 211B)</h5>\r\nWe will debut ArrayFire Forge, our new general-purpose data visualization library for GPUs. ArrayFire Forge is a data visualization library that is written specifically for use with GPU-accelerated applications. By using interoperability with OpenGL, Forge enables developers to create real-time, responsive, and stunning visualizations in 2D and 3D. Forge is an open-source project and distributed on GitHub.\r\n\r\nVisit the <a href=\"https://registration.gputechconf.com/form/session-listing\">GTC Session Catalog</a> for more details—you don\'t want to miss out!\r\n<h5>Schedule a Meeting with Us</h5>\r\nDo you want to meet with us personally? Schedule a time to sit down with ArrayFire engineers and account representatives using our <a href=\"http://www.meetme.so/arrayfire\">online scheduler</a>.\r\n<h5>Get a GTC 2015 20% Discount</h5>\r\nWe have 20% discount coupons available for GTC registrations. If you\'re interested, please contact sales@arrayfire.com for more information.\r\n\r\nWe look forward to seeing everyone at GTC!\r\n\r\n&nbsp;\r\n\r\n&nbsp;','Visit ArrayFire at GTC 2016','','inherit','open','closed','','8821-revision-v1','','','2016-03-31 17:29:45','2016-03-31 21:29:45','',8821,'http://sandbox.arrayfire.com/8821-revision-v1/',0,'revision','',0),(8824,6,'2016-03-31 17:33:28','2016-03-31 21:33:28','<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2016/03/GTC_2016_Banner2.jpg\"><img class=\"alignnone wp-image-8822 size-full\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2016/03/GTC_2016_Banner2.jpg\" alt=\"GTC_2016_Banner2\" width=\"700\" height=\"250\" /></a>\r\n\r\nGTC is quickly approaching and we want to see you there!\r\n\r\n<strong>When: April 4-7</strong>\r\n<strong>Where: San Jose, California</strong>\r\n<strong>ArrayFire Booth: 103</strong>\r\n\r\nGTC is the world\'s premier GPU developer conference. Connect with experts from NVIDIA and other leaders in high performance computing. At GTC you\'ll discover what\'s next in GPU breakthroughs, and gain useful insights in hundreds of sessions and hands-on labs covering a diverse range of application domains.\r\n\r\nWe invite you to attend the following talk presented by one of our knowledgeable and experienced GPU developers.\r\n<h4><strong>Real-Time Visualization of CUDA® Data Using ArrayFire Forge</strong></h4>\r\n<h5>Presented by Brian Kloppenborg - Wednesday April 6 at 3:30 pm (Room 211B)</h5>\r\nWe will debut ArrayFire Forge, our new general-purpose data visualization library for GPUs. ArrayFire Forge is a data visualization library that is written specifically for use with GPU-accelerated applications. By using interoperability with OpenGL, Forge enables developers to create real-time, responsive, and stunning visualizations in 2D and 3D. Forge is an open-source project and distributed on GitHub.\r\n\r\nVisit the <a href=\"https://mygtc.gputechconf.com/form/session-listing\">GTC Session Catalog</a> for more details—you don\'t want to miss out!\r\n<h4>Schedule a Meeting with Us</h4>\r\nDo you want to meet with us personally? We\'d love to chat! Schedule a time to sit down with ArrayFire engineers and account representatives using our <a href=\"http://www.meetme.so/arrayfire\">online scheduler</a>.\r\n<h5></h5>\r\nWe look forward to seeing everyone at GTC!','Visit ArrayFire at GTC 2016','','inherit','open','closed','','8821-revision-v1','','','2016-03-31 17:33:28','2016-03-31 21:33:28','',8821,'http://sandbox.arrayfire.com/8821-revision-v1/',0,'revision','',0),(8825,6,'2016-03-31 17:35:54','2016-03-31 21:35:54','<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2016/03/GTC_2016_Banner2.jpg\"><img class=\"alignnone wp-image-8822 size-full\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2016/03/GTC_2016_Banner2.jpg\" alt=\"GTC_2016_Banner2\" width=\"700\" height=\"250\" /></a>\r\n\r\nGTC is quickly approaching and we want to see you there!\r\n\r\n<strong>When: April 4-7</strong>\r\n<strong>Where: San Jose, California</strong>\r\n<strong>ArrayFire Booth: 103</strong>\r\n\r\nGTC is the world\'s premier GPU developer conference. Connect with experts from NVIDIA and other leaders in high performance computing. At GTC you\'ll discover what\'s next in GPU breakthroughs and gain useful insights in hundreds of sessions and hands-on labs covering a diverse range of application domains.\r\n\r\nWe invite you to attend the following talk presented by one of our knowledgeable and experienced GPU developers.\r\n<h5><strong>Real-Time Visualization of CUDA® Data Using ArrayFire Forge</strong></h5>\r\n<h6>Presented by Brian Kloppenborg - Wednesday April 6 at 3:30 pm (Room 211B)</h6>\r\nWe will debut ArrayFire Forge, our new general-purpose data visualization library for GPUs. ArrayFire Forge is a data visualization library that is written specifically for use with GPU-accelerated applications. By using interoperability with OpenGL, Forge enables developers to create real-time, responsive, and stunning visualizations in 2D and 3D. Forge is an open-source project and distributed on GitHub.\r\n\r\nVisit the <a href=\"https://mygtc.gputechconf.com/form/session-listing\">GTC Session Catalog</a> for more details—you don\'t want to miss out!\r\n<h5>Schedule a Meeting with Us</h5>\r\nDo you want to meet with us personally? We\'d love to chat! Schedule a time to sit down with ArrayFire engineers and account representatives using our <a href=\"http://www.meetme.so/arrayfire\">online scheduler</a>.\r\n<h5></h5>\r\nWe look forward to seeing everyone at GTC!','Visit ArrayFire at GTC 2016','','inherit','open','closed','','8821-revision-v1','','','2016-03-31 17:35:54','2016-03-31 21:35:54','',8821,'http://sandbox.arrayfire.com/8821-revision-v1/',0,'revision','',0),(8826,6,'2016-03-31 17:40:30','2016-03-31 21:40:30','<a href=\"http://sandbox.arrayfire.com/wp-content/uploads/2016/03/GTC_2016_Banner2.jpg\"><img class=\"alignnone wp-image-8822 size-full\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2016/03/GTC_2016_Banner2.jpg\" alt=\"GTC_2016_Banner2\" width=\"700\" height=\"250\" /></a>\r\n\r\nGTC is quickly approaching and we want to see you there!\r\n\r\n<strong>When: April 4-7</strong>\r\n<strong>Where: San Jose, California</strong>\r\n<strong>ArrayFire Booth: 103</strong>\r\n\r\nGTC is the world\'s premier GPU developer conference. Connect with experts from NVIDIA and other leaders in high performance computing. At GTC you\'ll discover what\'s next in GPU breakthroughs and gain useful insights in hundreds of sessions and hands-on labs covering a diverse range of application domains.\r\n\r\nWe invite you to attend the following talk presented by one of our knowledgeable and experienced GPU developers.\r\n<h5><strong>Real-Time Visualization of CUDA® Data Using ArrayFire Forge</strong></h5>\r\n<h6>Presented by Brian Kloppenborg - Wednesday April 6 at 3:30 pm (Room 211B)</h6>\r\nWe will debut ArrayFire Forge, our new general-purpose data visualization library for GPUs. ArrayFire Forge is a data visualization library that is written specifically for use with GPU-accelerated applications. By using interoperability with OpenGL, Forge enables developers to create real-time, responsive, and stunning visualizations in 2D and 3D. Forge is an open-source project and distributed on GitHub.\r\n\r\nVisit the <a href=\"https://mygtc.gputechconf.com/form/session-listing\">GTC Session Catalog</a> for more details—you don\'t want to miss out!\r\n<h5>Schedule a Meeting with Us</h5>\r\nDo you want to meet with us personally? We\'d love to chat! Schedule a time to sit down with ArrayFire engineers and account representatives using our <a href=\"http://www.meetme.so/arrayfire\">online scheduler</a>.\r\n\r\nWe look forward to seeing everyone at GTC!','Visit ArrayFire at GTC 2016','','inherit','open','closed','','8821-revision-v1','','','2016-03-31 17:40:30','2016-03-31 21:40:30','',8821,'http://sandbox.arrayfire.com/8821-revision-v1/',0,'revision','',0),(8828,17728,'2016-04-24 06:02:36','2016-04-24 10:02:36','','arrayfire_logo_symbol','','inherit','open','closed','','arrayfire_logo_symbol-2','','','2016-06-02 09:45:47','2016-06-02 13:45:47','',8901,'http://sandbox.arrayfire.com/wp-content/uploads/2016/04/arrayfire_logo_symbol.png',0,'attachment','image/png',0),(8829,11,'2016-04-26 12:59:17','2016-04-26 16:59:17','[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"10px\" padding_bottom=\"40px\"]\r\n[custom_headline type=\"left\" level=\"h2\"]\r\nArrayFire Installers\r\n[/custom_headline]\r\n[custom_headline type=\"left\" level=\"h5\"]\r\nEach download contains both CUDA and OpenCL files.\r\n[/custom_headline]\r\n[gap size=\"4%\"]\r\n\r\n[column type=\"one-fourth\"][button  block=\"true\" onclick=\"&lt;!-- Google Code for ArrayFire Download (Windows) Conversion Page\r\nIn your html page, add the snippet and call\r\ngoog_report_conversion when someone clicks on the\r\nchosen link or button. --&gt;\r\n&lt;script type=\"text/javascript\"&gt;\r\n/* &lt;!&amp;#91;CDATA&amp;#91; */\r\ngoog_snippet_vars = function() {\r\nvar w = window;\r\nw.google_conversion_id = 1021026651;\r\nw.google_conversion_label = \"18VJCJjPql4Q28Lu5gM\";\r\nw.google_remarketing_only = false;\r\n}\r\n// DO NOT CHANGE THE CODE BELOW.\r\ngoog_report_conversion = function(url) {\r\ngoog_snippet_vars();\r\nwindow.google_conversion_format = \"3\";\r\nwindow.google_is_call = true;\r\nvar opt = new Object();\r\nopt.onload_callback = function() {\r\nif (typeof(url) != \'undefined\') {\r\nwindow.location = url;\r\n}\r\n}\r\nvar conv_handler = window&amp;#91;\'google_trackConversion\'&amp;#93;;\r\nif (typeof(conv_handler) == \'function\') {\r\nconv_handler(opt);\r\n}\r\n}\r\n/* &amp;#93;&amp;#93;&gt; */\r\n&lt;/script&gt;\r\n&lt;script type=\"text/javascript\"\r\nsrc=\"//www.googleadservices.com/pagead/conversion_async.js\"&gt;\r\n&lt;/script&gt;\" class=\"center-text\" type=\"flat\" shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/windows-installer\" size=\"regular\" ]Windows, v3.3.2\r\n(64-bit)[/button][/column] [column type=\"one-fourth\"][button block=\"true\" type=\"flat\"  shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/linux-x86_64-installer\" size=\"regular\" ]Linux, v3.3.2\r\n(64-bit)[/button][/column][column type=\"one-fourth\"][button  block=\"true\" type=\"flat\"  shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/osx-installer\" size=\"regular\" ]Mac OSX, v3.3.2\r\n(64-bit)[/button][/column] [column type=\"one-fourth\" last=\"true\"][button block=\"true\"  type=\"flat\"  shape=\"rounded\" href=\"http://go.sandbox.arrayfire.com/linux-armv7l-installer\" size=\"regular\" ]Tegra K1 v3.3.2\r\n(32-bit)[/button][/column][gap size=\"9%\"]\r\n\r\nCheck out our GitHub repository to <a href=\"https://github.com/arrayfire/arrayfire\">build from the source</a>.\r\n\r\nLooking for an older installer? <a href=\"http://sandbox.arrayfire.com/installer_archive\">Try here</a>.[/content_band]\r\n<p style=\"text-align: left;\">[content_band inner_container=\"true\" no_margin=\"true\" border=\"none\" padding_top=\"10px\" padding_bottom=\"40px\" bg_color=\"#f1f1f1\"][column type=\"one-half\"][gap size=\"8%\"]<img class=\"aligncenter wp-image-5156\" src=\"http://sandbox.arrayfire.com/wp-content/uploads/2014/02/mobile_Exported1-e1395437261846.png\" alt=\"mobile_Exported\" width=\"233\" height=\"311\" />[/column][column type=\"one-half\" last=\"true\"]\r\n[custom_headline type=\"left\" level=\"h2\"]\r\nGreat. What now?\r\n[/custom_headline]</p>\r\n<p style=\"text-align: left;\">[gap size=\"5%\"]</p>\r\n<p style=\"text-align: left;\">Welcome to ArrayFire! You\'ve got an awesome library there—learn more about its features and functions on <a href=\"http://www.sandbox.arrayfire.com/docs/index.htm\">our documentation</a>.</p>\r\n<p style=\"text-align: left;\">In addition to our <a href=\"https://groups.google.com/forum/#!forum/arrayfire-users\">ArrayFire user group</a> and <a href=\"http://sandbox.arrayfire.com/blog/\">our blog</a>, we offer a plethora of <a href=\"http://sandbox.arrayfire.com/support/\">support options</a> to fit your needs.</p>\r\n<p style=\"text-align: left;\">Got a job that needs closer attention? Hire us! Our engineers are acceleration wizards. Check out our <a href=\"http://sandbox.arrayfire.com/consulting/\">consulting offerings</a>, or set up a free <a href=\"http://meetme.so/arrayfire\">technical consultation</a> with us today![/column]</p>\r\n<p style=\"text-align: left;\">[/content_band]</p>\r\n<p style=\"text-align: center;\"></p>','Download','','inherit','closed','closed','','5931-revision-v1','','','2016-04-26 12:59:17','2016-04-26 16:59:17','',5931,'http://sandbox.arrayfire.com/5931-revision-v1/',0,'revision','',0),(8831,18528,'2016-05-12 10:43:34','2016-05-12 14:43:34','The fundamental primitive of the ArrayFire Library is our container object, the array. As the next post in our blog series, \"<a href=\"http://sandbox.arrayfire.com/tag/learning-arrayfire-from-scratch/\">Learning ArrayFire from scratch</a>\", we will describe how to construct arrays, what datatypes arrays support, indexing, how to query an array for various properties (content, dimensions), and how to write mathematical expressions that involve arrays.\r\n\r\n<!--more-->\r\n\r\nArrayFire abstracts away much of the details of programming parallel architectures by providing a high-level container object, the <a class=\"el\" href=\"http://arrayfire.org/docs/group__array__mat.htm\">array</a>, that represents data stored on a CPU, GPU, FPGA, or other type of accelerator. This abstraction permits developers to write massively parallel applications in a high-level language where they need not be concerned about low-level optimizations that are frequently required to achieve high throughput on most parallel architectures.\r\n<h4>Creating ArrayFire Arrays</h4>\r\nArrays represent memory on a supported device. You can create arrays of uninitialized memory using the array constructor:\r\n<pre class=\"lang:c++ decode:true\">// Arrays may be created using the af::array constructor and dimensioned\r\n// as 1D, 2D, 3D; however, the values in these arrays will be undefined\r\narray undefined_1D = array(100);        // 1D array with 100 elements\r\narray undefined_2D = array(10, 100);    // 2D array of size 10 x 100\r\narray undefined_3D = array(10, 10, 10); // 3D array of size 10 x 10 x 10</pre>\r\nOr using one of many constructors that initialize memory:\r\n<pre class=\"lang:default decode:true\">// Create an array of zeros of length three:\r\narray zeros      = constant(0, 3);\r\n\r\n// Generate a 1x4 array of uniformly distributed [0,1] random numbe// using af::randu():\r\narray rand1      = randu(1, 4);\r\n    \r\n// Make a 2x2 array (or matrix, if you prefer) of random numbers\r\n// sampled from a normal distribution using af::randn():\r\narray rand2      = randn(2, 2);\r\n\r\n// Construct a 3x3 identity matrix. \r\narray iden       = af::identity(3, 3);</pre>\r\nLastly, arrays may be populated with data from the host using our copy constructor:\r\n<pre class=\"lang:default decode:true\">// Create a six-element array on the host\r\nfloat hA[] = {0, 1, 2, 3, 4, 5};\r\n    \r\n// Using the array copy constructor, we can create a 2x3\r\n// matrix from this data:\r\narray A(2, 3, hA);</pre>\r\nArrays can also be created from CUDA device pointers or OpenCL memory buffers. Please consult the <a href=\"http://arrayfire.org/docs/gettingstarted.htm\">documentation</a> on these aspects.\r\n<h4>Supported data types</h4>\r\nArrayFire arrays support standard integral and complex data types found in C/C++. The data type for an array is specified by providing an (optional) final parameter to any of the array constructors. The type field and supported types are as follows:\r\n<ul>\r\n 	<li>b8 8-bit boolean values (bool)</li>\r\n 	<li>f32 real single-precision (float)</li>\r\n 	<li>c32 complex single-precision (cfloat)</li>\r\n 	<li>s32 32-bit signed integer (int)</li>\r\n 	<li>u32 32-bit unsigned integer (unsigned)</li>\r\n 	<li>f64 real double-precision (double)</li>\r\n 	<li>c64 complex double-precision (cdouble)</li>\r\n 	<li>s64 64-bit signed integer (intl)</li>\r\n 	<li>u64 64-bit unsigned integer (uintl)</li>\r\n 	<li>s16 16-bit signed integer (short)</li>\r\n 	<li>u16 16-bit unsigned integer (unsigned short)</li>\r\n</ul>\r\nFor example, if you wanted to construct a 2x1 (column vector) of uniformly distributed 32-bit complex numbers (c32 data type), you would use the following code:\r\n<pre class=\"lang:default decode:true\">// Create a 2x1 column vector of uniformly distributed\r\n// 32-bit complex values:\r\narray randcplx   = randu(2, 1, c32);</pre>\r\n<h4>Indexing</h4>\r\nLike all functions in ArrayFire, indexing is also executed in parallel on the OpenCL/CUDA device. Because of this, indexing becomes part of a JIT operation and is accomplished using parentheses instead of square brackets (i.e. as A(0) instead of A[0]). To index af::arrays you may use one or a combination of the following functions:\r\n<ul>\r\n 	<li>integer scalars</li>\r\n 	<li>seq() representing a linear sequence</li>\r\n 	<li>end representing the last element of a dimension</li>\r\n 	<li>span representing the entire dimension</li>\r\n 	<li>row(i) or col(i) specifying a single row/column</li>\r\n 	<li>rows(first,last) or cols(first,last) specifying a span of rows or columns</li>\r\n</ul>\r\nHere are a few examples of these indexing functions in operation:\r\n<pre class=\"lang:default decode:true\">// Make an 3x3 array containing numbers 1-9:\r\narray A = array(seq(1,9), 3, 3);\r\n\r\nA(0);            // first element\r\nA(0,1);          // first row, second column\r\nA(end);          // last element\r\nA(-1);           // also last element\r\nA(end-1);        // second-to-last element\r\nA(1,span);       // second row\r\nA.row(end);      // last row\r\nA.cols(1,end);   // all but first column</pre>\r\nFor further examples, see the <a href=\"http://arrayfire.org/docs/indexing.htm\">documentation on indexing</a>.\r\n<h4>Querying existing arrays for their properties</h4>\r\nArrayFire array objects carry some ancillary information which can be quite useful when developing applications. For example, once you have an array <span class=\"lang:default decode:true crayon-inline \">A</span> , you can query for:\r\n<ul>\r\n 	<li>Number and size of dimensions via. <span class=\"lang:default decode:true crayon-inline \">A.numdims()</span>  and <span class=\"lang:default decode:true crayon-inline \">A.dims(int)</span>  functions.</li>\r\n 	<li>The size of the array in bytes with <span class=\"lang:default decode:true crayon-inline \">A.bytes()</span></li>\r\n 	<li>The underlying data type using <span class=\"lang:default decode:true crayon-inline \">A.type()</span> or one of many type-specific queries.</li>\r\n 	<li>Whether or not the array is complex or real using <span class=\"lang:default decode:true crayon-inline \">A.iscomplex()</span>  or <span class=\"lang:default decode:true crayon-inline \">A.isreal()</span></li>\r\n 	<li>If the data is scalar, <span class=\"lang:default decode:true crayon-inline \">A.isscalar()</span> , a vector, <span class=\"lang:default decode:true crayon-inline \">A.isvector()</span> , a row, <span class=\"lang:default decode:true crayon-inline \">A.isrow()</span> , or a column, <span class=\"lang:default decode:true crayon-inline \">A.iscolumn()</span> .</li>\r\n</ul>\r\n<h4>Writing mathematical expressions</h4>\r\nArrayFire features an intelligent Just-In-Time (JIT) compilation engine that converts expressions using arrays into the smallest number of CUDA/OpenCL kernels. For most operations on arrays, ArrayFire functions like a vector library. That means that an element-wise operation, like <span class=\"lang:default decode:true crayon-inline \">c[i] = a[i] + b[i]</span>  in C, would be written more concisely without indexing, like <span class=\"lang:default decode:true crayon-inline \">c = a + b</span> . When there are multiple expressions involving arrays, ArrayFire\'s JIT engine will merge them together. This \"kernel fusion\" technology not only decreases the number of kernel calls, but, more importantly, avoids extraneous global memory operations. Our JIT functionality extends across C/C++ function boundaries and only ends when a non-JIT function is encountered or a synchronization operation is explicitly called by the code. Thus writing mathematical functions in ArrayFire is as simple as writing the equations themselves!\r\n\r\nArrayFire provides <a class=\"el\" href=\"http://arrayfire.org/docs/group__arith__mat.htm\">hundreds of functions</a> for element-wise operations. All of the standard operators (e.g. +,-,*,/) are supported as are most transcendental functions (sin, cos, log, sqrt, etc.).\r\n\r\nIn addition to mathematical functions, ArrayFire also includes frequently used computer vision functions (FAST, ORB, SIFT), and image processing functions (colorspace conversion, filters, histograms, transformations, and morphological operations).\r\n\r\n&nbsp;','Introduction to the ArrayFire array','','publish','open','closed','','introduction-to-the-arrayfire-array','','','2016-05-16 11:55:45','2016-05-16 15:55:45','',0,'http://sandbox.arrayfire.com/?p=8831',0,'post','',0),(8832,18528,'2016-05-11 10:58:02','2016-05-11 14:58:02','','Introduction to the ArrayFire array','','inherit','closed','closed','','8831-revision-v1','','','2016-05-11 10:58:02','2016-05-11 14:58:02','',8831,'http://sandbox.arrayfire.com/8831-revision-v1/',0,'revision','',0),(8833,18528,'2016-05-11 11:00:35','2016-05-11 15:00:35','Continuing our blog series \"<a href=\"http://sandbox.arrayfire.com/tag/learning-arrayfire-from-scratch/\">Learning ArrayFire from scratch</a>\" today we will provide an introduction to the core data structure in ArrayFire: the af::array. We describe how to construct arrays, what datatypes arrays support, how to query an array for various properties (content, dimensions), how to write mathematical expressions on arrays.\r\n\r\n<!--more-->','Introduction to the ArrayFire array','','inherit','closed','closed','','8831-revision-v1','','','2016-05-11 11:00:35','2016-05-11 15:00:35','',8831,'http://sandbox.arrayfire.com/8831-revision-v1/',0,'revision','',0),