diff --git a/Cargo.toml b/Cargo.toml index 3950700d7..eb5ca7752 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "arrayfire" description = "ArrayFire is a high performance software library for parallel computing with an easy-to-use API. Its array based function set makes parallel programming simple. ArrayFire's multiple backends (CUDA, OpenCL and native CPU) make it platform independent and highly portable. A few lines of code in ArrayFire can replace dozens of lines of parallel computing code, saving you valuable time and lowering development costs. This crate provides Rust bindings for ArrayFire library." -version = "3.3.2" +version = "3.4.0" documentation = "http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html" homepage = "https://github.com/arrayfire/arrayfire" repository = "https://github.com/arrayfire/arrayfire-rust" diff --git a/README.md b/README.md index a55cf2315..87a1f4a6e 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ |:-------:|:-------:|:---:| | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/rust-linux)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/rust-linux/) | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/rust-windows)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/rust-windows/) | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/rust-osx)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/rust-osx/) | -[ArrayFire](https://github.com/arrayfire/arrayfire) is a high performance library for parallel computing with an easy-to-use API. It enables users to write scientific computing code that is portable across CUDA, OpenCL and CPU devices. This project provides Rust bindings for the ArrayFire library. The wrapper is currently compliant with ArrayFire 3.3 API. If you find any bugs, please report them [here](https://github.com/arrayfire/arrayfire-rust/issues). +[ArrayFire](https://github.com/arrayfire/arrayfire) is a high performance library for parallel computing with an easy-to-use API. It enables users to write scientific computing code that is portable across CUDA, OpenCL and CPU devices. This project provides Rust bindings for the ArrayFire library. The wrapper is currently compliant with ArrayFire 3.4 API. If you find any bugs, please report them [here](https://github.com/arrayfire/arrayfire-rust/issues). ## Documentation @@ -30,7 +30,7 @@ first. 3. Make sure you add the path to library files to your path environment variables. - On Linux & OSX: do `export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib` - On Windows: Add `%AF_PATH%\lib` to your PATH environment variable. -4. Add `arrayfire = "3.3.2"` to the dependencies section of your project's Cargo.toml file. +4. Add `arrayfire = "3.4.0"` to the dependencies section of your project's Cargo.toml file. Once step (4) is over, you should be able to use ArrayFire in your Rust project. If you find any bugs, please report them [here](https://github.com/arrayfire/arrayfire-rust/issues). @@ -58,12 +58,8 @@ cargo build let num_rows: u64 = 5; let num_cols: u64 = 3; let dims = Dim4::new(&[num_rows, num_cols, 1, 1]); -println!("Create a 5-by-3 matrix of random floats on the GPU"); -let a = match randu(dims, Aftype::F32) { - Ok(value) => value, - Err(error) => panic!("{}", error), -}; -print(&a); +let a = randu::(dims); +af_print!("Create a 5-by-3 matrix of random floats on the GPU", a); ``` ### Sample output @@ -72,9 +68,10 @@ print(&a); ~/p/arrayfire_rust> cargo run --example helloworld ... running 1 test -ArrayFire v3.2.0 (CUDA, 64-bit Mac OSX, build d8d4b38) -Platform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000 -[0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0 +ArrayFire v3.4.0 (CUDA, 64-bit Linux, build 10d9716) +Platform: CUDA Toolkit 7.5, Driver: 361.42 +[0] GeForce GT 650M, 2048 MB, CUDA Compute 3.0 + Create a 5-by-3 matrix of random floats on the GPU [5 3 1 1] 0.7402 0.4464 0.7762 @@ -82,7 +79,6 @@ Create a 5-by-3 matrix of random floats on the GPU 0.0390 0.1099 0.7140 0.9690 0.4702 0.3585 0.9251 0.5132 0.6814 - ... ``` diff --git a/arrayfire b/arrayfire index 5842ed251..10d9716a4 160000 --- a/arrayfire +++ b/arrayfire @@ -1 +1 @@ -Subproject commit 5842ed25195848653148fa9b3a8270255d83f5b8 +Subproject commit 10d9716a4aca5bc413d642be6295ce08614d5c36 diff --git a/build.rs b/build.rs index 3a4df9cca..1230ba6b8 100644 --- a/build.rs +++ b/build.rs @@ -6,7 +6,7 @@ use std::env; use std::fs; use rustc_serialize::json; use std::fs::OpenOptions; -use std::io::{ErrorKind, Read, Write}; +use std::io::{ErrorKind, Read}; use std::path::PathBuf; use std::process::Command; use std::convert::AsRef; diff --git a/src/algorithm/mod.rs b/src/algorithm/mod.rs index 98284daed..87379ed6e 100644 --- a/src/algorithm/mod.rs +++ b/src/algorithm/mod.rs @@ -1,9 +1,9 @@ extern crate libc; use array::Array; -use defines::AfError; +use defines::{AfError, BinaryOp}; use error::HANDLE_ERROR; -use self::libc::{c_int, c_uint, c_double}; +use self::libc::{c_int, uint8_t, c_uint, c_double}; type MutAfArray = *mut self::libc::c_longlong; type MutDouble = *mut self::libc::c_double; @@ -46,20 +46,15 @@ extern { fn af_sort_by_key(out_keys: MutAfArray, out_vals: MutAfArray, in_keys: AfArray, in_vals: AfArray, dim: c_uint, ascend: c_int) -> c_int; + + fn af_scan(out: MutAfArray, inp: AfArray, dim: c_int, op: uint8_t, inclusive: c_int) -> c_int; + fn af_scan_by_key(out: MutAfArray, key: AfArray, inp: AfArray, + dim: c_int, op: uint8_t, inclusive: c_int) -> c_int; } macro_rules! dim_reduce_func_def { - ($fn_name: ident, $ffi_name: ident) => ( - /// Reduction operation along specific dimension - /// - /// # Parameters - /// - /// - `input` - Input Array - /// - `dim` - Dimension along which the input Array will be reduced - /// - /// # Return Values - /// - /// Reduced Array + ($doc_str: expr, $fn_name: ident, $ffi_name: ident) => ( + #[doc=$doc_str] #[allow(unused_mut)] pub fn $fn_name(input: &Array, dim: i32) -> Array { unsafe { @@ -73,21 +68,272 @@ macro_rules! dim_reduce_func_def { ) } -dim_reduce_func_def!(sum, af_sum); -dim_reduce_func_def!(product, af_product); -dim_reduce_func_def!(min, af_min); -dim_reduce_func_def!(max, af_max); -dim_reduce_func_def!(all_true, af_all_true); -dim_reduce_func_def!(any_true, af_any_true); -dim_reduce_func_def!(count, af_count); -dim_reduce_func_def!(accum, af_accum); -dim_reduce_func_def!(diff1, af_diff1); -dim_reduce_func_def!(diff2, af_diff2); +dim_reduce_func_def!(" + Sum elements along a given dimension + + # Parameters + + - `input` - Input Array + - `dim` - Dimension along which the input Array will be reduced + + # Return Values + + Result Array after summing all elements along given dimension + + # Examples + + ```rust + use arrayfire::{Dim4, print, randu, sum}; + let dims = Dim4::new(&[5, 3, 1, 1]); + let a = randu::(dims); + print(&a); + let b = sum(&a, 0); + print(&b); + let c = sum(&a, 1); + print(&c); + ``` + ", + sum, af_sum); + +dim_reduce_func_def!(" + Compute product of elements along a given dimension + + # Parameters + + - `input` - Input Array + - `dim` - Dimension along which the input Array will be reduced + + # Return Values + + Result Array after multiplying all elements along given dimension + + # Examples + + ```rust + use arrayfire::{Dim4, print, randu, product}; + let dims = Dim4::new(&[5, 3, 1, 1]); + let a = randu::(dims); + print(&a); + let b = product(&a, 0); + print(&b); + let c = product(&a, 1); + print(&c); + ``` + ", product, af_product); + +dim_reduce_func_def!(" + Find minimum among elements of given dimension + + # Parameters + + - `input` - Input Array + - `dim` - Dimension along which the input Array will be reduced + + # Return Values + + Result Array after finding minimum among elements along a given dimension + + # Examples + + ```rust + use arrayfire::{Dim4, print, randu, min}; + let dims = Dim4::new(&[5, 3, 1, 1]); + let a = randu::(dims); + print(&a); + let b = min(&a, 0); + print(&b); + let c = min(&a, 1); + print(&c); + ``` + ", min, af_min); + +dim_reduce_func_def!(" + Find maximum among elements of given dimension + + # Parameters + + - `input` - Input Array + - `dim` - Dimension along which the input Array will be reduced + + # Return Values + + Result Array after finding maximum among elements along a given dimension + + # Examples + + ```rust + use arrayfire::{Dim4, print, randu, max}; + let dims = Dim4::new(&[5, 3, 1, 1]); + let a = randu::(dims); + print(&a); + let b = max(&a, 0); + print(&b); + let c = max(&a, 1); + print(&c); + ``` + ", max, af_max); + +dim_reduce_func_def!(" + Find if all of the values along a given dimension in the Array are true + + # Parameters + + - `input` - Input Array + - `dim` - Dimension along which the predicate is evaluated + + # Return Values + + Result Array that contains the result of `AND` operation of all elements along given dimension + + # Examples + + ```rust + use arrayfire::{Dim4, print, randu, all_true}; + let dims = Dim4::new(&[5, 3, 1, 1]); + let a = randu::(dims); + print(&a); + let b = all_true(&a, 0); + print(&b); + let c = all_true(&a, 1); + print(&c); + ``` + ", all_true, af_all_true); + +dim_reduce_func_def!(" + Find if any of the values along a given dimension in the Array are true + + # Parameters + + - `input` - Input Array + - `dim` - Dimension along which the predicate is evaluated + + # Return Values + + Result Array that contains the result of `OR` operation of all elements along given dimension + + # Examples + + ```rust + use arrayfire::{Dim4, print, randu, any_true}; + let dims = Dim4::new(&[5, 3, 1, 1]); + let a = randu::(dims); + print(&a); + let b = any_true(&a, 0); + print(&b); + let c = any_true(&a, 1); + print(&c); + ``` + ", any_true, af_any_true); -/// Reduction operation along specific dimension +dim_reduce_func_def!(" + Count number of non-zero elements along a given dimension + + # Parameters + + - `input` - Input Array + - `dim` - Dimension along which the non-zero elements are counted + + # Return Values + + Result Array with number of non-zero elements along a given dimension + + # Examples + + ```rust + use arrayfire::{Dim4, gt, print, randu, count}; + let dims = Dim4::new(&[5, 3, 1, 1]); + let cnst: f32 = 0.5; + let a = gt(&randu::(dims), &cnst, false); + print(&a); + let b = count(&a, 0); + print(&b); + let c = count(&a, 1); + print(&c); + ``` + ", count, af_count); + +dim_reduce_func_def!(" + Perform exclusive sum of elements along a given dimension + + # Parameters + + - `input` - Input Array + - `dim` - Dimension along which the exclusive scan operation is carried out + + # Return Values + + Result Array with exclusive sums of input Array elements along a given dimension + + # Examples + + ```rust + use arrayfire::{Dim4, print, randu, accum}; + let dims = Dim4::new(&[5, 3, 1, 1]); + let a = randu::(dims); + print(&a); + let b = accum(&a, 0); + print(&b); + let c = accum(&a, 1); + print(&c); + ``` + ", accum, af_accum); + +dim_reduce_func_def!(" + Calculate first order numerical difference along a given dimension + + # Parameters + + - `input` - Input Array + - `dim` - Dimension along which first order difference is calculated + + # Return Values + + Result Array with first order difference values + + # Examples + + ```rust + use arrayfire::{Dim4, print, randu, diff1}; + let dims = Dim4::new(&[5, 3, 1, 1]); + let a = randu::(dims); + print(&a); + let b = diff1(&a, 0); + print(&b); + let c = diff1(&a, 1); + print(&c); + ``` + ", diff1, af_diff1); + +dim_reduce_func_def!(" + Calculate second order numerical difference along a given dimension + + # Parameters + + - `input` - Input Array + - `dim` - Dimension along which second order difference is calculated + + # Return Values + + Result Array with second order difference values + + # Examples + + ```rust + use arrayfire::{Dim4, print, randu, diff2}; + let dims = Dim4::new(&[5, 3, 1, 1]); + let a = randu::(dims); + print(&a); + let b = diff2(&a, 0); + print(&b); + let c = diff2(&a, 1); + print(&c); + ``` + ", diff2, af_diff2); + +/// Sum along specific dimension using user specified value instead of `NAN` values /// /// Sum values of the `input` Array along `dim` dimension after replacing any `NAN` values in the -/// Array with `nanval` value. +/// Array with the value of the parameter `nanval`. /// /// # Parameters /// @@ -97,7 +343,7 @@ dim_reduce_func_def!(diff2, af_diff2); /// /// # Return Values /// -/// Reduced Array +/// Array that is reduced along given dimension via addition operation pub fn sum_nan(input: &Array, dim: i32, nanval: f64) -> Array { unsafe { let mut temp: i64 = 0; @@ -108,7 +354,7 @@ pub fn sum_nan(input: &Array, dim: i32, nanval: f64) -> Array { } } -/// Reduction operation along specific dimension +/// Product of elements along specific dimension using user specified value instead of `NAN` values /// /// Compute product of the values of the `input` Array along `dim` dimension after replacing any `NAN` values in the Array with `nanval` value. /// @@ -120,7 +366,7 @@ pub fn sum_nan(input: &Array, dim: i32, nanval: f64) -> Array { /// /// # Return Values /// -/// Reduced Array +/// Array that is reduced along given dimension via multiplication operation pub fn product_nan(input: &Array, dim: i32, nanval: f64) -> Array { unsafe { let mut temp: i64 = 0; @@ -132,17 +378,8 @@ pub fn product_nan(input: &Array, dim: i32, nanval: f64) -> Array { } macro_rules! all_reduce_func_def { - ($fn_name: ident, $ffi_name: ident) => ( - /// Reduction operation of all values - /// - /// # Parameters - /// - /// - `input` is the input Array - /// - /// # Return Values - /// - /// A tuple of reduction result. For non-complex data type Arrays, second value of tuple is - /// zero. + ($doc_str: expr, $fn_name: ident, $ffi_name: ident) => ( + #[doc=$doc_str] #[allow(unused_mut)] pub fn $fn_name(input: &Array) -> (f64, f64) { unsafe { @@ -157,15 +394,169 @@ macro_rules! all_reduce_func_def { ) } -all_reduce_func_def!(sum_all, af_sum_all); -all_reduce_func_def!(product_all, af_product_all); -all_reduce_func_def!(min_all, af_min_all); -all_reduce_func_def!(max_all, af_max_all); -all_reduce_func_def!(all_true_all, af_all_true_all); -all_reduce_func_def!(any_true_all, af_any_true_all); -all_reduce_func_def!(count_all, af_count_all); +all_reduce_func_def!(" + Sum all values of the Array + + # Parameters + + - `input` is the input Array + + # Return Values + + A tuple containing the summation result. + + Note: For non-complex data type Arrays, second value of tuple is zero. + + # Examples + + ```rust + use arrayfire::{Dim4, print, randu, sum_all}; + let dims = Dim4::new(&[5, 5, 1, 1]); + let a = randu::(dims); + print(&a); + println!(\"Result : {:?}\", sum_all(&a)); + ``` + ", sum_all, af_sum_all); + +all_reduce_func_def!(" + Product of all values of the Array + + # Parameters + + - `input` is the input Array + + # Return Values + + A tuple containing the product result. + + Note: For non-complex data type Arrays, second value of tuple is zero. + + # Examples -/// Reduction operation of all values + ```rust + use arrayfire::{Dim4, print, randu, product_all}; + let dims = Dim4::new(&[5, 5, 1, 1]); + let a = randu::(dims); + print(&a); + println!(\"Result : {:?}\", product_all(&a)); + ``` + ", product_all, af_product_all); + +all_reduce_func_def!(" + Find minimum among all values of the Array + + # Parameters + + - `input` is the input Array + + # Return Values + + A tuple containing the minimum value. + + Note: For non-complex data type Arrays, second value of tuple is zero. + + # Examples + + ```rust + use arrayfire::{Dim4, print, randu, min_all}; + let dims = Dim4::new(&[5, 5, 1, 1]); + let a = randu::(dims); + print(&a); + println!(\"Result : {:?}\", min_all(&a)); + ``` + ", min_all, af_min_all); + +all_reduce_func_def!(" + Find maximum among all values of the Array + + # Parameters + + - `input` is the input Array + + # Return Values + + A tuple containing the maximum value. + + Note: For non-complex data type Arrays, second value of tuple is zero. + + # Examples + + ```rust + use arrayfire::{Dim4, print, randu, max_all}; + let dims = Dim4::new(&[5, 5, 1, 1]); + let a = randu::(dims); + print(&a); + println!(\"Result : {:?}\", max_all(&a)); + ``` + ", max_all, af_max_all); + +all_reduce_func_def!(" + Find if all values of Array are non-zero + + # Parameters + + - `input` is the input Array + + # Return Values + + A tuple containing the result of `AND` operation on all values of Array. + + # Examples + + ```rust + use arrayfire::{Dim4, print, randu, all_true_all}; + let dims = Dim4::new(&[5, 5, 1, 1]); + let a = randu::(dims); + print(&a); + println!(\"Result : {:?}\", all_true_all(&a)); + ``` + ", all_true_all, af_all_true_all); + +all_reduce_func_def!(" + Find if any value of Array is non-zero + + # Parameters + + - `input` is the input Array + + # Return Values + + A tuple containing the result of `OR` operation on all values of Array. + + # Examples + + ```rust + use arrayfire::{Dim4, print, randu, any_true_all}; + let dims = Dim4::new(&[5, 5, 1, 1]); + let a = randu::(dims); + print(&a); + println!(\"Result : {:?}\", any_true_all(&a)); + ``` + ", any_true_all, af_any_true_all); + +all_reduce_func_def!(" + Count number of non-zero values in the Array + + # Parameters + + - `input` is the input Array + + # Return Values + + A tuple containing the count of non-zero values in the Array. + + # Examples + + ```rust + use arrayfire::{Dim4, print, randu, count_all}; + let dims = Dim4::new(&[5, 5, 1, 1]); + let a = randu::(dims); + print(&a); + println!(\"Result : {:?}\", count_all(&a)); + ``` + ", count_all, af_count_all); + +/// Sum all values using user provided value for `NAN` /// /// Sum all the values of the `input` Array after replacing any `NAN` values with `val`. /// @@ -177,8 +568,9 @@ all_reduce_func_def!(count_all, af_count_all); /// /// # Return Values /// -/// A tuple of reduction result. For non-complex data type Arrays, second value of tuple is -/// zero. +/// A tuple of summation result. +/// +/// Note: For non-complex data type Arrays, second value of tuple is zero. pub fn sum_nan_all(input: &Array, val: f64) -> (f64, f64) { unsafe { let mut real: f64 = 0.0; @@ -190,9 +582,9 @@ pub fn sum_nan_all(input: &Array, val: f64) -> (f64, f64) { } } -/// Reduction operation of all values +/// Product of all values using user provided value for `NAN` /// -/// Compute the product of all the values of the `input` Array after replacing any `NAN` values with `val`. +/// Compute the product of all the values of the `input` Array after replacing any `NAN` values with `val` /// /// # Parameters /// @@ -202,8 +594,9 @@ pub fn sum_nan_all(input: &Array, val: f64) -> (f64, f64) { /// /// # Return Values /// -/// A tuple of reduction result. For non-complex data type Arrays, second value of tuple is -/// zero. +/// A tuple of product result. +/// +/// Note: For non-complex data type Arrays, second value of tuple is zero. pub fn product_nan_all(input: &Array, val: f64) -> (f64, f64) { unsafe { let mut real: f64 = 0.0; @@ -216,19 +609,8 @@ pub fn product_nan_all(input: &Array, val: f64) -> (f64, f64) { } macro_rules! dim_ireduce_func_def { - ($fn_name: ident, $ffi_name: ident) => ( - /// Reduction operation along specific dimension - /// - /// # Parameters - /// - /// - `input` - Input Array - /// - `dim` - Dimension along which the input Array will be reduced - /// - /// # Return Values - /// - /// A tuple of Arrays: Reduced Array and Indices Array. - /// - /// The indices Array has the index of the result element along the reduction dimension. + ($doc_str: expr, $fn_name: ident, $ffi_name: ident) => ( + #[doc=$doc_str] #[allow(unused_mut)] pub fn $fn_name(input: &Array, dim: i32) -> (Array, Array) { unsafe { @@ -243,24 +625,35 @@ macro_rules! dim_ireduce_func_def { ) } -dim_ireduce_func_def!(imin, af_imin); -dim_ireduce_func_def!(imax, af_imax); +dim_ireduce_func_def!(" + Find minimum value along given dimension and their corresponding indices + + # Parameters + + - `input` - Input Array + - `dim` - Dimension along which the input Array will be reduced + + # Return Values + + A tuple of Arrays: Array minimum values and Array containing their index along the reduced dimension. + ", imin, af_imin); + +dim_ireduce_func_def!(" + Find maximum value along given dimension and their corresponding indices + + # Parameters + + - `input` - Input Array + - `dim` - Dimension along which the input Array will be reduced + + # Return Values + + A tuple of Arrays: Array maximum values and Array containing their index along the reduced dimension. + ", imax, af_imax); macro_rules! all_ireduce_func_def { - ($fn_name: ident, $ffi_name: ident) => ( - /// Reduction operation of all values - /// - /// # Parameters - /// - /// `input` - Input Array - /// - /// # Return Values - /// - /// A triplet of reduction result. - /// - /// The second value of the tuple is zero for non-complex data type Arrays. - /// - /// The third value of triplet is the index of result element from reduction operation. + ($doc_str: expr, $fn_name: ident, $ffi_name: ident) => ( + #[doc=$doc_str] #[allow(unused_mut)] pub fn $fn_name(input: &Array) -> (f64, f64, u32) { unsafe { @@ -276,8 +669,36 @@ macro_rules! all_ireduce_func_def { ) } -all_ireduce_func_def!(imin_all, af_imin_all); -all_ireduce_func_def!(imax_all, af_imax_all); +all_ireduce_func_def!(" + Find minimum and it's index in the whole Array + + # Parameters + + `input` - Input Array + + # Return Values + + A triplet with + + * minimum element of Array in the first component. + * second component of value zero if Array is of non-complex type. + * index of minimum element in the third component. + ", imin_all, af_imin_all); +all_ireduce_func_def!(" + Find maximum and it's index in the whole Array + + # Parameters + + `input` - Input Array + + # Return Values + + A triplet with + + - maximum element of Array in the first component. + - second component of value zero if Array is of non-complex type. + - index of maximum element in the third component. + ", imax_all, af_imax_all); /// Locate the indices of non-zero elements. /// @@ -447,4 +868,52 @@ pub fn set_intersect(first: &Array, second: &Array, is_unique: bool) -> Array { HANDLE_ERROR(AfError::from(err_val)); Array::from(temp) } -} \ No newline at end of file +} + +/// Generalized scan +/// +/// # Parameters +/// +/// - `input` is the data on which scan is to be performed +/// - `dim` is the dimension along which scan operation is to be performed +/// - `op` takes value of [BinaryOp](./enum.BinaryOp.html) enum indicating +/// the type of scan operation +/// - `inclusive` says if inclusive/exclusive scan is to be performed +/// +/// # Return Values +/// +/// Output Array of scanned input +pub fn scan(input: &Array, dim: i32, op: BinaryOp, inclusive: bool) -> Array { + unsafe { + let mut temp : i64 = 0; + let err_val = af_scan(&mut temp as MutAfArray, input.get() as AfArray, dim as c_int, + op as uint8_t, inclusive as c_int); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } +} + +/// Generalized scan by key +/// +/// # Parameters +/// +/// - `key` is the key Array +/// - `input` is the data on which scan is to be performed +/// - `dim` is the dimension along which scan operation is to be performed +/// - `op` takes value of [BinaryOp](./enum.BinaryOp.html) enum indicating +/// the type of scan operation +/// - `inclusive` says if inclusive/exclusive scan is to be performed +/// +/// # Return Values +/// +/// Output Array of scanned input +pub fn scan_by_key(key: &Array, input: &Array, dim: i32, op: BinaryOp, inclusive: bool) -> Array { + unsafe { + let mut temp : i64 = 0; + let err_val = af_scan_by_key(&mut temp as MutAfArray, + key.get() as AfArray, input.get() as AfArray, dim as c_int, + op as uint8_t, inclusive as c_int); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } +} diff --git a/src/arith/mod.rs b/src/arith/mod.rs index 95d710cdd..6a49a68ad 100644 --- a/src/arith/mod.rs +++ b/src/arith/mod.rs @@ -42,6 +42,7 @@ extern { fn af_bitshiftr(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; fn af_minof(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; fn af_maxof(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; + fn af_clamp(out: MutAfArray, inp: AfArray, lo: AfArray, hi: AfArray, batch: c_int) -> c_int; fn af_not(out: MutAfArray, arr: AfArray) -> c_int; fn af_abs(out: MutAfArray, arr: AfArray) -> c_int; @@ -111,7 +112,10 @@ impl<'f> Not for &'f Array { } macro_rules! unary_func { - ($fn_name: ident, $ffi_fn: ident) => ( + ($doc_str: expr, $fn_name: ident, $ffi_fn: ident) => ( + #[doc=$doc_str] + /// + /// This is an element wise unary operation. #[allow(unused_mut)] pub fn $fn_name(input: &Array) -> Array { unsafe { @@ -124,50 +128,53 @@ macro_rules! unary_func { ) } -unary_func!(abs, af_abs); -unary_func!(arg, af_arg); -unary_func!(sign, af_sign); -unary_func!(round, af_round); -unary_func!(trunc, af_trunc); -unary_func!(floor, af_floor); -unary_func!(ceil, af_ceil); -unary_func!(sin, af_sin); -unary_func!(cos, af_cos); -unary_func!(tan, af_tan); -unary_func!(asin, af_asin); -unary_func!(acos, af_acos); -unary_func!(atan, af_atan); -unary_func!(cplx, af_cplx); -unary_func!(real, af_real); -unary_func!(imag, af_imag); -unary_func!(conjg, af_conjg); -unary_func!(sinh, af_sinh); -unary_func!(cosh, af_cosh); -unary_func!(tanh, af_tanh); -unary_func!(asinh, af_asinh); -unary_func!(acosh, af_acosh); -unary_func!(atanh, af_atanh); -unary_func!(pow2, af_pow2); -unary_func!(exp, af_exp); -unary_func!(sigmoid, af_sigmoid); -unary_func!(expm1, af_expm1); -unary_func!(erf, af_erf); -unary_func!(erfc, af_erfc); -unary_func!(log, af_log); -unary_func!(log1p, af_log1p); -unary_func!(log10, af_log10); -unary_func!(log2, af_log2); -unary_func!(sqrt, af_sqrt); -unary_func!(cbrt, af_cbrt); -unary_func!(factorial, af_factorial); -unary_func!(tgamma, af_tgamma); -unary_func!(lgamma, af_lgamma); -unary_func!(iszero, af_iszero); -unary_func!(isinf, af_isinf); -unary_func!(isnan, af_isnan); +unary_func!("Computes absolute value", abs, af_abs); +unary_func!("Computes phase value", arg, af_arg); +unary_func!("Computes the sign of input Array values", sign, af_sign); +unary_func!("Round the values in an Array", round, af_round); +unary_func!("Truncate the values in an Array", trunc, af_trunc); +unary_func!("Floor the values in an Array", floor, af_floor); +unary_func!("Ceil the values in an Array", ceil, af_ceil); +unary_func!("Compute sin", sin, af_sin); +unary_func!("Compute cos", cos, af_cos); +unary_func!("Compute tan", tan, af_tan); +unary_func!("Compute asin", asin, af_asin); +unary_func!("Compute acos", acos, af_acos); +unary_func!("Compute atan", atan, af_atan); +unary_func!("Create a complex Array from real Array", cplx, af_cplx); +unary_func!("Extract real values from a complex Array", real, af_real); +unary_func!("Extract imaginary values from a complex Array", imag, af_imag); +unary_func!("Compute the complex conjugate", conjg, af_conjg); +unary_func!("Compute sinh", sinh, af_sinh); +unary_func!("Compute cosh", cosh, af_cosh); +unary_func!("Compute tanh", tanh, af_tanh); +unary_func!("Compute asinh", asinh, af_asinh); +unary_func!("Compute acosh", acosh, af_acosh); +unary_func!("Compute atanh", atanh, af_atanh); +unary_func!("Compute two raised to the power of value", pow2, af_pow2); +unary_func!("Compute e raised to the power of value", exp, af_exp); +unary_func!("Compute sigmoid function", sigmoid, af_sigmoid); +unary_func!("Compute e raised to the power of value -1", expm1, af_expm1); +unary_func!("Compute error function value", erf, af_erf); +unary_func!("Compute the complementary error function value", erfc, af_erfc); +unary_func!("Compute the natural logarithm", log, af_log); +unary_func!("Compute the logarithm of input Array + 1", log1p, af_log1p); +unary_func!("Compute logarithm base 10", log10, af_log10); +unary_func!("Compute logarithm base 2", log2, af_log2); +unary_func!("Compute the square root", sqrt, af_sqrt); +unary_func!("Compute the cube root", cbrt, af_cbrt); +unary_func!("Compute the factorial", factorial, af_factorial); +unary_func!("Compute gamma function", tgamma, af_tgamma); +unary_func!("Compute the logarithm of absolute values of gamma function", lgamma, af_lgamma); +unary_func!("Check if values are zero", iszero, af_iszero); +unary_func!("Check if values are infinity", isinf, af_isinf); +unary_func!("Check if values are NaN", isnan, af_isnan); macro_rules! binary_func { - ($fn_name: ident, $ffi_fn: ident) => ( + ($doc_str: expr, $fn_name: ident, $ffi_fn: ident) => ( + #[doc=$doc_str] + /// + /// This is an element wise binary operation. #[allow(unused_mut)] pub fn $fn_name(lhs: &Array, rhs: &Array) -> Array { unsafe { @@ -182,15 +189,15 @@ macro_rules! binary_func { ) } -binary_func!(bitand, af_bitand); -binary_func!(bitor, af_bitor); -binary_func!(bitxor, af_bitxor); -binary_func!(neq, af_neq); -binary_func!(and, af_and); -binary_func!(or, af_or); -binary_func!(minof, af_minof); -binary_func!(maxof, af_maxof); -binary_func!(hypot, af_hypot); +binary_func!("Elementwise AND(bit) operation of two Arrays", bitand, af_bitand); +binary_func!("Elementwise OR(bit) operation of two Arrays", bitor, af_bitor); +binary_func!("Elementwise XOR(bit) operation of two Arrays", bitxor, af_bitxor); +binary_func!("Elementwise not equals comparison of two Arrays", neq, af_neq); +binary_func!("Elementwise logical and operation of two Arrays", and, af_and); +binary_func!("Elementwise logical or operation of two Arrays", or, af_or); +binary_func!("Elementwise minimum operation of two Arrays", minof, af_minof); +binary_func!("Elementwise maximum operation of two Arrays", maxof, af_maxof); +binary_func!("Compute length of hypotenuse of two Arrays", hypot, af_hypot); pub trait Convertable { fn convert(&self) -> Array; @@ -221,7 +228,7 @@ impl Convertable for Array { } macro_rules! overloaded_binary_func { - ($fn_name: ident, $help_name: ident, $ffi_name: ident) => ( + ($doc_str: expr, $fn_name: ident, $help_name: ident, $ffi_name: ident) => ( fn $help_name(lhs: &Array, rhs: &Array, batch: bool) -> Array { unsafe { let mut temp: i64 = 0; @@ -233,6 +240,26 @@ macro_rules! overloaded_binary_func { } } + #[doc=$doc_str] + /// + /// This is a binary elementwise operation. + /// + ///# Parameters + /// + /// - `arg1`is an argument that implements an internal trait `Convertable`. + /// - `arg2`is an argument that implements an internal trait `Convertable`. + /// - `batch` is an boolean that indicates if the current operation is an batch operation. + /// + /// Both parameters `arg1` and `arg2` can be either an Array or a value of rust integral + /// type. + /// + ///# Return Values + /// + /// An Array with results of the binary operation. + /// + ///# Note + /// + /// The trait `Convertable` essentially translates to a scalar native type on rust or Array. pub fn $fn_name (arg1: &T, arg2: &U, batch: bool) -> Array where T: Convertable, U: Convertable { let lhs = arg1.convert(); let rhs = arg2.convert(); @@ -253,23 +280,70 @@ macro_rules! overloaded_binary_func { // thanks to Umar Arshad for the idea on how to // implement overloaded function -overloaded_binary_func!(add, add_helper, af_add); -overloaded_binary_func!(sub, sub_helper, af_sub); -overloaded_binary_func!(mul, mul_helper, af_mul); -overloaded_binary_func!(div, div_helper, af_div); -overloaded_binary_func!(rem, rem_helper, af_rem); -overloaded_binary_func!(shiftl, shiftl_helper, af_bitshiftl); -overloaded_binary_func!(shiftr, shiftr_helper, af_bitshiftr); -overloaded_binary_func!(lt, lt_helper, af_lt); -overloaded_binary_func!(gt, gt_helper, af_gt); -overloaded_binary_func!(le, le_helper, af_le); -overloaded_binary_func!(ge, ge_helper, af_ge); -overloaded_binary_func!(eq, eq_helper, af_eq); -overloaded_binary_func!(modulo, modulo_helper, af_mod); -overloaded_binary_func!(atan2, atan2_helper, af_atan2); -overloaded_binary_func!(cplx2, cplx2_helper, af_cplx2); -overloaded_binary_func!(root, root_helper, af_root); -overloaded_binary_func!(pow, pow_helper, af_pow); +overloaded_binary_func!("Addition of two Arrays", add, add_helper, af_add); +overloaded_binary_func!("Subtraction of two Arrays", sub, sub_helper, af_sub); +overloaded_binary_func!("Multiplication of two Arrays", mul, mul_helper, af_mul); +overloaded_binary_func!("Division of two Arrays", div, div_helper, af_div); +overloaded_binary_func!("Compute remainder from two Arrays", rem, rem_helper, af_rem); +overloaded_binary_func!("Compute left shift", shiftl, shiftl_helper, af_bitshiftl); +overloaded_binary_func!("Compute right shift", shiftr, shiftr_helper, af_bitshiftr); +overloaded_binary_func!("Perform `less than` comparison operation", lt, lt_helper, af_lt); +overloaded_binary_func!("Perform `greater than` comparison operation", gt, gt_helper, af_gt); +overloaded_binary_func!("Perform `less than equals` comparison operation", le, le_helper, af_le); +overloaded_binary_func!("Perform `greater than equals` comparison operation", ge, ge_helper, af_ge); +overloaded_binary_func!("Perform `equals` comparison operation", eq, eq_helper, af_eq); +overloaded_binary_func!("Compute modulo of two Arrays", modulo, modulo_helper, af_mod); +overloaded_binary_func!("Calculate atan2 of two Arrays", atan2, atan2_helper, af_atan2); +overloaded_binary_func!("Create complex array from two Arrays", cplx2, cplx2_helper, af_cplx2); +overloaded_binary_func!("Compute root", root, root_helper, af_root); +overloaded_binary_func!("Computer power", pow, pow_helper, af_pow); + +/// Clamp the values of Array +/// +/// # Parameters +/// +/// - `arg1`is an argument that implements an internal trait `Convertable`. +/// - `arg2`is an argument that implements an internal trait `Convertable`. +/// - `batch` is an boolean that indicates if the current operation is an batch operation. +/// +/// Both parameters `arg1` and `arg2` can be either an Array or a value of rust integral +/// type. +/// +/// # Return Values +/// +/// An Array with results of the binary operation. +/// +/// # Note +/// +/// The trait `Convertable` essentially translates to a scalar native type on rust or Array. +pub fn clamp (input: &Array, arg1: &T, arg2: &U, batch: bool) -> Array + where T: Convertable, U: Convertable +{ + let clamp_helper = |lo: &Array, hi: &Array| { + unsafe { + let mut temp: i64 = 0; + let err_val = af_clamp(&mut temp as MutAfArray, input.get() as AfArray, + lo.get() as AfArray, hi.get() as AfArray, + batch as c_int); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } + }; + + let lo = arg1.convert(); + let hi = arg2.convert(); + match (lo.is_scalar(), hi.is_scalar()) { + ( true, false) => { + let l = tile(&lo, hi.dims()); + clamp_helper(&l, &hi) + }, + (false, true) => { + let r = tile(&hi, lo.dims()); + clamp_helper(&lo, &r) + }, + _ => clamp_helper(&lo, &hi), + } +} macro_rules! arith_scalar_func { ($rust_type: ty, $op_name:ident, $fn_name: ident, $ffi_fn: ident) => ( @@ -281,7 +355,22 @@ macro_rules! arith_scalar_func { unsafe { let mut temp: i64 = 0; let err_val = $ffi_fn(&mut temp as MutAfArray, self.get() as AfArray, - cnst_arr.get() as AfArray, 0); + cnst_arr.get() as AfArray, 0); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } + } + } + + impl $op_name<$rust_type> for Array { + type Output = Array; + + fn $fn_name(self, rhs: $rust_type) -> Array { + let cnst_arr = constant(rhs, self.dims()); + unsafe { + let mut temp: i64 = 0; + let err_val = $ffi_fn(&mut temp as MutAfArray, self.get() as AfArray, + cnst_arr.get() as AfArray, 0); HANDLE_ERROR(AfError::from(err_val)); Array::from(temp) } diff --git a/src/array.rs b/src/array.rs index a47851d29..aa6df0b46 100644 --- a/src/array.rs +++ b/src/array.rs @@ -4,19 +4,21 @@ use dim4::Dim4; use defines::{AfError, DType, Backend}; use error::HANDLE_ERROR; use util::HasAfEnum; -use self::libc::{uint8_t, c_void, c_int, c_uint, c_longlong}; +use self::libc::{uint8_t, c_void, c_int, c_uint, c_longlong, c_char}; +use std::ffi::CString; type MutAfArray = *mut self::libc::c_longlong; type MutDouble = *mut self::libc::c_double; type MutUint = *mut self::libc::c_uint; type AfArray = self::libc::c_longlong; type DimT = self::libc::c_longlong; +type MutVoidPtr = *mut self::libc::c_ulonglong; +type VoidPtr = self::libc::c_ulonglong; // Some unused functions from array.h in C-API of ArrayFire // af_create_handle // af_copy_array // af_write_array -// af_get_data_ptr // af_get_data_ref_count #[allow(dead_code)] @@ -63,6 +65,12 @@ extern { fn af_eval(arr: AfArray) -> c_int; + fn af_eval_multiple(num: c_int, arrays: *const AfArray) -> c_int; + + fn af_set_manual_eval_flag(flag: c_int) -> c_int; + + fn af_get_manual_eval_flag(flag: *mut c_int) -> c_int; + fn af_retain_array(out: MutAfArray, arr: AfArray) -> c_int; fn af_copy_array(out: MutAfArray, arr: AfArray) -> c_int; @@ -71,6 +79,8 @@ extern { fn af_print_array(arr: AfArray) -> c_int; + fn af_print_array_gen(exp: *const c_char, arr: AfArray, precision: c_int) -> c_int; + fn af_cast(out: MutAfArray, arr: AfArray, aftype: uint8_t) -> c_int; fn af_get_backend_id(backend: *mut c_int, input: AfArray) -> c_int; @@ -79,7 +89,7 @@ extern { fn af_create_strided_array(arr: MutAfArray, data: *const c_void, offset: DimT, ndims: c_uint, dims: *const DimT, strides: *const DimT, - aftype: uint8_t) -> c_int; + aftype: uint8_t, stype: uint8_t) -> c_int; fn af_get_strides(s0: *mut DimT, s1: *mut DimT, s2: *mut DimT, s3: *mut DimT, arr: AfArray) -> c_int; @@ -89,6 +99,14 @@ extern { fn af_is_linear(result: *mut c_int, arr: AfArray) -> c_int; fn af_is_owner(result: *mut c_int, arr: AfArray) -> c_int; + + fn af_is_sparse(result: *mut c_int, arr: AfArray) -> c_int; + + fn af_lock_array(arr: AfArray) -> c_int; + + fn af_unlock_array(arr: AfArray) -> c_int; + + fn af_get_device_ptr(ptr: MutVoidPtr, arr: AfArray) -> c_int; } /// A multidimensional data container @@ -99,8 +117,8 @@ pub struct Array { } macro_rules! is_func { - ($fn_name: ident, $ffi_fn: ident) => ( - /// Checks if the Array is of specific format/data type. + ($doc_str: expr, $fn_name: ident, $ffi_fn: ident) => ( + #[doc=$doc_str] pub fn $fn_name(&self) -> bool { unsafe { let mut ret_val: i32 = 0; @@ -117,7 +135,7 @@ impl Array { /// /// # Examples /// - /// ``` + /// ```rust /// use arrayfire::{Array, Dim4, print}; /// let values: [f32; 3] = [1.0, 2.0, 3.0]; /// let indices = Array::new(&values, Dim4::new(&[3, 1, 1, 1])); @@ -153,7 +171,7 @@ impl Array { dims.ndims() as c_uint, dims.get().as_ptr() as * const c_longlong, strides.get().as_ptr() as * const c_longlong, - aftype as uint8_t); + aftype as uint8_t, 1); HANDLE_ERROR(AfError::from(err_val)); Array::from(temp) } @@ -296,20 +314,20 @@ impl Array { } } - is_func!(is_empty, af_is_empty); - is_func!(is_scalar, af_is_scalar); - is_func!(is_row, af_is_row); - is_func!(is_column, af_is_column); - is_func!(is_vector, af_is_vector); - is_func!(is_complex, af_is_complex); - is_func!(is_double, af_is_double); - is_func!(is_single, af_is_single); - is_func!(is_real, af_is_real); - is_func!(is_floating, af_is_floating); - is_func!(is_integer, af_is_integer); - is_func!(is_bool, af_is_bool); - is_func!(is_linear, af_is_linear); - is_func!(is_owner, af_is_owner); + is_func!("Check if Array is empty", is_empty, af_is_empty); + is_func!("Check if Array is scalar", is_scalar, af_is_scalar); + is_func!("Check if Array is a row", is_row, af_is_row); + is_func!("Check if Array is a column", is_column, af_is_column); + is_func!("Check if Array is a vector", is_vector, af_is_vector); + is_func!("Check if Array is of complex type", is_complex, af_is_complex); + is_func!("Check if Array's numerical type is of double precision", is_double, af_is_double); + is_func!("Check if Array's numerical type is of single precision", is_single, af_is_single); + is_func!("Check if Array is of real type", is_real, af_is_real); + is_func!("Check if Array is of single precision", is_floating, af_is_floating); + is_func!("Check if Array is of integral type", is_integer, af_is_integer); + is_func!("Check if Array is of boolean type", is_bool, af_is_bool); + is_func!("Check if Array's memory layout is continuous and one dimensional", is_linear, af_is_linear); + is_func!("Check if Array's memory is owned by it and not a view of another Array", is_owner, af_is_owner); /// Cast the Array data type to `target_type` pub fn cast(&self) -> Array { @@ -321,6 +339,49 @@ impl Array { Array::from(temp) } } + + /// Find if the current array is sparse + pub fn is_sparse(&self) -> bool { + unsafe { + let mut temp: i32 = 0; + let err_val = af_is_sparse(&mut temp as *mut c_int, self.handle as AfArray); + HANDLE_ERROR(AfError::from(err_val)); + temp > 0 + } + } + + /// Lock the device buffer in the memory manager + /// + /// Locked buffers are not freed by memory manager until unlock is called. + pub fn lock(&self) { + unsafe { + let err_val = af_lock_array(self.handle as AfArray); + HANDLE_ERROR(AfError::from(err_val)); + } + } + + /// Unlock the device buffer in the memory manager + /// + /// This function will give back the control over the device pointer to the + /// memory manager. + pub fn unlock(&self) { + unsafe { + let err_val = af_unlock_array(self.handle as AfArray); + HANDLE_ERROR(AfError::from(err_val)); + } + } + + /// Get the device pointer and lock the buffer in memory manager + /// + /// The device pointer is not freed by memory manager until unlock is called. + pub fn device_ptr(&self) -> u64 { + unsafe { + let mut temp: u64 = 0; + let err_val = af_get_device_ptr(&mut temp as MutVoidPtr, self.handle as AfArray); + HANDLE_ERROR(AfError::from(err_val)); + temp + } + } } /// Used for creating Array object from native resource id @@ -359,19 +420,23 @@ impl Drop for Array { /// Print data in the Array /// +/// # Parameters +/// +/// - `input` is the Array to be printed +/// /// # Examples /// -/// ``` +/// ```rust /// use arrayfire::{Dim4, print, randu}; /// println!("Create a 5-by-3 matrix of random floats on the GPU"); -/// let dims = Dim4::new(&[3, 1, 1, 1]); +/// let dims = Dim4::new(&[5, 3, 1, 1]); /// let a = randu::(dims); /// print(&a); /// ``` /// /// The sample output will look like below: /// -/// ```bash +/// ```text /// [5 3 1 1] /// 0.7402 0.4464 0.7762 /// 0.9210 0.6673 0.2948 @@ -380,8 +445,102 @@ impl Drop for Array { /// 0.9251 0.5132 0.6814 /// ``` pub fn print(input: &Array) { + let emptystring = CString::new("").unwrap(); + unsafe { + let err_val = af_print_array_gen(emptystring.to_bytes_with_nul().as_ptr() as *const c_char, + input.get() as AfArray, 4); + HANDLE_ERROR(AfError::from(err_val)); + } +} + +/// Generalized Array print function +/// +/// Use this function to print Array data with arbitrary preicsion +/// +/// # Parameters +/// +/// - `msg` is message to be printed before printing the Array data +/// - `input` is the Array to be printed +/// - `precision` is data precision with which Array has to be printed +/// +/// # Examples +/// +/// ```rust +/// use arrayfire::{Dim4, print_gen, randu}; +/// 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_gen(String::from("Random Array"), &a, Some(6)); +/// ``` +/// +/// The sample output will look like below: +/// +/// ```text +/// Random Array +/// +/// [5 3 1 1] +/// 0.740276 0.446440 0.776202 +/// 0.921094 0.667321 0.294810 +/// 0.039014 0.109939 0.714090 +/// 0.969058 0.470269 0.358590 +/// 0.925181 0.513225 0.681451 +/// ``` +pub fn print_gen(msg: String, input: &Array, precision: Option) { + let emptystring = CString::new(msg.as_bytes()).unwrap(); + unsafe { + let err_val = af_print_array_gen(emptystring.to_bytes_with_nul().as_ptr() as *const c_char, + input.get() as AfArray, + match precision {Some(p)=>p, None=>4} as c_int); + HANDLE_ERROR(AfError::from(err_val)); + } +} + +/// evaluate multiple arrays +/// +/// Use this function to evaluate multiple arrays in single call +/// +/// # Parameters +/// +/// - `inputs` are the list of arrays to be evaluated +pub fn eval_multiple(inputs: Vec<&Array>) { + unsafe { + let mut v = Vec::new(); + for i in inputs { + v.push(i.get()); + } + + let err_val = af_eval_multiple(v.len() as c_int, v.as_ptr() as *const AfArray); + HANDLE_ERROR(AfError::from(err_val)); + } +} + +/// Set eval flag value +/// +/// This function can be used to toggle on/off the manual evaluation of arrays. +/// +/// # Parameters +/// +/// - `flag` is a boolean value indicating manual evaluation setting +pub fn set_manual_eval(flag: bool) { + unsafe { + let err_val = af_set_manual_eval_flag(flag as c_int); + HANDLE_ERROR(AfError::from(err_val)); + } +} + +/// Get eval flag value +/// +/// This function can be used to find out if manual evaluation of arrays is +/// turned on or off. +/// +/// # Return Values +/// +/// A boolean indicating manual evaluation setting. +pub fn is_eval_manual() -> bool { unsafe { - let err_val = af_print_array(input.get() as AfArray); + let mut ret_val: i32 = 0; + let err_val = af_get_manual_eval_flag(&mut ret_val as *mut c_int); HANDLE_ERROR(AfError::from(err_val)); + ret_val > 0 } } diff --git a/src/backend.rs b/src/backend.rs index 26d5b2ba0..df434e1b8 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -42,12 +42,12 @@ pub fn get_available_backends() -> Vec { let mut temp: i32 = 0; let err_val = af_get_available_backends(&mut temp as *mut c_int); HANDLE_ERROR(AfError::from(err_val)); - + let mut b = Vec::new(); if temp & 0b0100 == 0b0100 { b.push(Backend::OPENCL); } if temp & 0b0010 == 0b0010 { b.push(Backend::CUDA); } if temp & 0b0001 == 0b0001 { b.push(Backend::CPU); } - + b } } @@ -67,4 +67,4 @@ pub fn get_active_backend() -> Backend { _ => panic!("Invalid backend retrieved, undefined behavior."), } } -} \ No newline at end of file +} diff --git a/src/data/mod.rs b/src/data/mod.rs index 6c8b6509b..23fbfbf24 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -38,12 +38,6 @@ extern { fn af_iota(out: MutAfArray, ndims: c_uint, dims: *const DimT, t_ndims: c_uint, tdims: *const DimT, afdtype: uint8_t) -> c_int; - fn af_randu(out: MutAfArray, ndims: c_uint, dims: *const DimT, afdtype: uint8_t) -> c_int; - fn af_randn(out: MutAfArray, ndims: c_uint, dims: *const DimT, afdtype: uint8_t) -> c_int; - - fn af_set_seed(seed: Uintl) -> c_int; - fn af_get_seed(seed: *mut Uintl) -> c_int; - fn af_identity(out: MutAfArray, ndims: c_uint, dims: *const DimT, afdtype: uint8_t) -> c_int; fn af_diag_create(out: MutAfArray, arr: AfArray, num: c_int) -> c_int; fn af_diag_extract(out: MutAfArray, arr: AfArray, num: c_int) -> c_int; @@ -250,46 +244,28 @@ pub fn iota(dims: Dim4, tdims: Dim4) -> Array { } } -/// Set seed for random number generation -pub fn set_seed(seed: u64) { - unsafe { - let err_val = af_set_seed(seed as Uintl); - HANDLE_ERROR(AfError::from(err_val)); - } -} - -/// Get the seed of random number generator +/// Create an identity array with 1's in diagonal +/// +/// # Parameters +/// +/// - `dims` is the output Array dimensions +/// +/// # Return Values +/// +/// Identity matrix #[allow(unused_mut)] -pub fn get_seed() -> u64 { +pub fn identity(dims: Dim4) -> Array { unsafe { - let mut temp: u64 = 0; - let err_val = af_get_seed(&mut temp as *mut Uintl); + let aftype = T::get_af_dtype(); + let mut temp: i64 = 0; + let err_val = af_identity(&mut temp as MutAfArray, + dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, + aftype as uint8_t); HANDLE_ERROR(AfError::from(err_val)); - temp + Array::from(temp) } } -macro_rules! data_gen_def { - ($fn_name:ident, $ffi_name: ident) => ( - #[allow(unused_mut)] - pub fn $fn_name(dims: Dim4) -> Array { - unsafe { - let aftype = T::get_af_dtype(); - let mut temp: i64 = 0; - let err_val = $ffi_name(&mut temp as MutAfArray, - dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, - aftype as uint8_t); - HANDLE_ERROR(AfError::from(err_val)); - Array::from(temp) - } - } - ) -} - -data_gen_def!(randu, af_randu); -data_gen_def!(randn, af_randn); -data_gen_def!(identity, af_identity); - /// Create a diagonal matrix /// /// # Parameters @@ -380,7 +356,17 @@ pub fn join_many(dim: i32, inputs: Vec<&Array>) -> Array { } macro_rules! data_func_def { - ($fn_name:ident, $ffi_name: ident) => ( + ($doc_str: expr, $fn_name:ident, $ffi_name: ident) => ( + #[doc=$doc_str] + /// + ///# Parameters + /// + /// - `input` is the input Array + /// - `dims` is the target(output) dimensions + /// + ///# Return Values + /// + /// An Array with modified data. #[allow(unused_mut)] pub fn $fn_name(input: &Array, dims: Dim4) -> Array { unsafe { @@ -395,9 +381,9 @@ macro_rules! data_func_def { ) } -data_func_def!(tile, af_tile); -data_func_def!(reorder, af_reorder); -data_func_def!(shift, af_shift); +data_func_def!("Tile the input array along specified dimension", tile, af_tile); +data_func_def!("Reorder the array in specified order", reorder, af_reorder); +data_func_def!("Circular shift of values along specified dimension", shift, af_shift); /// Change the shape of the Array /// @@ -495,7 +481,7 @@ pub fn upper(input: &Array, is_unit_diag: bool) -> Array { /// This function does the C-equivalent of the following statement, except that the operation /// happens on a GPU for all elements simultaneously. /// -/// ```ignore +/// ```text /// c = cond ? a : b; /// where cond, a & b are all objects of type Array /// ``` /// @@ -526,7 +512,7 @@ pub fn select(a: &Array, cond: &Array, b: &Array) -> Array { /// This function does the C-equivalent of the following statement, except that the operation /// happens on a GPU for all elements simultaneously. /// -/// ```ignore +/// ```text /// c = cond ? a : b; /// where a is a scalar(f64) and b is Array /// ``` /// @@ -557,7 +543,7 @@ pub fn selectl(a: f64, cond: &Array, b: &Array) -> Array { /// This function does the C-equivalent of the following statement, except that the operation /// happens on a GPU for all elements simultaneously. /// -/// ```ignore +/// ```text /// c = cond ? a : b; /// where a is Array and b is a scalar(f64) /// ``` /// @@ -588,7 +574,7 @@ pub fn selectr(a: &Array, cond: &Array, b: f64) -> Array { /// This function does the C-equivalent of the following statement, except that the operation /// happens on a GPU for all elements simultaneously. /// -/// ```ignore +/// ```text /// a = cond ? a : b; /// where cond, a & b are all objects of type Array /// ``` /// @@ -615,7 +601,7 @@ pub fn replace(a: &mut Array, cond: &Array, b: &Array) { /// This function does the C-equivalent of the following statement, except that the operation /// happens on a GPU for all elements simultaneously. /// -/// ```ignore +/// ```text /// a = cond ? a : b; /// where cond, a are Arrays and b is scalar(f64) /// ``` /// @@ -635,4 +621,4 @@ pub fn replace_scalar(a: &mut Array, cond: &Array, b: f64) { let err_val = af_replace_scalar(a.get() as AfArray, cond.get() as AfArray, b as c_double); HANDLE_ERROR(AfError::from(err_val)); } -} \ No newline at end of file +} diff --git a/src/defines.rs b/src/defines.rs index 669f2e053..e74337d3b 100644 --- a/src/defines.rs +++ b/src/defines.rs @@ -147,6 +147,18 @@ pub enum InterpType { BILINEAR= 2, /// Cubic interpolation method CUBIC = 3, + /// Floor indexed + LOWER = 4, + /// Linear interpolation with cosine smoothing + LINEAR_COSINE = 5, + /// Bilinear interpolation with cosine smoothing + BILINEAR_COSINE = 6, + /// Bicubic interpolation + BICUBIC = 7, + /// Cubic interpolation with Catmull-Rom splines + CUBIC_SPLINE = 8, + /// Bicubic interpolation with Catmull-Rom splines + BICUBIC_SPLINE = 9 } /// Helps determine how to pad kernels along borders @@ -333,3 +345,55 @@ pub enum MarkerType { PLUS = 6, STAR = 7 } + +/// Image moment types +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum MomentType { + M00 = 1, // 1<<0 + M01 = 2, // 1<<1 + M10 = 4, // 1<<2 + M11 = 8, // 1<<3 + FIRST_ORDER = 1<<0 | 1<<1 | 1<<2 | 1<<3 +} + +/// Sparse storage format type +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum SparseFormat { + /// Dense format + DENSE = 0, + /// Compressed sparse row format + CSR = 1, + /// Compressed sparse coloumn format + CSC = 2, + /// Coordinate list (row, coloumn, value) tuples. + COO = 3 +} + +/// Binary operation types for generalized scan functions +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum BinaryOp { + ADD = 0, + MUL = 1, + MIN = 2, + MAX = 3 +} + +/// Random engine types +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum RandomEngineType { + ///Philox variant with N=4, W=32 and Rounds=10 + PHILOX_4X32_10 = 100, + ///Threefry variant with N=2, W=32 and Rounds=16 + THREEFRY_2X32_16 = 200, + ///Mersenne variant with MEXP = 11213 + MERSENNE_GP11213 = 300 +} + +pub const PHILOX : RandomEngineType = RandomEngineType::PHILOX_4X32_10; +pub const THREEFRY : RandomEngineType = RandomEngineType::THREEFRY_2X32_16; +pub const MERSENNE : RandomEngineType = RandomEngineType::MERSENNE_GP11213; +pub const DEFAULT_RANDOM_ENGINE : RandomEngineType = PHILOX; diff --git a/src/device/mod.rs b/src/device/mod.rs index 250b2fbb5..d8a8a0081 100644 --- a/src/device/mod.rs +++ b/src/device/mod.rs @@ -44,7 +44,7 @@ pub fn get_version() -> (i32, i32, i32) { /// /// An example output of `af::info` call looks like below /// -/// ```ignore +/// ```text /// ArrayFire v3.0.0 (CUDA, 64-bit Mac OSX, build d8d4b38) /// Platform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000 /// [0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0 diff --git a/src/dim4.rs b/src/dim4.rs index 29eda2375..0ddcac59f 100644 --- a/src/dim4.rs +++ b/src/dim4.rs @@ -18,7 +18,7 @@ impl Default for Dim4 { /// /// # Examples /// -/// ``` +/// ```rust /// use arrayfire::Dim4; /// /// let dims = Dim4::new(&[4, 4, 2, 1]); @@ -39,7 +39,7 @@ impl Index for Dim4 { /// /// # Examples /// -/// ``` +/// ```rust /// use arrayfire::Dim4; /// /// let dims = Dim4::new(&[4, 4, 2, 1]); @@ -56,7 +56,7 @@ impl Dim4 { /// /// # Examples /// - /// ``` + /// ```rust /// use arrayfire::Dim4; /// let dims = Dim4::new(&[4, 4, 2, 1]); /// ``` diff --git a/src/graphics.rs b/src/graphics.rs index 42a2dbd18..e17f65c1a 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -4,7 +4,7 @@ use array::Array; use defines::AfError; use defines::{ColorMap, MarkerType}; use error::HANDLE_ERROR; -use self::libc::{c_int, c_uint, c_double, c_char}; +use self::libc::{c_int, c_uint, c_float, c_double, c_char}; use std::ffi::CString; type MutWndHandle = *mut self::libc::c_ulonglong; @@ -15,19 +15,49 @@ type CellPtr = *const self::libc::c_void; #[allow(dead_code)] extern { fn af_create_window(out: MutWndHandle, w: c_int, h: c_int, title: *const c_char) -> c_int; + fn af_set_position(wnd: WndHandle, x: c_uint, y: c_uint) -> c_int; fn af_set_title(wnd: WndHandle, title: *const c_char) -> c_int; fn af_set_size(wnd: WndHandle, w: c_uint, h: c_uint) -> c_int; fn af_set_visibility(wnd: WndHandle, is_visible: c_int) -> c_int; + + fn af_set_axes_titles(wnd: WndHandle, + xtitle: *const c_char, ytitle: *const c_char, ztitle: *const c_char, + props: CellPtr) -> c_int; + fn af_set_axes_limits_compute(wnd: WndHandle, x: AfArray, y: AfArray, z: AfArray, + exact: c_int, props: CellPtr) -> c_int; + fn af_set_axes_limits_2d(wnd: WndHandle, xmin: c_float, xmax: c_float, + ymin: c_float, ymax: c_float, + exact: c_int, props: CellPtr) -> c_int; + fn af_set_axes_limits_3d(wnd: WndHandle, xmin: c_float, xmax: c_float, + ymin: c_float, ymax: c_float, + zmin: c_float, zmax: c_float, + exact: c_int, props: CellPtr) -> c_int; + fn af_draw_image(wnd: WndHandle, arr: AfArray, props: CellPtr) -> c_int; - fn af_draw_plot(wnd: WndHandle, x: AfArray, y: AfArray, props: CellPtr) -> c_int; - fn af_draw_plot3(wnd: WndHandle, P: AfArray, props: CellPtr) -> c_int; fn af_draw_hist(wnd: WndHandle, x: AfArray, minval: c_double, maxval: c_double, props: CellPtr) -> c_int; fn af_draw_surface(wnd: WndHandle, xvals: AfArray, yvals: AfArray, S: AfArray, props: CellPtr) -> c_int; - fn af_draw_scatter(wnd: WndHandle, x: AfArray, y: AfArray, marker: c_int, props: CellPtr) -> c_int; - fn af_draw_scatter3(wnd: WndHandle, P: AfArray, marker: c_int, props: CellPtr) -> c_int; + + fn af_draw_plot_2d(wnd: WndHandle, x: AfArray, y: AfArray, props: CellPtr) -> c_int; + fn af_draw_plot_3d(wnd: WndHandle, x: AfArray, y: AfArray, z: AfArray, props: CellPtr) -> c_int; + fn af_draw_plot_nd(wnd: WndHandle, P: AfArray, props: CellPtr) -> c_int; + + fn af_draw_scatter_2d(wnd: WndHandle, x: AfArray, y: AfArray, + marker: c_int, props: CellPtr) -> c_int; + fn af_draw_scatter_3d(wnd: WndHandle, x: AfArray, y: AfArray, z: AfArray, + marker: c_int, props: CellPtr) -> c_int; + fn af_draw_scatter_nd(wnd: WndHandle, P: AfArray, + marker: c_int, props: CellPtr) -> c_int; + + fn af_draw_vector_field_2d(wnd: WndHandle, xpnts: AfArray, ypnts: AfArray, + xdirs: AfArray, ydirs: AfArray, props: CellPtr) -> c_int; + fn af_draw_vector_field_3d(wnd: WndHandle, xpnts: AfArray, ypnts: AfArray, + xdirs: AfArray, ydirs: AfArray, zdirs: AfArray, zdirs: AfArray, + props: CellPtr) -> c_int; + fn af_draw_vector_field_nd(wnd: WndHandle, pnts: AfArray, dirs: AfArray, props: CellPtr) -> c_int; + fn af_grid(wnd: WndHandle, rows: c_int, cols: c_int) -> c_int; fn af_show(wnd: WndHandle) -> c_int; fn af_is_window_closed(out: *mut c_int, wnd: WndHandle) -> c_int; @@ -55,7 +85,7 @@ pub struct Cell { /// /// # Examples /// -/// ```no_run +/// ```rust,no_run /// use arrayfire::{histogram, load_image, Window}; /// let mut wnd = Window::new(1280, 720, String::from("Image Histogram")); /// let img = load_image("Path to image".to_string(), true/*If color image, 'false' otherwise*/); @@ -104,6 +134,16 @@ impl Drop for Window { impl Window { /// Creates new Window object + /// + /// # Parameters + /// + /// - `width` is width of the window + /// - `height` is the height of window + /// - `title` is the string displayed on window title bar + /// + /// # Return Values + /// + /// Window Object #[allow(unused_mut)] pub fn new(width: i32, height: i32, title: String) -> Window { unsafe { @@ -123,6 +163,11 @@ impl Window { } /// Set window starting position on the screen + /// + /// # Parameters + /// + /// - `x` is the horiontal coordinate where window is to be placed + /// - `y` is the vertical coordinate where window is to be placed pub fn set_position(&self, x: u32, y: u32) { unsafe { let err_val = af_set_position(self.handle as WndHandle, x as c_uint, y as c_uint); @@ -131,6 +176,10 @@ impl Window { } /// Set window title + /// + /// # Parameters + /// + /// - `title` is the string to be displayed on window title bar pub fn set_title(&self, title: String) { unsafe { let cstr_ret = CString::new(title.as_bytes()); @@ -190,7 +239,12 @@ impl Window { } } - /// Used to setup display layout in multiview mode + /// Setup display layout in multiview mode + /// + /// # Parameters + /// + /// - `rows` is the number of rows into which whole window is split into in multiple view mode + /// - `cols` is the number of cols into which whole window is split into in multiple view mode pub fn grid(&self, rows: i32, cols: i32) { unsafe { let err_val = af_grid(self.handle as WndHandle, rows as c_int, cols as c_int); @@ -209,14 +263,130 @@ impl Window { } } - /// Used in multiview mode to set the current sub-region to which the subsequence draw call - /// renders to + /// Set the current sub-region to render + /// + /// This function is only to be used into multiview mode + /// + /// # Parameters + /// + /// - `r` is the target row id + /// - `c` is the target row id pub fn set_view(&mut self, r: i32, c: i32) { self.row = r; self.col = c; } + /// Set chart axes titles + /// + /// # Parameters + /// + /// - `xlabel` is x axis title + /// - `ylabel` is y axis title + /// - `zlabel` is z axis title + pub fn set_axes_titles(&mut self, xlabel: String, ylabel: String, zlabel: String) { + let cprops = &Cell {row: self.row, col: self.col, title: String::from(""), cmap: self.cmap}; + let xstr = CString::new(xlabel.as_bytes()).unwrap(); + let ystr = CString::new(ylabel.as_bytes()).unwrap(); + let zstr = CString::new(zlabel.as_bytes()).unwrap(); + unsafe { + let err_val = af_set_axes_titles(self.handle as WndHandle, + xstr.to_bytes_with_nul().as_ptr() as *const c_char, + ystr.to_bytes_with_nul().as_ptr() as *const c_char, + zstr.to_bytes_with_nul().as_ptr() as *const c_char, + cprops as *const Cell as CellPtr); + HANDLE_ERROR(AfError::from(err_val)); + } + } + + /// Set chart axes limits by computing limits from data + /// + /// In multiple view (grid) mode, setting limits will effect the chart that is currently + /// active via set_view call + /// + /// # Parameters + /// + /// - `xrange` is set of all x values to compute min/max for x axis + /// - `yrange` is set of all y values to compute min/max for y axis + /// - `zrange` is set of all z values to compute min/max for z axis. If None is passed to + /// this paramter, 2d chart limits are set. + /// - `exact` indicates if the exact min/max values from `xrange`, `yrange` and `zrange` + /// are to extracted. If exact is false then the most significant digit is rounded up + /// to next power of 2 and the magnitude remains the same. + pub fn set_axes_limits_compute(&mut self, xrange: &Array, yrange: &Array, + zrange: Option<&Array>, exact: bool) { + let cprops = &Cell {row: self.row, col: self.col, title: String::from(""), cmap: self.cmap}; + unsafe { + let err_val = af_set_axes_limits_compute(self.handle as WndHandle, + xrange.get() as AfArray, + yrange.get() as AfArray, + match zrange { + Some(z) => z.get() as AfArray, + None => 0, + }, exact as c_int, + cprops as *const Cell as CellPtr); + HANDLE_ERROR(AfError::from(err_val)); + } + } + + /// Set 2d chart axes limits + /// + /// In multiple view (grid) mode, setting limits will effect the chart that is currently + /// active via set_view call + /// + /// # Parameters + /// + /// - `xmin` is minimum value on x axis + /// - `xmax` is maximum value on x axis + /// - `ymin` is minimum value on y axis + /// - `ymax` is maximum value on y axis + /// - `exact` indicates if the exact min/max values from `xrange`, `yrange` and `zrange` + /// are to extracted. If exact is false then the most significant digit is rounded up + /// to next power of 2 and the magnitude remains the same. + pub fn set_axes_limits_2d(&mut self, xmin: f32, xmax: f32, ymin: f32, ymax: f32, exact: bool) { + let cprops = &Cell {row: self.row, col: self.col, title: String::from(""), cmap: self.cmap}; + unsafe { + let err_val = af_set_axes_limits_2d(self.handle as WndHandle, xmin as c_float, + xmax as c_float, ymin as c_float, ymax as c_float, + exact as c_int, cprops as *const Cell as CellPtr); + HANDLE_ERROR(AfError::from(err_val)); + } + } + + /// Set 3d chart axes limits + /// + /// In multiple view (grid) mode, setting limits will effect the chart that is currently + /// active via set_view call + /// + /// # Parameters + /// + /// - `xmin` is minimum value on x axis + /// - `xmax` is maximum value on x axis + /// - `ymin` is minimum value on y axis + /// - `ymax` is maximum value on y axis + /// - `zmin` is minimum value on z axis + /// - `zmax` is maximum value on z axis + /// - `exact` indicates if the exact min/max values from `xrange`, `yrange` and `zrange` + /// are to extracted. If exact is false then the most significant digit is rounded up + /// to next power of 2 and the magnitude remains the same. + pub fn set_axes_limits_3d(&mut self, xmin: f32, xmax: f32, ymin: f32, ymax: f32, + zmin: f32, zmax: f32, exact: bool) { + let cprops = &Cell {row: self.row, col: self.col, title: String::from(""), cmap: self.cmap}; + unsafe { + let err_val = af_set_axes_limits_3d(self.handle as WndHandle, xmin as c_float, + xmax as c_float, ymin as c_float, ymax as c_float, + zmin as c_float, zmax as c_float, + exact as c_int, cprops as *const Cell as CellPtr); + HANDLE_ERROR(AfError::from(err_val)); + } + } + /// Render given Array as an image + /// + /// # Parameters + /// + /// - `input` image + /// - `title` parameter has effect only in multiview mode, where this string + /// is displayed as the respective cell/view title. pub fn draw_image(&self, input: &Array, title: Option) { let tstr = match title { Some(s) => s, @@ -231,36 +401,79 @@ impl Window { } /// Render given two Array's `x` and `y` as a 2d line plot - pub fn draw_plot(&self, x: &Array, y: &Array, title: Option) { + /// + /// # Parameters + /// + /// - `x` is the x coordinates of the plot + /// - `y` is the y coordinates of the plot + /// - `title` parameter has effect only in multiview mode, where this string + /// is displayed as the respective cell/view title. + pub fn draw_plot2(&self, x: &Array, y: &Array, title: Option) { let tstr = match title { Some(s) => s, None => format!("Cell({},{}))", self.col, self.row) }; let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap}; unsafe { - let err_val = af_draw_plot(self.handle as WndHandle, - x.get() as AfArray, - y.get() as AfArray, - cprops as *const Cell as CellPtr); + let err_val = af_draw_plot_2d(self.handle as WndHandle, + x.get() as AfArray, y.get() as AfArray, + cprops as *const Cell as CellPtr); + HANDLE_ERROR(AfError::from(err_val)); + } + } + + /// Render given Array's `x`, `y` and `z` as a 3d line plot + /// + /// # Parameters + /// + /// - `x` is the x coordinates of the plot + /// - `y` is the y coordinates of the plot + /// - `z` is the z coordinates of the plot + /// - `title` parameter has effect only in multiview mode, where this string + /// is displayed as the respective cell/view title. + pub fn draw_plot3(&self, x: &Array, y: &Array, z: &Array, title: Option) { + let tstr = match title { + Some(s) => s, + None => format!("Cell({},{}))", self.col, self.row) + }; + let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap}; + unsafe { + let err_val = af_draw_plot_3d(self.handle as WndHandle, + x.get() as AfArray, y.get() as AfArray, z.get() as AfArray, + cprops as *const Cell as CellPtr); HANDLE_ERROR(AfError::from(err_val)); } } /// Render give Arrays of points as a 3d line plot - pub fn draw_plot3(&self, points: &Array, title: Option) { + /// + /// # Parameters + /// + /// - `points` is an Array containing list of points of plot + /// - `title` parameter has effect only in multiview mode, where this string + /// is displayed as the respective cell/view title. + pub fn draw_plot(&self, points: &Array, title: Option) { let tstr = match title { Some(s) => s, None => format!("Cell({},{}))", self.col, self.row) }; let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap}; unsafe { - let err_val = af_draw_plot3(self.handle as WndHandle, points.get() as AfArray, - cprops as *const Cell as CellPtr); + let err_val = af_draw_plot_nd(self.handle as WndHandle, points.get() as AfArray, + cprops as *const Cell as CellPtr); HANDLE_ERROR(AfError::from(err_val)); } } /// Render given Array as a histogram + /// + /// # Parameters + /// + /// - `hst` is an Array containing histogram data + /// - `minval` is the minimum bin value of histogram + /// - `maxval` is the maximum bin value of histogram + /// - `title` parameter has effect only in multiview mode, where this string + /// is displayed as the respective cell/view title. pub fn draw_hist(&self, hst: &Array, minval: f64, maxval: f64, title: Option) { let tstr = match title { Some(s) => s, @@ -276,6 +489,14 @@ impl Window { } /// Render give Arrays as 3d surface + /// + /// # Parameters + /// + /// - `x` is the x coordinates of the surface plot + /// - `y` is the y coordinates of the surface plot + /// - `z` is the z coordinates of the surface plot + /// - `title` parameter has effect only in multiview mode, where this string + /// is displayed as the respective cell/view title. pub fn draw_surface(&self, xvals: &Array, yvals: &Array, zvals: &Array, title: Option) { let tstr = match title { Some(s) => s, @@ -292,36 +513,152 @@ impl Window { } } - /// Render give Arrays as 2d scatter plot - pub fn draw_scatter(&self, xvals: &Array, yvals: &Array, marker: MarkerType, title: Option) { + /// Render given Arrays as 2d scatter plot + /// + /// # Parameters + /// + /// - `xvals` is the x coordinates of the scatter plot + /// - `yvals` is the y coordinates of the scatter plot + /// - `marker` is of enum type [MarkerType](./enum.MarkerType.html) + /// - `title` parameter has effect only in multiview mode, where this string + /// is displayed as the respective cell/view title. + pub fn draw_scatter2(&self, xvals: &Array, yvals: &Array, + marker: MarkerType, title: Option) { let tstr = match title { Some(s) => s, None => format!("Cell({},{}))", self.col, self.row) }; let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap}; unsafe { - let err_val = af_draw_scatter(self.handle as WndHandle, - xvals.get() as AfArray, - yvals.get() as AfArray, - marker as c_int, - cprops as *const Cell as CellPtr); + let err_val = af_draw_scatter_2d(self.handle as WndHandle, + xvals.get() as AfArray, yvals.get() as AfArray, + marker as c_int, cprops as *const Cell as CellPtr); + HANDLE_ERROR(AfError::from(err_val)); + } + } + + /// Render given Arrays as 3d scatter plot + /// + /// # Parameters + /// + /// - `xvals` is the x coordinates of the scatter plot + /// - `yvals` is the y coordinates of the scatter plot + /// - `zvals` is the z coordinates of the scatter plot + /// - `marker` is of enum type [MarkerType](./enum.MarkerType.html) + /// - `title` parameter has effect only in multiview mode, where this string + /// is displayed as the respective cell/view title. + pub fn draw_scatter3(&self, xvals: &Array, yvals: &Array, zvals: &Array, + marker: MarkerType, title: Option) { + let tstr = match title { + Some(s) => s, + None => format!("Cell({},{}))", self.col, self.row) + }; + let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap}; + unsafe { + let err_val = af_draw_scatter_3d(self.handle as WndHandle, xvals.get() as AfArray, + yvals.get() as AfArray, zvals.get() as AfArray, + marker as c_int, cprops as *const Cell as CellPtr); HANDLE_ERROR(AfError::from(err_val)); } } /// Render give Array as 3d scatter plot - pub fn draw_scatter3(&self, vals: &Array, marker: MarkerType, title: Option) { + /// + /// # Parameters + /// + /// - `points` is an Array containing list of points of plot + /// - `marker` is of enum type [MarkerType](./enum.MarkerType.html) + /// - `title` parameter has effect only in multiview mode, where this string + /// is displayed as the respective cell/view title. + pub fn draw_scatter(&self, vals: &Array, marker: MarkerType, title: Option) { + let tstr = match title { + Some(s) => s, + None => format!("Cell({},{}))", self.col, self.row) + }; + let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap}; + unsafe { + let err_val = af_draw_scatter_nd(self.handle as WndHandle, vals.get() as AfArray, + marker as c_int, cprops as *const Cell as CellPtr); + HANDLE_ERROR(AfError::from(err_val)); + } + } + + /// Render given Arrays as 2d vector field + /// + /// # Parameters + /// + /// - `xpnts` is an Array containing list of x coordinates + /// - `xdirs` is an Array containing direction component of x coord + /// - `ypnts` is an Array containing list of y coordinates + /// - `ydirs` is an Array containing direction component of y coord + /// - `title` parameter has effect only in multiview mode, where this string + /// is displayed as the respective cell/view title. + pub fn draw_vector_field2(&self, xpnts: &Array, ypnts: &Array, + xdirs: &Array, ydirs: &Array, title: Option) { let tstr = match title { Some(s) => s, None => format!("Cell({},{}))", self.col, self.row) }; let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap}; unsafe { - let err_val = af_draw_scatter3(self.handle as WndHandle, - vals.get() as AfArray, - marker as c_int, - cprops as *const Cell as CellPtr); + let err_val = af_draw_vector_field_2d(self.handle as WndHandle, + xpnts.get() as AfArray, ypnts.get() as AfArray, + xdirs.get() as AfArray, ydirs.get() as AfArray, + cprops as *const Cell as CellPtr); HANDLE_ERROR(AfError::from(err_val)); } } -} \ No newline at end of file + + /// Render given Arrays as 3d vector field + /// + /// # Parameters + /// + /// - `xpnts` is an Array containing list of x coordinates + /// - `xdirs` is an Array containing direction component of x coord + /// - `ypnts` is an Array containing list of y coordinates + /// - `ydirs` is an Array containing direction component of y coord + /// - `zpnts` is an Array containing list of z coordinates + /// - `zdirs` is an Array containing direction component of z coord + /// - `title` parameter has effect only in multiview mode, where this string + /// is displayed as the respective cell/view title. + pub fn draw_vector_field3(&self, xpnts: &Array, ypnts: &Array, zpnts: &Array, + xdirs: &Array, ydirs: &Array, zdirs: &Array, + title: Option) { + let tstr = match title { + Some(s) => s, + None => format!("Cell({},{}))", self.col, self.row) + }; + let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap}; + unsafe { + let err_val = af_draw_vector_field_3d(self.handle as WndHandle, xpnts.get() as AfArray, + ypnts.get() as AfArray, zpnts.get() as AfArray, + xdirs.get() as AfArray, ydirs.get() as AfArray, + zdirs.get() as AfArray, + cprops as *const Cell as CellPtr); + HANDLE_ERROR(AfError::from(err_val)); + } + } + + /// Render given Array as vector field + /// + /// # Parameters + /// + /// - `points` is an Array containing list of coordinates of vector field + /// - `directions` is an Array containing directions at the coordinates specified in `points` + /// Array. + /// - `title` parameter has effect only in multiview mode, where this string + /// is displayed as the respective cell/view title. + pub fn draw_vector_field(&self, points: &Array, directions: &Array, title: Option) { + let tstr = match title { + Some(s) => s, + None => format!("Cell({},{}))", self.col, self.row) + }; + let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap}; + unsafe { + let err_val = af_draw_vector_field_nd(self.handle as WndHandle, + points.get() as AfArray, directions.get() as AfArray, + cprops as *const Cell as CellPtr); + HANDLE_ERROR(AfError::from(err_val)); + } + } +} diff --git a/src/image/mod.rs b/src/image/mod.rs index 19bbc9639..88258d541 100644 --- a/src/image/mod.rs +++ b/src/image/mod.rs @@ -1,7 +1,7 @@ extern crate libc; use array::Array; -use defines::{AfError, BorderType, ColorSpace, Connectivity, InterpType, YCCStd}; +use defines::{AfError, BorderType, ColorSpace, Connectivity, InterpType, YCCStd, MomentType}; use error::HANDLE_ERROR; use util::HasAfEnum; use self::libc::{uint8_t, c_uint, c_int, c_float, c_double}; @@ -65,6 +65,8 @@ extern { fn af_medfilt(out: MutAfArray, input: AfArray, wlen: DimT, wwid: DimT, etype: uint8_t) -> c_int; + fn af_medfilt1(out: MutAfArray, input: AfArray, wlen: DimT, etype: uint8_t) -> c_int; + fn af_minfilt(out: MutAfArray, input: AfArray, wlen: DimT, wwid: DimT, etype: uint8_t) -> c_int; @@ -93,6 +95,9 @@ extern { fn af_rgb2ycbcr(out: MutAfArray, input: AfArray, stnd: c_int) -> c_int; fn af_is_image_io_available(out: *mut c_int) -> c_int; fn af_transform_coordinates(out: MutAfArray, tf: AfArray, d0: c_float, d1: c_float) -> c_int; + + fn af_moments(out: MutAfArray, input: AfArray, moment: c_int) ->c_int; + fn af_moments_all(out: *mut c_double, input: AfArray, moment: c_int) ->c_int; } /// Calculate the gradients @@ -652,7 +657,19 @@ pub fn mean_shift(input: &Array, spatial_sigma: f32, chromatic_sigma: f32, } macro_rules! filt_func_def { - ($fn_name: ident, $ffi_name: ident) => ( + ($doc_str: expr, $fn_name: ident, $ffi_name: ident) => ( + #[doc=$doc_str] + /// + ///# Parameters + /// + /// - `input` is the input image(Array) + /// - `wlen` is the horizontal length of the filter + /// - `hlen` is the vertical length of the filter + /// - `etype` is enum of type [BorderType](./enum.BorderType.html) + /// + ///# Return Values + /// + /// An Array with filtered image data. #[allow(unused_mut)] pub fn $fn_name(input: &Array, wlen: u64, wwid: u64, etype: BorderType) -> Array { @@ -667,9 +684,9 @@ macro_rules! filt_func_def { ) } -filt_func_def!(medfilt, af_medfilt); -filt_func_def!(minfilt, af_minfilt); -filt_func_def!(maxfilt, af_maxfilt); +filt_func_def!("Median filter", medfilt, af_medfilt); +filt_func_def!("Box filter with minimum as box operation", minfilt, af_minfilt); +filt_func_def!("Box filter with maximum as box operation", maxfilt, af_maxfilt); /// Creates a Gaussian Kernel. /// @@ -830,14 +847,18 @@ pub fn hist_equal(input: &Array, hist: &Array) -> Array { } macro_rules! grayrgb_func_def { - ($fn_name: ident, $ffi_name: ident) => ( - /// Color space conversion functions + ($doc_str: expr, $fn_name: ident, $ffi_name: ident) => ( + #[doc=$doc_str] /// - /// # Parameters + ///# Parameters /// /// - `r` is fraction of red channel to appear in output /// - `g` is fraction of green channel to appear in output /// - `b` is fraction of blue channel to appear in output + /// + ///#Return Values + /// + ///An Array with image data in target color space #[allow(unused_mut)] pub fn $fn_name(input: &Array, r: f32, g: f32, b: f32) -> Array { unsafe { @@ -851,12 +872,12 @@ macro_rules! grayrgb_func_def { ) } -grayrgb_func_def!(rgb2gray, af_rgb2gray); -grayrgb_func_def!(gray2rgb, af_gray2rgb); +grayrgb_func_def!("Color(RGB) to Grayscale conversion", rgb2gray, af_rgb2gray); +grayrgb_func_def!("Grayscale to Color(RGB) conversion", gray2rgb, af_gray2rgb); macro_rules! hsvrgb_func_def { - ($fn_name: ident, $ffi_name: ident) => ( - /// Color space conversion functions + ($doc_str: expr, $fn_name: ident, $ffi_name: ident) => ( + #[doc=$doc_str] #[allow(unused_mut)] pub fn $fn_name(input: &Array) -> Array { unsafe { @@ -869,8 +890,8 @@ macro_rules! hsvrgb_func_def { ) } -hsvrgb_func_def!(hsv2rgb, af_hsv2rgb); -hsvrgb_func_def!(rgb2hsv, af_rgb2hsv); +hsvrgb_func_def!("HSV to RGB color space conversion", hsv2rgb, af_hsv2rgb); +hsvrgb_func_def!("RGB to HSV color space conversion", rgb2hsv, af_rgb2hsv); /// Generate an array with image windows as columns /// @@ -910,7 +931,7 @@ hsvrgb_func_def!(rgb2hsv, af_rgb2hsv); /// /// # Examples /// -/// ```ignore +/// ```text /// A [5 5 1 1] /// 10 15 20 25 30 /// 11 16 21 26 31 @@ -1119,4 +1140,69 @@ pub fn transform_coords(tf: &Array, d0: f32, d1: f32) -> Array { HANDLE_ERROR(AfError::from(err_val)); Array::from(temp) } -} \ No newline at end of file +} + +/// Find Image moments +/// +/// # Parameters +/// +/// - `input` is the input image +/// - `moment` is the type of moment to be computed, takes a value of +/// [enum](./enum.MomentType.html) +/// +/// # Return Values +/// +/// Moments Array +pub fn moments(input: &Array, moment: MomentType) -> Array { + unsafe { + let mut temp: i64 = 0; + let err_val = af_moments(&mut temp as MutAfArray, + input.get() as AfArray, + moment as c_int); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } +} + +/// Find Image moment for whole image +/// +/// # Parameters +/// +/// - `input` is the input image +/// - `moment` is the type of moment to be computed, takes a value of +/// [enum](./enum.MomentType.html) +/// +/// # Return Values +/// +/// Moment value of the whole image +pub fn moments_all(input: &Array, moment: MomentType) -> f64 { + unsafe { + let mut temp: f64 = 0.0; + let err_val = af_moments_all(&mut temp as *mut c_double, + input.get() as AfArray, + moment as c_int); + HANDLE_ERROR(AfError::from(err_val)); + temp + } +} + +/// One dimensional median filter on image +/// +/// # Parameters +/// +/// - `input` is the input image(Array) +/// - `wlen` is the horizontal length of the filter +/// - `etype` is enum of type [BorderType](./enum.BorderType.html) +/// +/// # Return Values +/// +/// An Array with filtered image data. +pub fn medfilt1(input: &Array, wlen: u64, etype: BorderType) -> Array { + unsafe { + let mut temp: i64 = 0; + let err_val = af_medfilt1(&mut temp as MutAfArray, input.get() as AfArray, + wlen as DimT, etype as uint8_t); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } +} diff --git a/src/index.rs b/src/index.rs index d45a93b5e..273963bab 100644 --- a/src/index.rs +++ b/src/index.rs @@ -117,7 +117,7 @@ impl Drop for Indexer { /// /// # Examples /// -/// ``` +/// ```rust /// use arrayfire::{Dim4, Seq, index, randu, print}; /// let dims = Dim4::new(&[5, 5, 1, 1]); /// let a = randu::(dims); @@ -145,7 +145,7 @@ pub fn index(input: &Array, seqs: &[Seq]) -> Array /// /// # Examples /// -/// ``` +/// ```rust /// use arrayfire::{Dim4, randu, row, print}; /// let dims = Dim4::new(&[5, 5, 1, 1]); /// let a = randu::(dims); @@ -160,7 +160,7 @@ pub fn row(input: &Array, row_num: u64) -> Array { } #[allow(dead_code)] -/// Set row `row_num` in `input` Array to a new Array `new_row` +/// Set `row_num`^th row in `input` Array to a new Array `new_row` pub fn set_row(input: &Array, new_row: &Array, row_num: u64) -> Array { assign_seq(input, &[Seq::new(row_num as f64, row_num as f64, 1.0), Seq::default()], @@ -168,7 +168,7 @@ pub fn set_row(input: &Array, new_row: &Array, row_num: u64) -> Array { } #[allow(dead_code)] -/// Get all rows from `first` to `last` in the `input` Array +/// Get an Array with all rows from `first` to `last` in the `input` Array pub fn rows(input: &Array, first: u64, last: u64) -> Array { index(input, &[Seq::new(first as f64, last as f64, 1.0), Seq::default()]) } @@ -183,7 +183,7 @@ pub fn set_rows(input: &Array, new_rows: &Array, first: u64, last: u64) -> Array /// /// # Examples /// -/// ``` +/// ```rust /// use arrayfire::{Dim4, randu, col, print}; /// let dims = Dim4::new(&[5, 5, 1, 1]); /// let a = randu::(dims); @@ -197,7 +197,7 @@ pub fn col(input: &Array, col_num: u64) -> Array { } #[allow(dead_code)] -/// Set col `col_num` in `input` Array to a new Array `new_col` +/// Set `col_num`^th col in `input` Array to a new Array `new_col` pub fn set_col(input: &Array, new_col: &Array, col_num: u64) -> Array { assign_seq(input, &[Seq::default(), Seq::new(col_num as f64, col_num as f64, 1.0)], @@ -217,11 +217,11 @@ pub fn set_cols(input: &Array, new_cols: &Array, first: u64, last: u64) -> Array } #[allow(dead_code)] -/// Get slice `slice_num` from `input` Array +/// Get `slice_num`^th slice from `input` Array /// -/// Slices indicate that the indexing is along 3rd dimension +/// Note. Slices indicate that the indexing is along 3rd dimension pub fn slice(input: &Array, slice_num: u64) -> Array { - index(input, + index(input, &[Seq::default(), Seq::default(), Seq::new(slice_num as f64, slice_num as f64, 1.0)]) } @@ -274,7 +274,7 @@ pub fn lookup(input: &Array, indices: &Array, seq_dim: i32) -> Array { /// /// # Examples /// -/// ``` +/// ```rust /// use arrayfire::{constant, Dim4, Seq, assign_seq, print}; /// 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])); @@ -313,7 +313,7 @@ pub fn assign_seq(lhs: &Array, seqs: &[Seq], rhs: &Array) -> Array /// /// # Examples /// -/// ``` +/// ```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])); @@ -352,7 +352,7 @@ pub fn index_gen(input: &Array, indices: Indexer) -> Array { /// /// # Examples /// -/// ``` +/// ```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])); diff --git a/src/lib.rs b/src/lib.rs index 18c0ce186..00a4426ef 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ extern crate lazy_static; pub use array::Array; -pub use array::{print}; +pub use array::{print, print_gen, eval_multiple, is_eval_manual, set_manual_eval}; mod array; //pub use algorithm::{sum_nan, product_nan, sum_nan_all, product_nan_all}; @@ -14,12 +14,12 @@ pub use algorithm::{sum, product, min, max, all_true, any_true, count, sum_nan, pub use algorithm::{sum_all, product_all, min_all, max_all, sum_nan_all, product_nan_all}; pub use algorithm::{all_true_all, any_true_all, count_all, imin, imax, imin_all, imax_all}; pub use algorithm::{accum, locate, diff1, diff2, sort, sort_index, sort_by_key}; -pub use algorithm::{set_unique, set_union, set_intersect}; +pub use algorithm::{set_unique, set_union, set_intersect, scan, scan_by_key}; mod algorithm; pub use arith::{add, sub, div, mul, lt, gt, le, ge, eq, neq, and, or, minof, maxof, rem}; pub use arith::{bitand, bitor, bitxor, shiftl, shiftr}; -pub use arith::{abs, sign, round, trunc, floor, ceil, modulo, sigmoid}; +pub use arith::{abs, sign, round, trunc, floor, ceil, modulo, sigmoid, clamp}; pub use arith::{sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh}; pub use arith::{atan2, cplx2, arg, cplx, real, imag, conjg, hypot}; pub use arith::{sqrt, log, log1p, log10, log2, pow2, exp, expm1, erf, erfc, root, pow}; @@ -33,7 +33,6 @@ pub use blas::{matmul, dot, transpose, transpose_inplace}; mod blas; pub use data::{constant, range, iota}; -pub use data::{set_seed, get_seed, randu, randn}; pub use data::{identity, diag_create, diag_extract, lower, upper}; pub use data::{join, join_many, tile}; pub use data::{reorder, shift, moddims, flat, flip}; @@ -47,7 +46,8 @@ mod device; pub use defines::{DType, AfError, Backend, ColorMap, YCCStd, HomographyType}; pub use defines::{InterpType, BorderType, MatchType, NormType}; pub use defines::{Connectivity, ConvMode, ConvDomain, ColorSpace, MatProp}; -pub use defines::{MarkerType}; +pub use defines::{MarkerType, MomentType, SparseFormat, BinaryOp, RandomEngineType}; +pub use defines::{PHILOX, THREEFRY, MERSENNE, DEFAULT_RANDOM_ENGINE}; mod defines; pub use dim4::Dim4; @@ -72,8 +72,9 @@ pub use image::{resize, transform, rotate, translate, scale, skew}; pub use image::{dilate, dilate3, erode, erode3, minfilt, maxfilt}; pub use image::{gradient, histogram, hist_equal, regions}; pub use image::{gray2rgb, rgb2gray, hsv2rgb, rgb2hsv, color_space}; -pub use image::{bilateral, mean_shift, medfilt, sobel}; +pub use image::{bilateral, mean_shift, medfilt, sobel, medfilt1}; pub use image::{unwrap, wrap, sat, rgb2ycbcr, ycbcr2rgb, is_imageio_available, transform_coords}; +pub use image::{moments, moments_all}; mod image; pub use lapack::{svd, lu, qr, cholesky, solve, solve_lu, inverse, det, rank, norm}; @@ -82,7 +83,12 @@ mod lapack; mod macros; mod num; -pub use signal::{approx1, approx2}; +pub use random::RandomEngine; +pub use random::{set_seed, get_seed, randu, randn, random_uniform, random_normal}; +pub use random::{get_default_random_engine, set_default_random_engine_type}; +mod random; + +pub use signal::{approx1, approx2, set_fft_plan_cache_size}; pub use signal::{fft, fft2, fft3, ifft, ifft2, ifft3}; pub use signal::{fft_r2c, fft2_r2c, fft3_r2c, fft_c2r, fft2_c2r, fft3_c2r}; pub use signal::{fft_inplace, fft2_inplace, fft3_inplace}; @@ -92,13 +98,18 @@ pub use signal::{fft_convolve1, fft_convolve2, fft_convolve3}; pub use signal::{fir, iir}; mod signal; +pub use sparse::{sparse, sparse_from_host, sparse_from_dense, sparse_convert_to}; +pub use sparse::{sparse_to_dense, sparse_get_info, sparse_get_values, sparse_get_nnz}; +pub use sparse::{sparse_get_row_indices, sparse_get_col_indices, sparse_get_format}; +mod sparse; + pub use statistics::{mean, stdev, median, var, cov, corrcoef}; pub use statistics::{mean_weighted, var_weighted}; pub use statistics::{var_all, mean_all, stdev_all, median_all}; pub use statistics::{mean_all_weighted, var_all_weighted}; mod statistics; -pub use util::{HasAfEnum}; +pub use util::{HasAfEnum, get_size}; mod util; pub use vision::Features; diff --git a/src/macros.rs b/src/macros.rs index bc509379a..d427af28d 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -35,7 +35,7 @@ /// /// # Examples /// -/// ``` +/// ```rust /// # #[macro_use(mem_info)] extern crate arrayfire; /// # fn main() { /// use arrayfire::{Dim4, device_mem_info, print, randu}; @@ -49,7 +49,7 @@ /// /// Sample Output: /// -/// ```ignore +/// ```text /// AF Memory: Here /// Allocated [ Bytes | Buffers ] = [ 4096 | 4 ] /// In Use [ Bytes | Buffers ] = [ 2048 | 2 ] @@ -72,7 +72,7 @@ macro_rules! mem_info { /// /// # Examples /// -/// ``` +/// ```rust /// # #[macro_use] extern crate arrayfire; /// /// # fn main() { @@ -108,11 +108,11 @@ macro_rules! join_many { /// /// # Examples /// -/// ``` +/// ```rust /// # #[macro_use] extern crate arrayfire; /// /// # fn main() { -/// use arrayfire::{Dim4, print, randu}; +/// use arrayfire::{Dim4, print_gen, randu}; /// let dims = Dim4::new(&[3, 1, 1, 1]); /// let a = randu::(dims); /// af_print!("Create a 5-by-3 matrix of random floats on the GPU", a); @@ -123,8 +123,21 @@ macro_rules! join_many { macro_rules! af_print { [$msg: expr, $x: ident] => { { - println!("{}", $msg); - print(&$x); + print_gen(String::from($msg), &$x, Some(4)); + } + }; +} + +/// Evaluate arbitrary number of arrays +#[macro_export] +macro_rules! eval { + [$($x:ident),+] => { + { + let mut temp_vec = Vec::new(); + $( + temp_vec.push($x); + )* + eval_multiple(temp_vec) } }; } diff --git a/src/random/mod.rs b/src/random/mod.rs new file mode 100644 index 000000000..9a095ad2d --- /dev/null +++ b/src/random/mod.rs @@ -0,0 +1,260 @@ +extern crate libc; + +use array::Array; +use dim4::Dim4; +use defines::{AfError, RandomEngineType}; +use error::HANDLE_ERROR; +use self::libc::{uint8_t, c_int, c_uint}; +use util::HasAfEnum; + +type MutAfArray = *mut self::libc::c_longlong; +type AfArray = self::libc::c_longlong; +type MutRandEngine = *mut self::libc::c_longlong; +type RandEngine = self::libc::c_longlong; +type DimT = self::libc::c_longlong; +type Intl = self::libc::c_longlong; +type Uintl = self::libc::c_ulonglong; + +#[allow(dead_code)] +extern { + fn af_set_seed(seed: Uintl) -> c_int; + fn af_get_seed(seed: *mut Uintl) -> c_int; + + fn af_randu(out: MutAfArray, ndims: c_uint, dims: *const DimT, afdtype: uint8_t) -> c_int; + fn af_randn(out: MutAfArray, ndims: c_uint, dims: *const DimT, afdtype: uint8_t) -> c_int; + + fn af_create_random_engine(engine: MutRandEngine, rtype: uint8_t, seed: Uintl) -> c_int; + fn af_retain_random_engine(engine: MutRandEngine, inputEngine: RandEngine) -> c_int; + fn af_random_engine_set_type(engine: MutRandEngine, rtpye: uint8_t) -> c_int; + fn af_random_engine_get_type(rtype: *mut uint8_t, engine: RandEngine) -> c_int; + fn af_random_engine_set_seed(engine: MutRandEngine, seed: Uintl) -> c_int; + fn af_random_engine_get_seed(seed: *mut Uintl, engine: RandEngine) -> c_int; + fn af_release_random_engine(engine: RandEngine) -> c_int; + + fn af_get_default_random_engine(engine: MutRandEngine) -> c_int; + fn af_set_default_random_engine_type(rtype: uint8_t) -> c_int; + + fn af_random_uniform(out: MutAfArray, ndims: c_uint, dims: *const DimT, + aftype: uint8_t, engine: RandEngine) -> c_int; + fn af_random_normal(out: MutAfArray, ndims: c_uint, dims: *const DimT, + aftype: uint8_t, engine: RandEngine) -> c_int; +} + +/// Set seed for random number generation +pub fn set_seed(seed: u64) { + unsafe { + let err_val = af_set_seed(seed as Uintl); + HANDLE_ERROR(AfError::from(err_val)); + } +} + +/// Get the seed of random number generator +#[allow(unused_mut)] +pub fn get_seed() -> u64 { + unsafe { + let mut temp: u64 = 0; + let err_val = af_get_seed(&mut temp as *mut Uintl); + HANDLE_ERROR(AfError::from(err_val)); + temp + } +} + +macro_rules! data_gen_def { + ($doc_str: expr, $fn_name:ident, $ffi_name: ident) => ( + #[doc=$doc_str] + /// + ///# Parameters + /// + /// - `dims` is the output dimensions + /// + ///# Return Values + /// + /// An Array with random values. + #[allow(unused_mut)] + pub fn $fn_name(dims: Dim4) -> Array { + unsafe { + let aftype = T::get_af_dtype(); + let mut temp: i64 = 0; + let err_val = $ffi_name(&mut temp as MutAfArray, + dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, + aftype as uint8_t); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } + } + ) +} + +data_gen_def!("Create random numbers from uniform distribution", randu, af_randu); +data_gen_def!("Create random numbers from normal distribution", randn, af_randn); + +/// Random number generator engine +/// +/// This is a wrapper for ArrayFire's native random number generator engine. +pub struct RandomEngine { + handle: i64, +} + +/// Used for creating RandomEngine object from native resource id +impl From for RandomEngine { + fn from(t: i64) -> RandomEngine { + RandomEngine {handle: t} + } +} + +impl RandomEngine { + /// Create a new random engine object + /// + /// # Parameters + /// + /// - `rengine` can be value of [RandomEngineType](./enum.RandomEngineType.html) enum. + /// - `seed` is the initial seed value + /// + /// # Return Values + /// + /// A object of type RandomEngine + pub fn new(rengine: RandomEngineType, seed: Option) -> RandomEngine { + unsafe { + let mut temp: i64 = 0; + let err_val = af_create_random_engine(&mut temp as MutRandEngine, rengine as uint8_t, + match seed {Some(s) => s, None => 0} as Uintl); + HANDLE_ERROR(AfError::from(err_val)); + RandomEngine::from(temp) + } + } + + /// Get random engine type + pub fn get_type(&self) -> RandomEngineType { + unsafe { + let mut temp: u8 = 0; + let err_val = af_random_engine_get_type(&mut temp as *mut uint8_t, + self.handle as RandEngine); + HANDLE_ERROR(AfError::from(err_val)); + RandomEngineType::from(temp as i32) + } + } + + /// Get random engine type + pub fn set_type(&mut self, engine_type: RandomEngineType) { + unsafe { + let err_val = af_random_engine_set_type(&mut self.handle as MutRandEngine, + engine_type as uint8_t); + HANDLE_ERROR(AfError::from(err_val)); + } + } + + /// Set seed for random engine + pub fn set_seed(&mut self, seed: u64) { + unsafe { + let err_val = af_random_engine_set_seed(&mut self.handle as MutRandEngine, + seed as Uintl); + HANDLE_ERROR(AfError::from(err_val)); + } + } + + /// Get seed of the random engine + pub fn get_seed(&self) -> u64 { + unsafe { + let mut seed: u64 = 0; + let err_val = af_random_engine_get_seed(&mut seed as *mut Uintl, self.handle as RandEngine); + HANDLE_ERROR(AfError::from(err_val)); + seed + } + } + + /// Returns the native FFI handle for Rust object `RandomEngine` + pub fn get(&self) -> i64 { + self.handle + } +} + +/// Increment reference count of RandomEngine's native resource +impl Clone for RandomEngine { + fn clone(&self) -> RandomEngine { + unsafe { + let mut temp: i64 = 0; + let err_val = af_retain_random_engine(&mut temp as MutRandEngine, self.handle as RandEngine); + HANDLE_ERROR(AfError::from(err_val)); + RandomEngine::from(temp) + } + } +} + +/// Free RandomEngine's native resource +impl Drop for RandomEngine { + fn drop(&mut self) { + unsafe { + let err_val = af_release_random_engine(self.handle as RandEngine); + HANDLE_ERROR(AfError::from(err_val)); + } + } +} + +/// Get default random engine +pub fn get_default_random_engine() -> RandomEngine { + unsafe { + let mut temp : i64 = 0; + let mut err_val = af_get_default_random_engine(&mut temp as MutRandEngine); + HANDLE_ERROR(AfError::from(err_val)); + let mut handle : i64 = 0; + err_val = af_retain_random_engine(&mut handle as MutRandEngine, temp as RandEngine); + HANDLE_ERROR(AfError::from(err_val)); + RandomEngine::from(handle) + } +} + +/// Set the random engine type for default random number generator +/// +/// # Parameters +/// +/// - `rtype` can take one of the values of enum [RandomEngineType](./enum.RandomEngineType.html) +pub fn set_default_random_engine_type(rtype: RandomEngineType) { + unsafe { + let err_val = af_set_default_random_engine_type(rtype as uint8_t); + HANDLE_ERROR(AfError::from(err_val)); + } +} + +/// Generate array of uniform numbers using a random engine +/// +/// # Parameters +/// +/// - `dims` is output array dimensions +/// - `engine` is an object of type [RandomEngine](./struct.RandomEngine.html) +/// +/// # Return Values +/// +/// An Array with uniform numbers generated using random engine +pub fn random_uniform(dims: Dim4, engine: RandomEngine) -> Array { + unsafe { + let aftype = T::get_af_dtype(); + let mut temp : i64 = 0; + let err_val = af_random_uniform(&mut temp as MutAfArray, + dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, + aftype as uint8_t, engine.get() as RandEngine); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } +} + +/// Generate array of normal numbers using a random engine +/// +/// # Parameters +/// +/// - `dims` is output array dimensions +/// - `engine` is an object of type [RandomEngine](./struct.RandomEngine.html) +/// +/// # Return Values +/// +/// An Array with normal numbers generated using random engine +pub fn random_normal(dims: Dim4, engine: RandomEngine) -> Array { + unsafe { + let aftype = T::get_af_dtype(); + let mut temp : i64 = 0; + let err_val = af_random_normal(&mut temp as MutAfArray, + dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, + aftype as uint8_t, engine.get() as RandEngine); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } +} diff --git a/src/signal/mod.rs b/src/signal/mod.rs index ac1c385c9..cf404cbf3 100644 --- a/src/signal/mod.rs +++ b/src/signal/mod.rs @@ -3,7 +3,7 @@ extern crate libc; use array::Array; use defines::{AfError, ConvDomain, ConvMode, InterpType}; use error::HANDLE_ERROR; -use self::libc::{uint8_t, c_int, c_float, c_double, c_longlong}; +use self::libc::{uint8_t, c_int, c_float, c_double, c_longlong, size_t}; type MutAfArray = *mut self::libc::c_longlong; type AfArray = self::libc::c_longlong; @@ -16,6 +16,8 @@ extern { fn af_approx2(out: MutAfArray, inp: AfArray, pos0: AfArray, pos1: AfArray, method: c_int, off_grid: c_float) -> c_int; + fn af_set_fft_plan_cache_size(cache_size: size_t) -> c_int; + fn af_fft(out: MutAfArray, arr: AfArray, nfac: c_double, odim0: c_longlong) -> c_int; @@ -115,6 +117,18 @@ pub fn approx2(input: &Array, pos0: &Array, pos1: &Array, } } +/// Set fft plan cache size +/// +/// Though this is a low overhead function, it is advised not to change +/// the fft plan cache size a mid program execution unless that is what +/// you intend to do. +pub fn set_fft_plan_cache_size(cache_size: usize) { + unsafe { + let err_val = af_set_fft_plan_cache_size(cache_size as size_t); + HANDLE_ERROR(AfError::from(err_val)); + } +} + /// Fast fourier transform for 1d signals /// /// # Parameters @@ -270,28 +284,21 @@ pub fn ifft3(input: &Array, norm_factor: f64, } macro_rules! conv_func_def { - ($fn_name:ident, $ffi_name: ident) => ( - /// Convolution - /// - /// The numeric suffix to the function name indicates the dimension in which the - /// convolution operation is going to take place. - /// - /// - 1 - Indicates 1d convolution - /// - 2 - Indicates 2d convolution - /// - 3 - Indicates 3d convolution + ($doc_str: expr, $fn_name:ident, $ffi_name: ident) => ( + #[doc=$doc_str] /// - /// # Parameters + ///# Parameters /// /// - `signal` is the input signal /// - `filter` is the signal that shall be flipped for convolution operation /// - `mode` indicates if the convolution should be expanded or not(where output size - /// equals input) + /// equals input). It takes a value of type [ConvMode](./enum.ConvMode.html) /// - `domain` indicates if the convolution should be performed in frequencey or spatial - /// domain + /// domain. It takes a value of type [ConvDomain](./enum.ConvDomain.html) /// - /// # Return Values + ///# Return Values /// - /// The convolved Array + /// Convolved Array #[allow(unused_mut)] pub fn $fn_name(signal: &Array, filter: &Array, mode: ConvMode, domain: ConvDomain) -> Array { @@ -307,9 +314,9 @@ macro_rules! conv_func_def { ) } -conv_func_def!(convolve1, af_convolve1); -conv_func_def!(convolve2, af_convolve2); -conv_func_def!(convolve3, af_convolve3); +conv_func_def!("1d convolution", convolve1, af_convolve1); +conv_func_def!("2d convolution", convolve2, af_convolve2); +conv_func_def!("3d convolution", convolve3, af_convolve3); /// Separable convolution for 2d signals /// @@ -337,26 +344,19 @@ pub fn convolve2_sep(cfilt: &Array, rfilt: &Array, signal: &Array, } macro_rules! fft_conv_func_def { - ($fn_name:ident, $ffi_name: ident) => ( - /// Convolution using Fast-fourier transform + ($doc_str: expr, $fn_name:ident, $ffi_name: ident) => ( + #[doc=$doc_str] /// - /// The numeric suffix to the function name indicates the dimension in which the - /// convolution operation is going to take place. - /// - /// - 1 - Indicates 1d convolution - /// - 2 - Indicates 2d convolution - /// - 3 - Indicates 3d convolution - /// - /// # Parameters + ///# Parameters /// /// - `signal` is the input signal /// - `filter` is the signal that shall be used for convolution operation /// - `mode` indicates if the convolution should be expanded or not(where output size - /// equals input) + /// equals input). It takes values of type [ConvMode](./enum.ConvMode.html) /// - /// # Return Values + ///# Return Values /// - /// The convolved Array + /// Convolved Array #[allow(unused_mut)] pub fn $fn_name(signal: &Array, filter: &Array, mode: ConvMode) -> Array { @@ -371,9 +371,9 @@ macro_rules! fft_conv_func_def { ) } -fft_conv_func_def!(fft_convolve1, af_fft_convolve1); -fft_conv_func_def!(fft_convolve2, af_fft_convolve2); -fft_conv_func_def!(fft_convolve3, af_fft_convolve3); +fft_conv_func_def!("1d convolution using fast-fourier transform", fft_convolve1, af_fft_convolve1); +fft_conv_func_def!("2d convolution using fast-fourier transform", fft_convolve2, af_fft_convolve2); +fft_conv_func_def!("3d convolution using fast-fourier transform", fft_convolve3, af_fft_convolve3); /// Finite impulse filter /// @@ -623,4 +623,4 @@ pub fn fft3_c2r(input: &Array, norm_factor: f64, is_odd: bool) -> Array { HANDLE_ERROR(AfError::from(err_val)); Array::from(temp) } -} \ No newline at end of file +} diff --git a/src/sparse/mod.rs b/src/sparse/mod.rs new file mode 100644 index 000000000..1950edcb8 --- /dev/null +++ b/src/sparse/mod.rs @@ -0,0 +1,288 @@ +extern crate libc; + +use array::Array; +use defines::{AfError, SparseFormat}; +use error::HANDLE_ERROR; +use self::libc::{uint8_t, c_void, c_int}; +use util::HasAfEnum; + +type MutAfArray = *mut self::libc::c_longlong; +type AfArray = self::libc::c_longlong; +type DimT = self::libc::c_longlong; +type MutDimT = *mut self::libc::c_longlong; + +#[allow(dead_code)] +extern { + fn af_create_sparse_array(out: MutAfArray, nRows: DimT, nCols: DimT, vals: AfArray, + rowIdx: AfArray, colIdx: AfArray, stype: uint8_t) -> c_int; + + fn af_create_sparse_array_from_ptr(out: MutAfArray, nRows: DimT, nCols: DimT, nNZ: DimT, + values: *const c_void, rowIdx: *const c_int, colIdx: *const c_int, + aftype: uint8_t, stype: uint8_t, src: uint8_t) -> c_int; + + fn af_create_sparse_array_from_dense(out: MutAfArray, dense: AfArray, stype: uint8_t) -> c_int; + + fn af_sparse_convert_to(out: MutAfArray, input: AfArray, dstStrge: uint8_t) -> c_int; + + fn af_sparse_to_dense(out: MutAfArray, sparse: AfArray) -> c_int; + + fn af_sparse_get_info(vals: MutAfArray, rIdx: MutAfArray, cIdx: MutAfArray, stype: *mut uint8_t, + input: AfArray) -> c_int; + + fn af_sparse_get_values(out: MutAfArray, input: AfArray) -> c_int; + + fn af_sparse_get_row_idx(out: MutAfArray, input: AfArray) -> c_int; + + fn af_sparse_get_col_idx(out: MutAfArray, input: AfArray) -> c_int; + + fn af_sparse_get_nnz(out: MutDimT, input: AfArray) -> c_int; + + fn af_sparse_get_storage(out: *mut uint8_t, input: AfArray) -> c_int; +} + +/// Create sprase matrix from arrays +/// +/// This function converts [Array](./struct.Array.html) of `values` into sparse array +/// of `format` sparse format using arrays `row_indices` and `col_indices`. +/// +/// # Parameters +/// +/// - `rows` is the number of rows in the dense matrix +/// - `cols` is the number of columns in the dense matrix +/// - `values` is the \ref af::array containing the non-zero elements +/// `of the matrix +/// - `row_indices` is the row indices for the sparse array +/// - `col_indices` is the column indices for the sparse array +/// - `format` is the storage format of the sparse array +/// +/// # Return Values +/// +/// Array with data in given sparse format +/// +/// # Note +/// +/// This function only uses references of the input arrays to create the +/// sparse data structure and does not perform deep copies. +pub fn sparse(rows: u64, cols: u64, values: &Array, row_indices: &Array, col_indices: &Array, + format: SparseFormat) -> Array { + unsafe { + let mut temp: i64 = 0; + let err_val = af_create_sparse_array(&mut temp as MutAfArray, rows as DimT, cols as DimT, + values.get() as AfArray, row_indices.get() as AfArray, + col_indices.get() as AfArray, format as uint8_t); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } +} + +/// Create sprase matrix from data on host memory +/// +/// This function converts host array `values` into sparse array of `format` sparse +/// format using host arrays `row_indices` and `col_indices`. +/// +/// # Parameters +/// +/// - `rows` is the number of rows in the dense matrix +/// - `cols` is the number of columns in the dense matrix +/// - `nzz` is the number of non zero elements in the dense matrix +/// - `values` is the \ref af::array containing the non-zero elements +/// `of the matrix +/// - `row_indices` is the row indices for the sparse array +/// - `col_indices` is the column indices for the sparse array +/// - `format` is the storage format of the sparse array +/// +/// # Return Values +/// +/// Array with data in given sparse format +/// +/// # Note +/// +/// The rules for deep copy/shallow copy/reference are the same as for creating a +/// regular [Array](./struct.Array.html). +pub fn sparse_from_host(rows: u64, cols: u64, nzz: u64, + values: &[T], row_indices: &[i32], col_indices: &[i32], + format: SparseFormat) -> Array { + unsafe { + let aftype = T::get_af_dtype(); + let mut temp: i64 = 0; + let err_val = af_create_sparse_array_from_ptr(&mut temp as MutAfArray, + rows as DimT, cols as DimT, nzz as DimT, + values.as_ptr() as *const c_void, + row_indices.as_ptr() as *const c_int, + col_indices.as_ptr() as *const c_int, + aftype as uint8_t, format as uint8_t, 1); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } +} + +/// Convert dense array to sparse array +/// +/// # Parameters +/// +/// - `dense` is the dense format array +/// - `format` is the target sparse format +/// +/// # Return Values +/// +/// Sparse Array +pub fn sparse_from_dense(dense: &Array, format: SparseFormat) -> Array { + unsafe { + let mut temp : i64 = 0; + let err_val = af_create_sparse_array_from_dense(&mut temp as MutAfArray, dense.get() as AfArray, + format as uint8_t); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } +} + +/// Convert between sparse formats +/// +/// # Parameters +/// +/// - `input` is the input sparse array +/// - `format` is the target sparse format +/// +/// # Return Values +/// +/// Sparse Array in targe sparse format. +pub fn sparse_convert_to(input: &Array, format: SparseFormat) -> Array { + unsafe { + let mut temp : i64 = 0; + let err_val = af_sparse_convert_to(&mut temp as MutAfArray, input.get() as AfArray, + format as uint8_t); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } +} + +/// Convert sparse array to dense array +/// +/// # Parameters +/// +/// - `input` is the sparse array +/// +/// # Return Values +/// +/// Dense Array +pub fn sparse_to_dense(input: &Array) -> Array { + unsafe { + let mut temp : i64 = 0; + let err_val = af_sparse_to_dense(&mut temp as MutAfArray, input.get() as AfArray); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } +} + +/// Get sparse Array information +/// +/// # Parameters +/// +/// - `input` is the sparse array +/// +/// # Return Values +/// +/// A tuple of values, row indices, coloumn indices Arrays and SparseFormat enum. +pub fn sparse_get_info(input: &Array) -> (Array, Array, Array, SparseFormat) { + unsafe { + let mut val : i64 = 0; + let mut row : i64 = 0; + let mut col : i64 = 0; + let mut stype : u8 = 0; + let err_val = af_sparse_get_info(&mut val as MutAfArray, &mut row as MutAfArray, + &mut col as MutAfArray, &mut stype as *mut uint8_t, + input.get() as AfArray); + HANDLE_ERROR(AfError::from(err_val)); + (Array::from(val), Array::from(row), Array::from(col), SparseFormat::from(stype as i32)) + } +} + +/// Get values of sparse Array +/// +/// # Parameters +/// +/// - `input` is the sparse array +/// +/// # Return Values +/// +/// Sparse array values +pub fn sparse_get_values(input: &Array) -> Array { + unsafe { + let mut val : i64 = 0; + let err_val = af_sparse_get_values(&mut val as MutAfArray, input.get() as AfArray); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(val) + } +} + +/// Get row indices Array +/// +/// # Parameters +/// +/// - `input` is the sparse array +/// +/// # Return Values +/// +/// Array with row indices values of sparse Array +pub fn sparse_get_row_indices(input: &Array) -> Array { + unsafe { + let mut val : i64 = 0; + let err_val = af_sparse_get_row_idx(&mut val as MutAfArray, input.get() as AfArray); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(val) + } +} + +/// Get cololumn indices Array +/// +/// # Parameters +/// +/// - `input` is the sparse array +/// +/// # Return Values +/// +/// Array with coloumn indices values of sparse Array +pub fn sparse_get_col_indices(input: &Array) -> Array { + unsafe { + let mut val : i64 = 0; + let err_val = af_sparse_get_col_idx(&mut val as MutAfArray, input.get() as AfArray); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(val) + } +} + +/// Get number of non-zero elements in sparse array +/// +/// # Parameters +/// +/// - `input` is the sparse array +/// +/// # Return Values +/// +/// Number of non-zero elements of sparse Array +pub fn sparse_get_nnz(input: &Array) -> i64 { + unsafe { + let mut count : i64 = 0; + let err_val = af_sparse_get_nnz(&mut count as *mut DimT, input.get() as AfArray); + HANDLE_ERROR(AfError::from(err_val)); + count + } +} + +/// Get sparse format +/// +/// # Parameters +/// +/// - `input` is the sparse array +/// +/// # Return Values +/// +/// Sparse array format +pub fn sparse_get_format(input: &Array) -> SparseFormat { + unsafe { + let mut stype : u8 = 0; + let err_val = af_sparse_get_storage(&mut stype as *mut uint8_t, input.get() as AfArray); + HANDLE_ERROR(AfError::from(err_val)); + SparseFormat::from(stype as i32) + } +} diff --git a/src/statistics/mod.rs b/src/statistics/mod.rs index 12ccea02f..cb1269a5c 100644 --- a/src/statistics/mod.rs +++ b/src/statistics/mod.rs @@ -34,18 +34,18 @@ extern { } macro_rules! stat_func_def { - ($fn_name: ident, $ffi_fn: ident) => ( - /// Compute a statistic along given dimension for an Array + ($doc_str: expr, $fn_name: ident, $ffi_fn: ident) => ( + #[doc=$doc_str] /// - /// # Parameters + ///# Parameters /// /// - `input` is the input Array /// - `dim` is dimension along which the current stat has to be computed /// - /// # Return Values + ///# Return Values /// - /// An Array whose size is equal to input except along the dimension which the stat - /// operation is performed. Array size along `dim` will be reduced to one. + /// An Array whose size is equal to input except along the dimension which + /// the stat operation is performed. Array size along `dim` will be reduced to one. #[allow(unused_mut)] pub fn $fn_name(input: &Array, dim: i64) -> Array { unsafe { @@ -58,24 +58,24 @@ macro_rules! stat_func_def { ) } -stat_func_def!(mean, af_mean); -stat_func_def!(stdev, af_stdev); -stat_func_def!(median, af_median); +stat_func_def!("Mean along specified dimension", mean, af_mean); +stat_func_def!("Standard deviation along specified dimension", stdev, af_stdev); +stat_func_def!("Median along specified dimension", median, af_median); macro_rules! stat_wtd_func_def { - ($fn_name: ident, $ffi_fn: ident) => ( - /// Compute a weighted statistic along given dimension for an Array + ($doc_str: expr, $fn_name: ident, $ffi_fn: ident) => ( + #[doc=$doc_str] /// - /// # Parameters + ///# Parameters /// /// - `input` is the input Array /// - `weights` Array has the weights to be used during the stat computation /// - `dim` is dimension along which the current stat has to be computed /// - /// # Return Values + ///# Return Values /// - /// An Array whose size is equal to input except along the dimension which the stat - /// operation is performed. Array size along `dim` will be reduced to one. + /// An Array whose size is equal to input except along the dimension which + /// the stat operation is performed. Array size along `dim` will be reduced to one. #[allow(unused_mut)] pub fn $fn_name(input: &Array, weights: &Array, dim: i64) -> Array { unsafe { @@ -89,8 +89,8 @@ macro_rules! stat_wtd_func_def { ) } -stat_wtd_func_def!(mean_weighted, af_mean_weighted); -stat_wtd_func_def!(var_weighted, af_var_weighted); +stat_wtd_func_def!("Weighted mean along specified dimension", mean_weighted, af_mean_weighted); +stat_wtd_func_def!("Weight variance along specified dimension", var_weighted, af_var_weighted); /// Compute Variance along a specific dimension /// @@ -159,14 +159,14 @@ pub fn var_all(input: &Array, isbiased: bool) -> (f64, f64) { } macro_rules! stat_all_func_def { - ($fn_name: ident, $ffi_fn: ident) => ( - /// Compute statistic for all elements of Array + ($doc_str: expr, $fn_name: ident, $ffi_fn: ident) => ( + #[doc=$doc_str] /// - /// # Parameters + ///# Parameters /// /// - `input` is the input Array /// - /// # Return Values + ///# Return Values /// /// A tuple of 64-bit floating point values with the stat values. #[allow(unused_mut)] @@ -183,20 +183,20 @@ macro_rules! stat_all_func_def { ) } -stat_all_func_def!(mean_all, af_mean_all); -stat_all_func_def!(stdev_all, af_stdev_all); -stat_all_func_def!(median_all, af_median_all); +stat_all_func_def!("Compute mean of all data", mean_all, af_mean_all); +stat_all_func_def!("Compute standard deviation of all data", stdev_all, af_stdev_all); +stat_all_func_def!("Compute median of all data", median_all, af_median_all); macro_rules! stat_wtd_all_func_def { - ($fn_name: ident, $ffi_fn: ident) => ( - /// Compute weighted statistic for all elements of Array + ($doc_str: expr, $fn_name: ident, $ffi_fn: ident) => ( + #[doc=$doc_str] /// - /// # Parameters + ///# Parameters /// /// - `input` is the input Array /// - `weights` Array has the weights /// - /// # Return Values + ///# Return Values /// /// A tuple of 64-bit floating point values with the stat values. #[allow(unused_mut)] @@ -213,8 +213,8 @@ macro_rules! stat_wtd_all_func_def { ) } -stat_wtd_all_func_def!(mean_all_weighted, af_mean_all_weighted); -stat_wtd_all_func_def!(var_all_weighted, af_var_all_weighted); +stat_wtd_all_func_def!("Compute weighted mean of all data", mean_all_weighted, af_mean_all_weighted); +stat_wtd_all_func_def!("Compute weighted variance of all data", var_all_weighted, af_var_all_weighted); /// Compute correlation coefficient /// @@ -235,4 +235,4 @@ pub fn corrcoef(x: &Array, y: &Array) -> (f64, f64) { HANDLE_ERROR(AfError::from(err_val)); (real, imag) } -} \ No newline at end of file +} diff --git a/src/util.rs b/src/util.rs index ba1726453..db8740bb2 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,8 +1,27 @@ +extern crate libc; extern crate num; use defines::{AfError, ColorMap, ConvDomain, ConvMode, DType, InterpType, MatProp, MatchType}; +use defines::{SparseFormat, BinaryOp, RandomEngineType}; +use error::HANDLE_ERROR; use std::mem; use self::num::Complex; +use self::libc::{uint8_t, c_int, size_t}; + +#[allow(dead_code)] +extern { + fn af_get_size_of(size: *mut size_t, aftype: uint8_t) -> c_int; +} + +/// Get size, in bytes, of the arrayfire native type +pub fn get_size(value: DType) -> usize { + unsafe { + let mut ret_val: usize = 0; + let err_val = af_get_size_of(&mut ret_val as *mut size_t, value as uint8_t); + HANDLE_ERROR(AfError::from(err_val)); + ret_val + } +} impl From for AfError { fn from(t: i32) -> AfError { @@ -20,7 +39,7 @@ impl From for DType { impl From for InterpType { fn from(t: i32) -> InterpType { - assert!(InterpType::NEAREST as i32 <= t && t <= InterpType::CUBIC as i32); + assert!(InterpType::NEAREST as i32 <= t && t <= InterpType::BICUBIC_SPLINE as i32); unsafe { mem::transmute(t) } } } @@ -117,3 +136,24 @@ impl_has_af_enum!(i64, DType::S64); impl_has_af_enum!(u64, DType::U64); impl_has_af_enum!(i16, DType::S16); impl_has_af_enum!(u16, DType::U16); + +impl From for SparseFormat { + fn from(t: i32) -> SparseFormat { + assert!(SparseFormat::DENSE as i32 <= t && t <= SparseFormat::COO as i32); + unsafe { mem::transmute(t) } + } +} + +impl From for BinaryOp { + fn from(t: i32) -> BinaryOp { + assert!(BinaryOp::ADD as i32 <= t && t <= BinaryOp::MAX as i32); + unsafe { mem::transmute(t) } + } +} + +impl From for RandomEngineType { + fn from(t: i32) -> RandomEngineType { + assert!(RandomEngineType::PHILOX_4X32_10 as i32 <= t && t <= RandomEngineType::MERSENNE_GP11213 as i32); + unsafe { mem::transmute(t) } + } +} diff --git a/src/vision/mod.rs b/src/vision/mod.rs index 48791a458..ab88a6004 100644 --- a/src/vision/mod.rs +++ b/src/vision/mod.rs @@ -75,7 +75,8 @@ pub struct Features { } macro_rules! feat_func_def { - ($fn_name: ident, $ffi_name: ident) => ( + ($doc_str: expr, $fn_name: ident, $ffi_name: ident) => ( + #[doc=$doc_str] pub fn $fn_name(&self) -> Array { unsafe { let mut temp: i64 = 0; @@ -84,7 +85,7 @@ macro_rules! feat_func_def { let temp_array = Array::from(temp); let retained = temp_array.clone(); mem::forget(temp_array); - + HANDLE_ERROR(AfError::from(err_val)); retained } @@ -93,6 +94,9 @@ macro_rules! feat_func_def { } impl Features { + /// Create and return an object of type Features + /// + /// This object is basically a bunch of Arrays. #[allow(unused_mut)] pub fn new(n: u64) -> Features { unsafe { @@ -115,12 +119,13 @@ impl Features { } } - feat_func_def!(xpos, af_get_features_xpos); - feat_func_def!(ypos, af_get_features_ypos); - feat_func_def!(score, af_get_features_score); - feat_func_def!(orientation, af_get_features_orientation); - feat_func_def!(size, af_get_features_size); + feat_func_def!("Get x coordinates Array", xpos, af_get_features_xpos); + feat_func_def!("Get y coordinates Array", ypos, af_get_features_ypos); + feat_func_def!("Get score Array", score, af_get_features_score); + feat_func_def!("Get orientation Array", orientation, af_get_features_orientation); + feat_func_def!("Get features size Array", size, af_get_features_size); + /// Get the internal handle for [Features](./struct.Features.html) object pub fn get(&self) -> i64 { self.feat } @@ -500,4 +505,4 @@ pub fn homography(x_src: &Array, y_src: &Array, HANDLE_ERROR(AfError::from(err_val)); (Array::from(temp), inliers) } -} \ No newline at end of file +}