diff --git a/doc/array_and_matrix_manipulation.md b/doc/array_and_matrix_manipulation.md new file mode 100644 index 000000000..7abcc3296 --- /dev/null +++ b/doc/array_and_matrix_manipulation.md @@ -0,0 +1,271 @@ +% Array and Matrix Manipulation + +ArrayFire provides several different methods for manipulating arrays and matrices. +The functionality includes: + +* [moddims()](#moddims) - change the dimensions of an array without changing the data +* [flat()](#flat) - flatten an array to one dimension +* [flip()](#flip) - flip an array along a dimension +* [join()](#join) - join up to 4 arrays +* [reorder()](#reorder) - changes the dimension order within the array +* [shift()](#shift) - shifts data along a dimension +* [tile()](#tile) - repeats an array along a dimension +* [transpose()](#transpose) - performs a matrix transpose + +Below we provide several examples of these functions and their use. + +### moddims() + +The [moddims](./fn.moddims.html) function changes the dimensions of an array without +changing its data or order. Note that this function modifies only the _metadata_ +associated with the array. It does not modify the content of the array. +Here is an example of moddims() converting an 8x1 array into a 2x4 and then +back to a 8x1: + +```rust +a [8 1 1 1] + 1.0000 + 2.0000 + 1.0000 + 2.0000 + 1.0000 + 2.0000 + 1.0000 + 2.0000 + +let new_dims = Dim4::new(&[2, 4, 1, 1]); +moddims(&a, new_dims) +[2 4 1 1] + 1.0000 1.0000 1.0000 1.0000 + 2.0000 2.0000 2.0000 2.0000 + +let out = moddims(&a, a.elements(), 1, 1, 1); +[8 1 1 1] + 1.0000 + 2.0000 + 1.0000 + 2.0000 + 1.0000 + 2.0000 + 1.0000 + 2.0000 +``` + +### flat() + +The [flat](./fn.flat.html) function flattens an array to one dimension: + +``` +a [3 3 1 1] + 1.0000 4.0000 7.0000 + 2.0000 5.0000 8.0000 + 3.0000 6.0000 9.0000 + +flat(&a) +[9 1 1 1] + 1.0000 + 2.0000 + 3.0000 + 4.0000 + 5.0000 + 6.0000 + 7.0000 + 8.0000 + 9.0000 +``` + +### flip() + +The [flip](./fn.flip.html) function flips the contents of an array along a +chosen dimension. In the example below, we show the 5x2 array flipped +along the zeroth (i.e. within a column) and first (e.g. across rows) axes: + +```rust +a [5 2 1 1] + 1.0000 6.0000 + 2.0000 7.0000 + 3.0000 8.0000 + 4.0000 9.0000 + 5.0000 10.0000 + +flip(a, 0) [5 2 1 1] + 5.0000 10.0000 + 4.0000 9.0000 + 3.0000 8.0000 + 2.0000 7.0000 + 1.0000 6.0000 + +flip(a, 1) [5 2 1 1] + 6.0000 1.0000 + 7.0000 2.0000 + 8.0000 3.0000 + 9.0000 4.0000 + 10.0000 5.0000 +``` + +### join() + +The [join](./fn.join.html), [join_many](./fn.join_many.html) functions can be +used to join arrays along a specific dimension. + +Here is an example of how to use join an array to itself: + +```rust +a [5 1 1 1] + 1.0000 + 2.0000 + 3.0000 + 4.0000 + 5.0000 + +join(0, a, a) [10 1 1 1] + 1.0000 + 2.0000 + 3.0000 + 4.0000 + 5.0000 + 1.0000 + 2.0000 + 3.0000 + 4.0000 + 5.0000 + +join(1, a, a) [5 2 1 1] + 1.0000 1.0000 + 2.0000 2.0000 + 3.0000 3.0000 + 4.0000 4.0000 + 5.0000 5.0000 +``` + +### reorder() + +The [reorder](./fn.reorder.html) function modifies the order of data within an array by +exchanging data according to the change in dimensionality. The linear ordering +of data within the array is preserved. + +```rust +a [2 2 3 1] + 1.0000 3.0000 + 2.0000 4.0000 + + 1.0000 3.0000 + 2.0000 4.0000 + + 1.0000 3.0000 + 2.0000 4.0000 + + +reorder(&a, 1, 0, 2) +[2 2 3 1] //equivalent to a transpose + 1.0000 2.0000 + 3.0000 4.0000 + + 1.0000 2.0000 + 3.0000 4.0000 + + 1.0000 2.0000 + 3.0000 4.0000 + + +reorder(&a, 2, 0, 1) +[3 2 2 1] + 1.0000 2.0000 + 1.0000 2.0000 + 1.0000 2.0000 + + 3.0000 4.0000 + 3.0000 4.0000 + 3.0000 4.0000 +``` + +### shift() + +The [shift](./fn.shift.html) function shifts data in a circular buffer fashion along a +chosen dimension. Consider the following example: + +```rust +a [3 5 1 1] + 0.0000 0.0000 0.0000 0.0000 0.0000 + 3.0000 4.0000 5.0000 1.0000 2.0000 + 3.0000 4.0000 5.0000 1.0000 2.0000 + +shift(&a, 0, 2 ) +[3 5 1 1] + 0.0000 0.0000 0.0000 0.0000 0.0000 + 1.0000 2.0000 3.0000 4.0000 5.0000 + 1.0000 2.0000 3.0000 4.0000 5.0000 + +shift(&a, -1, 2 ) +[3 5 1 1] + 1.0000 2.0000 3.0000 4.0000 5.0000 + 1.0000 2.0000 3.0000 4.0000 5.0000 + 0.0000 0.0000 0.0000 0.0000 0.0000 +``` + +### tile() + +The [tile](./fn.tile.html) function repeats an array along the specified dimension. +For example below we show how to tile an array along the zeroth and first +dimensions of an array: + +```rust +a [3 1 1 1] + 1.0000 + 2.0000 + 3.0000 + +// Repeat array a twice in the zeroth dimension +tile(&a, 2) +[6 1 1 1] + 1.0000 + 2.0000 + 3.0000 + 1.0000 + 2.0000 + 3.0000 + +// Repeat array a twice along both the zeroth and first dimensions +tile(&a, 2, 2) +[6 2 1 1] + 1.0000 1.0000 + 2.0000 2.0000 + 3.0000 3.0000 + 1.0000 1.0000 + 2.0000 2.0000 + 3.0000 3.0000 + +// Repeat array a twice along the first and three times along the second +// dimension. +let tile_dims = Dim4::new(&[1, 2, 3, 1]); +tile(a, tile_dims) [3 2 3 1] + 1.0000 1.0000 + 2.0000 2.0000 + 3.0000 3.0000 + + 1.0000 1.0000 + 2.0000 2.0000 + 3.0000 3.0000 + + 1.0000 1.0000 + 2.0000 2.0000 + 3.0000 3.0000 +``` + +### transpose() + +The [transpose](./fn.transpose.html) function performs a standard matrix transpose. The input +array must have the dimensions of a 2D-matrix. + +```rust +a [3 3 1 1] + 1.0000 3.0000 3.0000 + 2.0000 1.0000 3.0000 + 2.0000 2.0000 1.0000 + +transpose(&a, False) //Second parameter to be used for conjugate transpose +[3 3 1 1] + 1.0000 2.0000 2.0000 + 3.0000 1.0000 2.0000 + 3.0000 3.0000 1.0000 +``` diff --git a/doc/configuring_arrayfire_environment.md b/doc/configuring_arrayfire_environment.md new file mode 100644 index 000000000..7310144b5 --- /dev/null +++ b/doc/configuring_arrayfire_environment.md @@ -0,0 +1,161 @@ +% Configuring Arrayfire Environment + +Following are the list of environment and runtime configurations that will help enhance +your experience with ArrayFire. + +# AF_PATH + +This is the path with ArrayFire gets installed, ie. the includes and libs are +present in this directory. You can use this variable to add include paths and +libraries to your projects. + +# AF_PRINT_ERRORS + +When AF_PRINT_ERRORS is set to 1, the exceptions thrown are more verbose and +detailed. This helps in locating the exact failure. + +``` +AF_PRINT_ERRORS=1 ./myprogram +``` + +# AF_CUDA_DEFAULT_DEVICE + +Use this variable to set the default CUDA device. Valid values for this +variable are the device identifiers shown when [af::info](./fn.info.html) is run. + +``` +AF_CUDA_DEFAULT_DEVICE=1 ./myprogram +``` + +Note: af::setDevice call in the source code will take precedence over this +variable. + +# AF_OPENCL_DEFAULT_DEVICE + +Use this variable to set the default OpenCL device. Valid values for this +variable are the device identifiers shown when [af::info](./fn.info.html) is run. + +``` +AF_OPENCL_DEFAULT_DEVICE=1 ./myprogram +``` + +Note: [af::set_device](./fn.set_device.html) call in the source code will take precedence over this +variable. + +# AF_OPENCL_DEFAULT_DEVICE_TYPE + +Use this variable to set the default OpenCL device type. Valid values for this +variable are: CPU, GPU, ACC (Accelerators). + +When set, the first device of the specified type is chosen as default device. + +``` +AF_OPENCL_DEFAULT_DEVICE_TYPE=CPU ./myprogram +``` + +Note: `AF_OPENCL_DEFAULT_DEVICE` and [af::set_device](./fn.set_device.html) takes precedence over this variable. + +# AF_OPENCL_DEVICE_TYPE + +Use this variable to only choose OpenCL devices of specified type. Valid values for this +variable are: + +- ALL: All OpenCL devices. (Default behavior). +- CPU: CPU devices only. +- GPU: GPU devices only. +- ACC: Accelerator devices only. + +When set, the remaining OpenCL device types are ignored by the OpenCL backend. + +``` +AF_OPENCL_DEVICE_TYPE=CPU ./myprogram +``` + +# AF_OPENCL_CPU_OFFLOAD + +When ArrayFire runs on devices with unified memory with the host (ie. +`CL_DEVICE_HOST_UNIFIED_MENORY` is true for the device) then certain functions +are offloaded to run on the CPU using mapped buffers. + +ArrayFire takes advantage of fast libraries such as MKL while spending no time +copying memory from device to host. The device memory is mapped to a host +pointer which can be used in the offloaded functions. + +This functionality can be disabled by using the environment variable +`AF_OPENCL_CPU_OFFLOAD=0`. + +The default bevaior of this has changed in version 3.4. + +Prior to v3.4, CPU Offload functionality was used only when the user set +`AF_OPENCL_CPU_OFFLOAD=1` and disabled otherwise. + +From v3.4 onwards, CPU Offload is enabled by default and is disabled only when +`AF_OPENCL_CPU_OFFLOAD=0` is set. + +# AF_OPENCL_SHOW_BUILD_INFO + +This variable is useful when debuggin OpenCL kernel compilation failures. When +this variable is set to 1, and an error occurs during a OpenCL kernel +compilation, then the log and kernel are printed to screen. + +# AF_DISABLE_GRAPHICS + +Setting this variable to 1 will disable window creation when graphics +functions are being called. Disabling window creation will disable all other +graphics calls at runtime as well. + +This is a useful enviornment variable when running code on servers and systems +without displays. When graphics calls are run on such machines, they will +print warning about window creation failing. To suppress those calls, set this +variable. + +# AF_SYNCHRONOUS_CALLS + +When this environment variable is set to 1, ArrayFire will execute all +functions synchronously. + +# AF_SHOW_LOAD_PATH + +When using the Unified backend, if this variable is set to 1, it will show the +path where the ArrayFire backend libraries are loaded from. + +If the libraries are loaded from system paths, such as PATH or LD_LIBRARY_PATH +etc, then it will print "system path". If the libraries are loaded from other +paths, then those paths are shown in full. + +# AF_MEM_DEBUG + +When AF_MEM_DEBUG is set to 1 (or anything not equal to 0), the caching mechanism in the memory manager is disabled. +The device buffers are allocated using native functions as needed and freed when going out of scope. + +When the environment variable is not set, it is treated to be non zero. + +``` +AF_MEM_DEBUG=1 ./myprogram +``` + +# AF_MAX_BUFFERS + +When AF_MAX_BUFFERS is set, this environment variable specifies the maximum number of buffers allocated before garbage collection kicks in. + +Please note that the total number of buffers that can exist simultaneously can be higher than this number. This variable tells the garbage collector that it should free any available buffers immediately if the treshold is reached. + +When not set, the default value is 1000. + +# AF_OPENCL_MAX_JIT_LEN + +When set, this environment variable specifies the maximum height of the OpenCL JIT tree after which evaluation is forced. + +The default value, as of v3.4, is 50 on OSX, 100 everywhere else. This value was 20 for older versions. + +# AF_CUDA_MAX_JIT_LEN + +When set, this environment variable specifies the maximum height of the CUDA JIT tree after which evaluation is forced. + +The default value, as of v3.4, 100. This value was 20 for older versions. + +# AF_CPU_MAX_JIT_LEN + +When set, this environment variable specifies the maximum length of the CPU JIT tree after which evaluation is forced. + +The default value, as of v3.4, 100. This value was 20 for older versions. diff --git a/doc/external_docs.css b/doc/external_docs.css new file mode 100644 index 000000000..7e26a173d --- /dev/null +++ b/doc/external_docs.css @@ -0,0 +1,19 @@ +/* unvisited link */ +a:link { + color: #4d76ae; +} + +/* visited link */ +a:visited { + color: #4d76ae; +} + +/* mouse over link */ +a:hover { + color: #4d76ae; +} + +/* selected link */ +a:active { + color: #4d76ae; +} diff --git a/doc/getting_started.md b/doc/getting_started.md new file mode 100644 index 000000000..f42c16f09 --- /dev/null +++ b/doc/getting_started.md @@ -0,0 +1,232 @@ +% Getting Started + +# Introduction + +ArrayFire is a high performance software library for parallel computing with +an easy-to-use API. ArrayFire abstracts away much of the details of +programming parallel architectures by providing a high-level container object, +the [Array](./struct.Array.html), 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. + +# Supported data types + +ArrayFire provides one generic container object, the [Array](./struct.Array.html) +on which functions and mathematical operations are performed. The `array` +can represent one of many different [basic data types](./enum.DType.html): + +* [F32](./enum.DType.html) real single-precision (`float`) +* [C32](./enum.DType.html) complex single-precision (`cfloat`) +* [F64](./enum.DType.html) real double-precision (`double`) +* [C64](./enum.DType.html) complex double-precision (`cdouble`) +* [B8 ](./enum.DType.html) 8-bit boolean values (`bool`) +* [S32](./enum.DType.html) 32-bit signed integer (`int`) +* [U32](./enum.DType.html) 32-bit unsigned integer (`unsigned`) +* [U8 ](./enum.DType.html) 8-bit unsigned values (`unsigned char`) +* [S64](./enum.DType.html) 64-bit signed integer (`intl`) +* [U64](./enum.DType.html) 64-bit unsigned integer (`uintl`) +* [S16](./enum.DType.html) 16-bit signed integer (`short`) +* [U16](./enum.DType.html) 16-bit unsigned integer (`unsigned short`) + +Most of these data types are supported on all modern GPUs; however, some +older devices may lack support for double precision arrays. In this case, +a runtime error will be generated when the array is constructed. + +If not specified otherwise, `Array`s are created as single precision floating +point numbers ([F32](./enum.DType.html)). + +# Creating and populating an ArrayFire array + +ArrayFire [Array](./struct.Array.html)s represent memory stored on the device. +As such, creation and population of an array will consume memory on the device +which cannot freed until the `array` object goes out of scope. As device memory +allocation can be expensive, ArrayFire also includes a memory manager which +will re-use device memory whenever possible. + +Arrays can be created using one of the [array constructors](./struct.Array.html#method.new_empty). +Below we show how to create 1D, 2D, and 3D arrays with uninitialized values: + +```rust +let garbageVals = Array::new_empty(Dim4::new(&[3, 1, 1, 1]), DType::F32); +``` + +However, uninitialized memory is likely not useful in your application. +ArrayFire provides several convenient functions for creating arrays that contain +pre-populated values including constants, uniform random numbers, uniform +normally distributed numbers, and the identity matrix: + +```rust +// Create an array filled with constant value of 2.0 of type floating point +// The type of Array is infered from the type of the constant argument +let cnst = constant(2.0f32, Dim4::new(&[5, 5, 1, 1])); +print(&cnst); +``` +```rust +println!("Create a 5-by-3 matrix of random floats on the GPU"); +let dims = Dim4::new(&[5, 3, 1, 1]); +let a = randu::(dims); +print(&a); +``` + +As stated above, the default data type for arrays is [F32](./enum.DType.html) (a +32-bit floating point number) unless specified otherwise. + +ArrayFire `Array`s may also be populated from data found on the host. +For example: + +```rust +let values: [u32; 3] = [1u32, 2, 3]; +let indices = Array::new(&values, Dim4::new(&[3, 1, 1, 1])); +print(&indices); +``` + + + +# ArrayFire array contents, dimensions, and properties + +ArrayFire provides several functions to determine various aspects of arrays. +This includes functions to print the contents, query the dimensions, and +determine various other aspects of arrays. + +The [print](./fn.print.html) function can be used to print arrays that +have already been generated or any expression involving arrays: + +```rust +let values: [f32; 3] = [1.0, 2.0, 3.0]; +let indices = Array::new(&values, Dim4::new(&[3, 1, 1, 1])); +print(&indices); +``` + +The dimensions of an array may be determined using either a [Dim4](./struct.Dim4.html) object or by accessing the dimensions directly using the [Dim4::get](./struct.Dim4.html#method.get) and [Dim4::numdims](./struct.Dim4.html#method.ndims) functions: + +```rust +let values: [f32; 3] = [1.0, 2.0, 3.0]; +let dims: Dim4 = Dim4::new(&[3, 1, 1, 1]); +let indices = Array::new(&values, dims); +println!("Dims {:?} with dimensions {}", dims.get(), dims.ndims()); +``` + +In addition to dimensions, arrays also carry several properties including +methods to determine the underlying type and size (in bytes). You can even +determine whether the array is empty, real/complex, a row/column, or a scalar +or a vector. For further information on these capabilities, we suggest you consult the +full documentation on the [Array](./struct.Array.html). + +# Writing mathematical expressions using ArrayFire + +ArrayFire 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 `c[i] = a[i] + b[i]` in C, +would be written more concisely without indexing, like `c = a + b`. +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 API boundary and only ends +when a non-JIT function is encountered or a synchronization operation is +explicitly called by the code. + +ArrayFire provides hundreds of functions for element-wise +operations. All of the standard operators (e.g. +,-,\*,/) are supported +as are most transcendental functions (sin, cos, log, sqrt, etc.). +Here are a few examples: + +```rust +let num_rows: u64 = 5; +let num_cols: u64 = 3; +let dims = Dim4::new(&[num_rows, num_cols, 1, 1]); +let a = randu::(dims); +let b = randu::(dims); +print(&a); +print(&b); +let c = a + b; +print(&c); + +//Example of *Assign traits +let mut d = randu::(dims); +let e = constant(1f32, dims); +d += e; +print(&d); +``` + + + +# Indexing + +Like all functions in ArrayFire, indexing is also executed in parallel on +the OpenCL/CUDA device. To index `af::array`s you may use one or a combination of the following functions: + +* [Seq](./struct.Seq.html) representing a linear sequence +* [Seq::Default()](./struct.Seq.html) representing the entire dimension +* [row(&Array, i)](./fn.row.html) or [col(&Array, i)](./fn.col.html) specifying a single row/column +* [rows(&Array, first,last)](./fn.rows.html) or [cols(&Array, first,last)](./fn.cols.html) + specifying a span of rows or columns + +Please see the [indexing page](./indexing.html) for several examples of how to +use these functions. + +# Getting access to ArrayFire array memory on the host + +Memory in `af::Array`s may be accessed using the [Array::host()](./struct.Array.html#method.host) method. +The `host` function *copies* the data from the device and makes it available +in a standard slice or similar container on the host. As such, it is up to the developer to manage +any memory returned by `host`. + + + + +# Bitwise operators + +In addition to supporting standard mathematical functions, Arrays +that contain integer data types also support bitwise operators including +and, or, and shift etc. + +# Where to go for help? + +* [Google Groups](https://groups.google.com/forum/#!forum/arrayfire-users) +* ArrayFire Services: [Consulting](http://arrayfire.com/consulting/) | [Support](http://arrayfire.com/support/) | [Training](http://arrayfire.com/training/) +* [ArrayFire Blogs](http://arrayfire.com/blog/) +* Email: diff --git a/doc/indexing.md b/doc/indexing.md new file mode 100644 index 000000000..b5505d774 --- /dev/null +++ b/doc/indexing.md @@ -0,0 +1,135 @@ +% Indexing + +[Indexer](./struct.Indexer.html) structure is the key element used in Rust +wrapper for ArrayFire for creating references to existing Arrays. Given +below are few of such functions and their corresponding example use cases. +Use [Indexer::new](./struct.Indexer.html#method.new) to create an Indexer +object and set either a `Seq` object or `Array` as indexing object for a +given dimension. + +# Using Seq for all dimensions + +Create a view of an existing Array using Sequences and [index](./fn.index.html). + +```rust +let dims = Dim4::new(&[5, 5, 1, 1]); +let a = randu::(dims); +af_print!("a", a); +//a +//[5 5 1 1] +// 0.3990 0.5160 0.8831 0.9107 0.6688 +// 0.6720 0.3932 0.0621 0.9159 0.8434 +// 0.5339 0.2706 0.7089 0.0231 0.1328 +// 0.1386 0.9455 0.9434 0.2330 0.2657 +// 0.7353 0.1587 0.1227 0.2220 0.2299 + +// Index array using sequences +let seqs = &[Seq::new(1u32, 3, 1), Seq::default()]; +let sub = index(&a, seqs); +af_print!("a(seq(1,3,1), span)", sub); +// [3 5 1 1] +// 0.6720 0.3932 0.0621 0.9159 0.8434 +// 0.5339 0.2706 0.7089 0.0231 0.1328 +// 0.1386 0.9455 0.9434 0.2330 0.2657 +``` + +Set a sub-portion of an existing Array with a constant value using [assign_seq](./fn.assign_seq.html). + +```rust +let a = constant(2.0 as f32, Dim4::new(&[5, 3, 1, 1])); +let b = constant(1.0 as f32, Dim4::new(&[3, 3, 1, 1])); +let seqs = &[Seq::new(1.0, 3.0, 1.0), Seq::default()]; +let sub = assign_seq(&a, seqs, &b); +print(&a); +// 2.0 2.0 2.0 +// 2.0 2.0 2.0 +// 2.0 2.0 2.0 +// 2.0 2.0 2.0 +// 2.0 2.0 2.0 + +print(&sub); +// 2.0 2.0 2.0 +// 1.0 1.0 1.0 +// 1.0 1.0 1.0 +// 1.0 1.0 1.0 +// 2.0 2.0 2.0 +``` + +# Using Array and Seq combination + +Create a view of an existing Array using another Array and Sequence. + +```rust +use arrayfire::{Array, Dim4, Seq, print, randu, index_gen, Indexer}; +let values: [f32; 3] = [1.0, 2.0, 3.0]; +let indices = Array::new(&values, Dim4::new(&[3, 1, 1, 1])); +let seq4gen = Seq::new(0.0, 2.0, 1.0); +let a = randu::(Dim4::new(&[5, 3, 1, 1])); +// [5 3 1 1] +// 0.0000 0.2190 0.3835 +// 0.1315 0.0470 0.5194 +// 0.7556 0.6789 0.8310 +// 0.4587 0.6793 0.0346 +// 0.5328 0.9347 0.0535 + +let mut idxrs = Indexer::new(); +idxrs.set_index(&indices, 0, None); // 2nd parameter is indexing dimension +idxrs.set_index(&seq4gen, 1, Some(false)); // 3rd parameter indicates batch operation + +let sub2 = index_gen(&a, idxrs); +println!("a(indices, seq(0, 2, 1))"); print(&sub2); +// [3 3 1 1] +// 0.1315 0.0470 0.5194 +// 0.7556 0.6789 0.8310 +// 0.4587 0.6793 0.0346 +``` + +Set a sub-portion of an existing Array with another Array using a combination +of `Seq` and `Array`. + + ```rust + use arrayfire::{Array, Dim4, Seq, print, randu, constant, Indexer, assign_gen}; + let values: [f32; 3] = [1.0, 2.0, 3.0]; + let indices = Array::new(&values, Dim4::new(&[3, 1, 1, 1])); + let seq4gen = Seq::new(0.0, 2.0, 1.0); + let a = randu::(Dim4::new(&[5, 3, 1, 1])); + // [5 3 1 1] + // 0.0000 0.2190 0.3835 + // 0.1315 0.0470 0.5194 + // 0.7556 0.6789 0.8310 + // 0.4587 0.6793 0.0346 + // 0.5328 0.9347 0.0535 + + let b = constant(2.0 as f32, Dim4::new(&[3, 3, 1, 1])); + + let mut idxrs = Indexer::new(); + idxrs.set_index(&indices, 0, None); // 2nd parameter is indexing dimension + idxrs.set_index(&seq4gen, 1, Some(false)); // 3rd parameter indicates batch operation + + let sub2 = assign_gen(&a, &idxrs, &b); + println!("a(indices, seq(0, 2, 1))"); print(&sub2); + // [5 3 1 1] + // 0.0000 0.2190 0.3835 + // 2.0000 2.0000 2.0000 + // 2.0000 2.0000 2.0000 + // 2.0000 2.0000 2.0000 + // 0.5328 0.9347 0.0535 + ``` + +# Extract or Set rows/coloumns + +Extract a specific set of rows/coloumns from an existing Array. + +```rust +let dims = Dim4::new(&[5, 5, 1, 1]); +let a = randu::(dims); +println!("Grab last row of the random matrix"); +print(&a); +print(&row(&a, 4)); +print(&col(&a, 4)); +``` + +You can also use [rows](./fn.rows.html) & [cols](./fn.cols.html) to retrieve a +subset of rows or coloumns respectively. + +Similarly, [set_row](./fn.set_row.html) & [set_rows](./fn.set_rows.html) can be used to change the values in a particular set of rows using another Array. [set_col](./fn.set_col.html) & [set_cols](./fn.set_cols.html) has same functionality, except that it is for coloumns. diff --git a/doc/vectorization.md b/doc/vectorization.md new file mode 100644 index 000000000..2888bc2cd --- /dev/null +++ b/doc/vectorization.md @@ -0,0 +1,171 @@ +% Vectorization + + +By its very nature, ArrayFire is a vectorized library. Most functions operate on +Arrays as a whole -- on all elements in parallel. For example consider the following code: + +```rust +let mut a = af::range(Dim::new(&[10, 1, 1, 1])); // [0, 9] +a = a + 1; // [1, 10] +``` + +This code will result in a single backend kernel that operates on all 10 elements +of `a` in parallel. + +A small subset of such vectorized ArrayFire functions are given below for quick reference: + +| Operator Category | Functions | +|--------------------------------------------------------------|----------------------------| +| Arithmetic operations | +, -, *, /, %, >>, << | +| Logical operations | &&, \|\|, <, >, ==, != etc. | +| Numeric functions | [abs](./fn.abs.html), [floor](./fn.floor.html), [round](./fn.round.html), [min](./fn.min.html), [max](./fn.max.html), etc. | +| Complex operations | [real](./fn.real.html), [imag](./fn.imag.html), [conj](./fn.conj.html), etc. | +| Exponential and logarithmic functions | [exp](./fn.exp.html), [log](./fn.log.html), [expm1](./fn.expm1.html), [log1p](./fn.log1p.html), etc. | +| Trigonometric functions | [sin](./fn.sin.html), [cos](./fn.cos.html), [tan](./fn.tan.html), etc. | +| Hyperbolic functions | [sinh](./fn.sinh.html), [cosh](./fn.cosh.html), [tanh](./fn.tanh.html), etc. | + +In addition to element-wise operations, many other functions are also +vectorized in ArrayFire. + +Notice that even functions that perform some form of aggregation (e.g. +[sum](./fn.sum.html) or [min](./fn.min.html)), signal processing (like +[convolve](./fn.convolve.html)), and image processing functions +(i.e. [rotate](./fn.rotate.html) etc.) - all support vectorization on + different columns or images. + +For example, if we have `NUM` images of size `WIDTH`x`HEIGHT`, one could +convolve each image in a vector fashion as follows: + +```rust +let g_coef: [f32, 9] = { 1, 2, 1, 2, 4, 2, 1, 2, 1 }; + +let f = Array::new(g_coef, Dim4::new(&[3, 3, 1, 1])); +let filter = f * 1.0f32/16; + +let signal = randu(WIDTH, HEIGHT, NUM); +let conv = convolve2(signal, filter, ConvMode::DEFAULT, ConvDomain::AUTO); +``` + +Similarly, one can rotate 100 images by 45 degrees in a single call using +code like the following: + +```rust +// Construct an array of 100 WIDTH x HEIGHT images of random numbers +let imgs = randu(WIDTH, HEIGHT, 100); + +// Rotate all of the images in a single command +let rot_imgs = rotate(imgs, 45.0, False, InterpType::LINEAR); +``` + +Although *most* 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. + +Using the built in vectorized operations should be the first +and preferred method of vectorizing any code written with ArrayFire. + + diff --git a/generate_docs.sh b/generate_docs.sh new file mode 100755 index 000000000..5a60b6a14 --- /dev/null +++ b/generate_docs.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +cargo doc + +if [ -d "./target/doc/arrayfire" ]; then + # If cargo doc(generates ./target/doc directory) has been run + cp ./doc/external_docs.css ./target/doc/ + + rustdoc "./doc/getting_started.md" --markdown-css "../rustdoc.css" --markdown-css "../main.css" --markdown-css "../normalize.css" --markdown-css "../external_docs.css" -o "./target/doc/arrayfire/" + rustdoc "./doc/array_and_matrix_manipulation.md" --markdown-css "../rustdoc.css" --markdown-css "../main.css" --markdown-css "../normalize.css" --markdown-css "../external_docs.css" --markdown-no-toc -o "./target/doc/arrayfire/" + rustdoc "./doc/vectorization.md" --markdown-css "../rustdoc.css" --markdown-css "../main.css" --markdown-css "../normalize.css" --markdown-css "../external_docs.css" --markdown-no-toc -o "./target/doc/arrayfire/" + rustdoc "./doc/indexing.md" --markdown-css "../rustdoc.css" --markdown-css "../main.css" --markdown-css "../normalize.css" --markdown-css "../external_docs.css" -o "./target/doc/arrayfire/" + rustdoc "./doc/configuring_arrayfire_environment.md" --markdown-css "../rustdoc.css" --markdown-css "../main.css" --markdown-css "../normalize.css" --markdown-css "../external_docs.css" -o "./target/doc/arrayfire/" +fi diff --git a/src/array.rs b/src/array.rs index a2e515403..60770a1c3 100644 --- a/src/array.rs +++ b/src/array.rs @@ -18,6 +18,8 @@ extern { fn af_create_array(out: MutAfArray, data: *const c_void, ndims: c_uint, dims: *const DimT, aftype: uint8_t) -> c_int; + fn af_create_handle(out: MutAfArray, ndims: c_uint, dims: *const DimT, aftype: uint8_t) -> c_int; + fn af_get_elements(out: MutAfArray, arr: AfArray) -> c_int; fn af_get_type(out: *mut c_int, arr: AfArray) -> c_int; @@ -175,6 +177,27 @@ impl Array { } } + /// Constructs a new Array object of specified dimensions and type + /// + /// # Examples + /// + /// ```rust + /// use arrayfire::{Array, Dim4, DType}; + /// let garbageVals = Array::new_empty(Dim4::new(&[3, 1, 1, 1]), DType::F32); + /// ``` + #[allow(unused_mut)] + pub fn new_empty(dims: Dim4, aftype: DType) -> Array { + unsafe { + let mut temp: i64 = 0; + let err_val = af_create_handle(&mut temp as MutAfArray, + dims.ndims() as c_uint, + dims.get().as_ptr() as * const c_longlong, + aftype as uint8_t); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } + } + /// Returns the backend of the Array /// /// # Return Values diff --git a/src/defines.rs b/src/defines.rs index d777f310a..40163bd3e 100644 --- a/src/defines.rs +++ b/src/defines.rs @@ -339,13 +339,21 @@ pub enum HomographyType { #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq)] pub enum MarkerType { + /// No marker NONE = 0, + /// Pointer marker POINT = 1, + /// Hollow circle marker CIRCLE = 2, + /// Hollow Square marker SQUARE = 3, + /// Hollow Triangle marker TRIANGLE = 4, + /// Cross-hair marker CROSS = 5, + /// Plus symbol marker PLUS = 6, + /// Start symbol marker STAR = 7 } @@ -353,10 +361,15 @@ pub enum MarkerType { #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq)] pub enum MomentType { + /// Central moment of order (0 + 0) M00 = 1, // 1<<0 + /// Central moment of order (0 + 1) M01 = 2, // 1<<1 + /// Central moment of order (1 + 0) M10 = 4, // 1<<2 + /// Central moment of order (1 + 1) M11 = 8, // 1<<3 + /// All central moments of order (0,0), (0,1), (1,0) and (1,1) FIRST_ORDER = 1<<0 | 1<<1 | 1<<2 | 1<<3 } @@ -378,9 +391,13 @@ pub enum SparseFormat { #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq)] pub enum BinaryOp { + /// Addition operation ADD = 0, + /// Multiplication operation MUL = 1, + /// Minimum operation MIN = 2, + /// Maximum operation MAX = 3 } @@ -396,9 +413,13 @@ pub enum RandomEngineType { MERSENNE_GP11213 = 300 } +/// Default Philon RandomEngine that points to [PHILOX_4X32_10](./enum.RandomEngineType.html) pub const PHILOX : RandomEngineType = RandomEngineType::PHILOX_4X32_10; +/// Default Threefry RandomEngine that points to [THREEFRY_2X32_16](./enum.RandomEngineType.html) pub const THREEFRY : RandomEngineType = RandomEngineType::THREEFRY_2X32_16; +/// Default Mersenne RandomEngine that points to [MERSENNE_GP11213](./enum.RandomEngineType.html) pub const MERSENNE : RandomEngineType = RandomEngineType::MERSENNE_GP11213; +/// Default RandomEngine that defaults to [PHILOX](./constant.PHILOX.html) pub const DEFAULT_RANDOM_ENGINE : RandomEngineType = PHILOX; /// Scalar value types diff --git a/src/dim4.rs b/src/dim4.rs index 0ddcac59f..cc31b3bba 100644 --- a/src/dim4.rs +++ b/src/dim4.rs @@ -84,7 +84,7 @@ impl Dim4 { } } - // Get the dimensions as a slice of 4 values + /// Get the dimensions as a slice of 4 values pub fn get(&self) -> &[u64; 4] { &self.dims } diff --git a/src/error.rs b/src/error.rs index ddb765605..b20b7673c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,11 +4,14 @@ use std::error::Error; use std::marker::{Send, Sync}; use std::sync::RwLock; +/// Signature of callback function to be called to handle errors pub type ErrorCallback = Fn(AfError); /// Wrap ErrorCallback function pointer inside a structure /// to enable implementing Send, Sync traits on it. pub struct Callback<'cblifetime> { + ///Reference to a valid error callback function + ///Make sure this callback stays relevant throughout the lifetime of application. pub cb: &'cblifetime ErrorCallback, } @@ -60,6 +63,7 @@ pub fn register_error_handler(cb_value: Callback<'static>) { *gaurd.deref_mut() = cb_value; } +/// Default error handling callback provided by ArrayFire crate pub fn handle_error_general(error_code: AfError) { match error_code { AfError::SUCCESS => {}, /* No-op */ diff --git a/src/index.rs b/src/index.rs index e478b1b9d..67d2b3857 100644 --- a/src/index.rs +++ b/src/index.rs @@ -68,6 +68,7 @@ impl Indexable for Seq where c_double: From { impl Indexer { #[allow(unused_mut)] + /// Create a new Indexer object and set the dimension specific index objects later pub fn new() -> Indexer { unsafe { let mut temp: i64 = 0; diff --git a/src/lib.rs b/src/lib.rs index 2ead5233d..c59d22869 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,34 @@ +//! ArrayFire is a high performance software library for parallel computing with +//! an easy-to-use API. ArrayFire abstracts away much of the details of +//! programming parallel architectures by providing a high-level container object, +//! the [Array](./struct.Array.html), 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. + +//! This crate provides Rust bindings for the ArrayFire library. Given below table shows the rust bindings compatability with ArrayFire upstream. If you find any bugs, please report them on [github](https://github.com/arrayfire/arrayfire-rust/issues). +//! +//! +//! | ArrayFire Upstream | Rust Crate | +//! |:------------------:|:---------------:| +//! | 3.3.x | 3.3.x | +//! | 3.4.x | 3.4.x | +//! +//! Only, Major & Minor version numbers need to match. +//! +//! ## Tutorials +//! +//! - [Getting Started with ArrayFire](./getting_started.html) +//! - [Introduction to Vectorization](./vectorization.html) +//! - [Array and Matrix Manipulation](./array_and_matrix_manipulation.html) +//! - [Indexing](./indexing.html) +//! - [Configure ArrayFire Environment](./configuring_arrayfire_environment.html) + #![doc(html_logo_url = "http://www.arrayfire.com/logos/arrayfire_logo_symbol.png", html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://arrayfire.com/docs/rust")] +#![warn(missing_docs)] #[macro_use] extern crate lazy_static; diff --git a/src/seq.rs b/src/seq.rs index cd625dd19..643fde357 100644 --- a/src/seq.rs +++ b/src/seq.rs @@ -38,7 +38,7 @@ impl Seq { self.begin } - /// Get begin index of Seq + /// Get end index of Seq pub fn end(&self) -> T { self.end } diff --git a/src/util.rs b/src/util.rs index 648b05bbe..181f735ba 100644 --- a/src/util.rs +++ b/src/util.rs @@ -153,6 +153,7 @@ impl From for ColorMap { /// - u16 /// pub trait HasAfEnum { + /// Return trait implmentors corresponding [DType](./enum.DType.html) fn get_af_dtype() -> DType; }