From b088f07725fdfa86b962cacdf25c9da425f094a4 Mon Sep 17 00:00:00 2001 From: pradeep Date: Fri, 11 Mar 2016 15:49:47 +0530 Subject: [PATCH 1/5] API Catchup to 3.3.0 version More detailed information on the new release can be found at the following URL https://github.com/arrayfire/arrayfire/releases/tag/v3.3.0 --- Cargo.toml | 2 +- arrayfire | 2 +- examples/unified.rs | 12 ++-- src/array.rs | 111 +++++++++++++++++++++++++++++++++--- src/backend.rs | 23 +++++++- src/defines.rs | 33 ++++++++--- src/device/mod.rs | 134 +++++++++++++++++++++++++++++++++++++++++++- src/graphics.rs | 63 ++++++++++++++++++++- src/image/mod.rs | 49 ++++++++++++++++ src/lapack/mod.rs | 18 ++++++ src/lib.rs | 10 ++-- 11 files changed, 423 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 93fd8e562..bbd9a1a14 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.2.0" +version = "3.3.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/arrayfire b/arrayfire index f263db079..5842ed251 160000 --- a/arrayfire +++ b/arrayfire @@ -1 +1 @@ -Subproject commit f263db079443f7818a73ee94e237dd53ef017d01 +Subproject commit 5842ed25195848653148fa9b3a8270255d83f5b8 diff --git a/examples/unified.rs b/examples/unified.rs index 713a6f068..d865e3401 100644 --- a/examples/unified.rs +++ b/examples/unified.rs @@ -24,9 +24,9 @@ fn main() { println!("There are {:?} available backends", get_backend_count().unwrap()); let available = get_available_backends().unwrap(); - if available.contains(&Backend::AF_BACKEND_CPU){ + if available.contains(&Backend::CPU){ println!("Evaluating CPU Backend..."); - let err = set_backend(Backend::AF_BACKEND_CPU); + let err = set_backend(Backend::CPU); println!("There are {} CPU compute devices", device_count().unwrap()); match err { Ok(_) => test_backend(), @@ -34,9 +34,9 @@ fn main() { }; } - if available.contains(&Backend::AF_BACKEND_CUDA){ + if available.contains(&Backend::CUDA){ println!("Evaluating CUDA Backend..."); - let err = set_backend(Backend::AF_BACKEND_CUDA); + let err = set_backend(Backend::CUDA); println!("There are {} CUDA compute devices", device_count().unwrap()); match err { Ok(_) => test_backend(), @@ -44,9 +44,9 @@ fn main() { }; } - if available.contains(&Backend::AF_BACKEND_OPENCL){ + if available.contains(&Backend::OPENCL){ println!("Evaluating OpenCL Backend..."); - let err = set_backend(Backend::AF_BACKEND_OPENCL); + let err = set_backend(Backend::OPENCL); println!("There are {} OpenCL compute devices", device_count().unwrap()); match err { Ok(_) => test_backend(), diff --git a/src/array.rs b/src/array.rs index 77d1a1294..45914b1bf 100644 --- a/src/array.rs +++ b/src/array.rs @@ -72,6 +72,21 @@ extern { 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; + + fn af_get_device_id(device: *mut c_int, input: AfArray) -> c_int; + + 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; + + fn af_get_strides(s0: *mut DimT, s1: *mut DimT, s2: *mut DimT, s3: *mut DimT, + arr: AfArray) -> c_int; + + fn af_get_offset(offset: *mut DimT, arr: AfArray) -> c_int; + + fn af_is_linear(result: *mut c_int, arr: AfArray) -> c_int; + + fn af_is_owner(result: *mut c_int, arr: AfArray) -> c_int; } /// A multidimensional data container @@ -122,21 +137,68 @@ impl Array { } } + /// Constructs a new Array object from strided data + /// + /// This data can possiblly offseted using an additiona `offset` parameter. + /// + /// # Examples + /// + /// ``` + /// let values: &[f32] = &[1.0, 2.0, 3.0]; + /// let indices = Array::new(Dim4::new(&[3, 1, 1, 1]), values, Aftype::F32).unwrap(); + /// ``` + #[allow(unused_mut)] + pub fn new_strided(slice: &[T], offset: i64, + dims: Dim4, strides: Dim4, + aftype: Aftype) -> Result { + unsafe { + let mut temp: i64 = 0; + let err_val = af_create_strided_array(&mut temp as MutAfArray, + slice.as_ptr() as *const c_void, + offset as DimT, + 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); + match err_val { + 0 => Ok(Array {handle: temp}), + _ => Err(AfError::from(err_val)), + } + } + } + /// Returns the backend of the Array /// /// # Return Values /// /// Returns an value of type `Backend` which indicates which backend /// was active when Array was created. - pub fn get_backend(&self) -> Backend { + pub fn get_backend(&self) -> Result { unsafe { let mut ret_val: i32 = 0; - af_get_backend_id(&mut ret_val as *mut c_int, self.handle as AfArray); - match ret_val { - 1 => Backend::AF_BACKEND_CPU, - 2 => Backend::AF_BACKEND_CUDA, - 3 => Backend::AF_BACKEND_OPENCL, - _ => Backend::AF_BACKEND_DEFAULT, + let err_val = af_get_backend_id(&mut ret_val as *mut c_int, self.handle as AfArray); + match (err_val, ret_val) { + (0, 1) => Ok(Backend::CPU), + (0, 2) => Ok(Backend::CUDA), + (0, 3) => Ok(Backend::OPENCL), + _ => Err(AfError::from(err_val)), + } + } + } + + /// Returns the device identifier(integer) on which the Array was created + /// + /// # Return Values + /// + /// Return the device id on which Array was created. + pub fn get_device_id(&self) -> Result { + unsafe { + let mut ret_val: i32 = 0; + let err_val = af_get_device_id(&mut ret_val as *mut c_int, self.handle as AfArray); + match err_val { + 0 => Ok(ret_val), + _ => Err(AfError::from(err_val)), + } } } @@ -172,8 +234,8 @@ impl Array { let mut ret1: i64 = 0; let mut ret2: i64 = 0; let mut ret3: i64 = 0; - let err_val = af_get_dims(&mut ret0 as *mut c_longlong, &mut ret1 as *mut c_longlong, - &mut ret2 as *mut c_longlong, &mut ret3 as *mut c_longlong, + let err_val = af_get_dims(&mut ret0 as *mut DimT, &mut ret1 as *mut DimT, + &mut ret2 as *mut DimT, &mut ret3 as *mut DimT, self.handle as AfArray); match err_val { 0 => Ok(Dim4::new(&[ret0 as u64, ret1 as u64, ret2 as u64, ret3 as u64])), @@ -182,6 +244,23 @@ impl Array { } } + /// Returns the strides of the Array + pub fn strides(&self) -> Result { + unsafe { + let mut ret0: i64 = 0; + let mut ret1: i64 = 0; + let mut ret2: i64 = 0; + let mut ret3: i64 = 0; + let err_val = af_get_strides(&mut ret0 as *mut DimT, &mut ret1 as *mut DimT, + &mut ret2 as *mut DimT, &mut ret3 as *mut DimT, + self.handle as AfArray); + match err_val { + 0 => Ok(Dim4::new(&[ret0 as u64, ret1 as u64, ret2 as u64, ret3 as u64])), + _ => Err(AfError::from(err_val)), + } + } + } + /// Returns the number of dimensions of the Array pub fn numdims(&self) -> Result { unsafe { @@ -194,6 +273,18 @@ impl Array { } } + /// Returns the offset to the pointer from where data begins + pub fn offset(&self) -> Result { + unsafe { + let mut ret_val: i64 = 0; + let err_val = af_get_offset(&mut ret_val as *mut DimT, self.handle as AfArray); + match err_val { + 0 => Ok(ret_val), + _ => Err(AfError::from(err_val)), + } + } + } + /// Returns the native FFI handle for Rust object `Array` pub fn get(&self) -> i64 { self.handle @@ -247,6 +338,8 @@ impl Array { 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); /// Cast the Array data type to `target_type` pub fn cast(&self, target_type: Aftype) -> Result { diff --git a/src/backend.rs b/src/backend.rs index 0070cfd80..402ad297f 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -7,6 +7,7 @@ extern { fn af_set_backend(bknd: uint8_t) -> c_int; fn af_get_backend_count(num_backends: *mut c_uint) -> c_int; fn af_get_available_backends(backends: *mut c_int) -> c_int; + fn af_get_active_backend(backend: *mut c_int) -> c_int; } /// Toggle backends between cuda, opencl or cpu @@ -47,12 +48,28 @@ pub fn get_available_backends() -> Result, AfError> { match err_val { 0 => { let mut b = Vec::new(); - if temp & 0b0100 == 0b0100 { b.push(Backend::AF_BACKEND_OPENCL); } - if temp & 0b0010 == 0b0010 { b.push(Backend::AF_BACKEND_CUDA); } - if temp & 0b0001 == 0b0001 { b.push(Backend::AF_BACKEND_CPU); } + if temp & 0b0100 == 0b0100 { b.push(Backend::OPENCL); } + if temp & 0b0010 == 0b0010 { b.push(Backend::CUDA); } + if temp & 0b0001 == 0b0001 { b.push(Backend::CPU); } Ok(b) }, _ => Err(AfError::from(err_val)), } } } + +/// Get current active backend +#[allow(unused_mut)] +pub fn get_active_backend() -> Result { + unsafe { + let mut temp: i32 = 0; + let err_val = af_get_active_backend(&mut temp as *mut c_int); + match (err_val, temp) { + (0, 0) => Ok(Backend::DEFAULT), + (0, 1) => Ok(Backend::CPU), + (0, 2) => Ok(Backend::CUDA), + (0, 4) => Ok(Backend::OPENCL), + _ => Err(AfError::from(err_val)), + } + } +} diff --git a/src/defines.rs b/src/defines.rs index 8d5597d82..c2a4f8ddd 100644 --- a/src/defines.rs +++ b/src/defines.rs @@ -28,6 +28,8 @@ pub enum AfError { ERR_DIFF_TYPE = 205, /// Function does not support GFOR / batch mode ERR_BATCH = 207, + /// Input does not belong to the current device + ERR_DEVICE = 208, // 300-399 Errors for missing software features /// The option is not supported ERR_NOT_SUPPORTED = 301, @@ -51,22 +53,22 @@ pub enum AfError { #[derive(Clone, Copy, Debug, PartialEq)] pub enum Backend { /// Default backend order: OpenCL -> CUDA -> CPU - AF_BACKEND_DEFAULT = 0, + DEFAULT = 0, /// CPU a.k.a sequential algorithms - AF_BACKEND_CPU = 1, + CPU = 1, /// CUDA Compute Backend - AF_BACKEND_CUDA = 2, + CUDA = 2, /// OpenCL Compute Backend - AF_BACKEND_OPENCL = 4 + OPENCL = 4 } impl Display for Backend { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { let text = match *self { - Backend::AF_BACKEND_OPENCL => "OpenCL", - Backend::AF_BACKEND_CUDA => "Cuda", - Backend::AF_BACKEND_CPU => "CPU", - Backend::AF_BACKEND_DEFAULT => "Default", + Backend::OPENCL => "OpenCL", + Backend::CUDA => "Cuda", + Backend::CPU => "CPU", + Backend::DEFAULT => "Default", }; write!(f, "{}", text) } @@ -91,6 +93,7 @@ impl Error for AfError { AfError::ERR_TYPE => "The type is not supported by this function", AfError::ERR_DIFF_TYPE => "The type of input arrays are not compatible", AfError::ERR_BATCH => "Function does not support GFOR / batch mode", + AfError::ERR_DEVICE => "Array does not belong to device", AfError::ERR_NOT_SUPPORTED => "The option is not supported", AfError::ERR_NOT_CONFIGURED => "This build of ArrayFire does not support this feature", AfError::ERR_NO_DBL => "This device does not support double", @@ -305,3 +308,17 @@ pub enum HomographyType { /// Least Median of Squares LMEDS = 1, } + +/// Plotting markers +#[repr(C)] +#[derive(Copy, Clone)] +pub enum MarkerType { + NONE = 0, + POINT = 1, + CIRCLE = 2, + SQUARE = 3, + TRIANGLE = 4, + CROSS = 5, + PLUS = 6, + STAR = 7 +} diff --git a/src/device/mod.rs b/src/device/mod.rs index fd17e1fd0..0215b73d0 100644 --- a/src/device/mod.rs +++ b/src/device/mod.rs @@ -1,15 +1,23 @@ extern crate libc; use defines::AfError; -use self::libc::c_int; +use self::libc::{c_int, size_t, c_char}; +use std::ffi::CString; extern { fn af_get_version(major: *mut c_int, minor: *mut c_int, patch: *mut c_int) -> c_int; fn af_info() -> c_int; + fn af_init() -> c_int; fn af_get_device_count(nDevices: *mut c_int) -> c_int; fn af_get_dbl_support(available: *mut c_int, device: c_int) -> c_int; fn af_set_device(device: c_int) -> c_int; fn af_get_device(device: *mut c_int) -> c_int; + fn af_device_mem_info(alloc_bytes: *mut size_t, alloc_buffers: *mut size_t, + lock_bytes: *mut size_t, lock_buffers: *mut size_t) -> c_int; + fn af_print_mem_info(msg: *const c_char, device_id: c_int) -> c_int; + fn af_set_mem_step_size(step_bytes: size_t) -> c_int; + fn af_get_mem_step_size(step_bytes: *mut size_t) -> c_int; + fn af_device_gc() -> c_int; fn af_sync(device: c_int) -> c_int; } @@ -52,6 +60,20 @@ pub fn info() -> Result<(), AfError> { } } +/// Initialize ArrayFire library +/// +/// 0th device will be the default device unless init call +/// is followed by set_device +pub fn init() -> Result<(), AfError> { + unsafe { + let err_val = af_init(); + match err_val { + 0 => Ok(()), + _ => Err(AfError::from(err_val)), + } + } +} + /// Get total number of available devices pub fn device_count() -> Result { unsafe { @@ -111,6 +133,116 @@ pub fn get_device() -> Result { } } +/// Get memory information from the memory manager for the current active device +/// +/// # Parameters +/// +/// This function doesn't take any input parameters +/// +/// # Return Values +/// +/// A quadruple of values regarding the following information. +/// +/// * Number of bytes allocated +/// * Number of buffers allocated +/// * Number of bytes locked +/// * Number of buffers locked +pub fn device_mem_info() -> Result<(u64, u64, u64, u64), AfError> { + unsafe { + let mut o0: u64 = 0; + let mut o1: u64 = 0; + let mut o2: u64 = 0; + let mut o3: u64 = 0; + let err_val = af_device_mem_info(&mut o0 as *mut size_t, + &mut o1 as *mut size_t, + &mut o2 as *mut size_t, + &mut o3 as *mut size_t); + match err_val { + 0 => Ok((o0, o1, o2, o3)), + _ => Err(AfError::from(err_val)), + } + } +} + +/// Print buffer details from the ArrayFire device manager +/// +/// This information is printed in the form of a table. +/// +/// # Parameters +/// +/// - `msg` is a message to print before the table +/// - `device` is the id of the device for which buffer details are to be printed +/// +/// # Return Values +/// +/// None +pub fn print_mem_info(msg: String, device: i32) -> Result<(), AfError> { + unsafe { + let cmsg = CString::new(msg.as_bytes()); + match cmsg { + Ok(v) => { + let err_val = af_print_mem_info(v.to_bytes_with_nul().as_ptr() as * const c_char, + device as c_int); + match err_val { + 0 => Ok(()), + _ => Err(AfError::from(err_val)), + } + }, + Err(_) => Err(AfError::from(AfError::ERR_INTERNAL)), + } + } +} + +/// Set the minimum memory chunk size +/// +/// # Parameters +/// +/// - `step_bytes` is the size of minimum memory chunk in bytes +/// +/// # Return Values +/// +/// None +pub fn set_mem_step_size(step_bytes: u64) -> Result<(), AfError> { + unsafe { + let err_val = af_set_mem_step_size(step_bytes as size_t); + match err_val { + 0 => Ok(()), + _ => Err(AfError::from(err_val)), + } + } +} + +/// Get the minimum memory chunk size +/// +/// # Parameters +/// +/// None +/// +/// # Return Values +/// +/// Returns is the size of minimum memory chunk in bytes +pub fn get_mem_step_size() -> Result { + unsafe { + let mut temp: u64 = 0; + let err_val = af_get_mem_step_size(&mut temp as *mut size_t); + match err_val { + 0 => Ok(temp), + _ => Err(AfError::from(err_val)), + } + } +} + +/// Call the garbage collection routine +pub fn device_gc() -> Result<(), AfError> { + unsafe { + let err_val = af_device_gc(); + match err_val { + 0 => Ok(()), + _ => Err(AfError::from(err_val)), + } + } +} + /// Sync all operations on given device /// /// # Parameters diff --git a/src/graphics.rs b/src/graphics.rs index 718da6e71..1413f9151 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -2,7 +2,7 @@ extern crate libc; use array::Array; use defines::AfError; -use defines::ColorMap; +use defines::{ColorMap, MarkerType}; use self::libc::{c_int, c_uint, c_double, c_char}; use std::ffi::CString; @@ -17,6 +17,7 @@ extern { 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_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; @@ -24,6 +25,8 @@ extern { 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_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; @@ -151,6 +154,25 @@ impl Window { } } + /// Set window visibility + /// + /// # Parameters + /// + /// - `is_visible` is a boolean indicating whether window is to be hidden or brought into focus + /// + /// # Return Values + /// + /// None + pub fn set_visibility(&self, is_visible: bool) -> Result<(), AfError> { + unsafe { + let err_val = af_set_visibility(self.handle as WndHandle, is_visible as c_int); + match err_val { + 0 => Ok(()), + _ => Err(AfError::from(err_val)), + } + } + } + /// Set window size /// /// # Parameters @@ -307,4 +329,43 @@ impl Window { } } } + + /// Render give Arrays as 2d scatter plot + pub fn draw_scatter(&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); + match err_val { + 0 => (), + _ => panic!("Rendering scatter failed: {}", err_val), + } + } + } + + /// Render give Array as 3d scatter plot + pub fn draw_scatter3(&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_scatter3(self.handle as WndHandle, + vals.get() as AfArray, + marker as c_int, + cprops as *const Cell as CellPtr); + match err_val { + 0 => (), + _ => panic!("Rendering scatter3 failed: {}", err_val), + } + } + } } diff --git a/src/image/mod.rs b/src/image/mod.rs index 5188b0819..c81c7deae 100644 --- a/src/image/mod.rs +++ b/src/image/mod.rs @@ -95,6 +95,8 @@ extern { fn af_ycbcr2rgb(out: MutAfArray, input: AfArray, stnd: c_int) -> c_int; 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; } /// Calculate the gradients @@ -1141,3 +1143,50 @@ pub fn ycbcr2rgb(input: &Array, standard: YCCStd) -> Result { } } } + +/// Function to check if Image I/O is available +/// +/// # Parameters +/// +/// None +/// +/// # Return Values +/// +/// Return a boolean indicating if ArrayFire was compiled with Image I/O support +pub fn is_imageio_available() -> bool { + unsafe { + let mut temp: i32 = 0; + af_is_image_io_available(&mut temp as *mut c_int); + temp > 0 // Return boolean fla + } +} + +/// Transform input coordinates +/// +/// The transform function uses a perspective transform matrix to transform input coordinates +/// (given as two dimensions) into a coordinates matrix. +/// +/// The output is a 4x2 matrix, indicating the coordinates of the 4 bidimensional transformed +/// points. +/// +/// # Parameters +/// +/// - `tf` is the transformation matrix +/// - `d0` is the first input dimension +/// - `d1` is the second input dimension +/// +/// # Return Values +/// +/// Transformed coordinates +pub fn transform_coords(tf: &Array, d0: f32, d1: f32) -> Result { + unsafe { + let mut temp: i64 = 0; + let err_val = af_transform_coordinates(&mut temp as MutAfArray, + tf.get() as AfArray, + d0 as c_float, d1 as c_float); + match err_val { + 0 => Ok(Array::from(temp)), + _ => Err(AfError::from(err_val)), + } + } +} diff --git a/src/lapack/mod.rs b/src/lapack/mod.rs index ca02805db..e7a32e000 100644 --- a/src/lapack/mod.rs +++ b/src/lapack/mod.rs @@ -26,6 +26,7 @@ extern { fn af_rank(rank: *mut c_uint, input: AfArray, tol: c_double) -> c_int; fn af_det(det_real: MutDouble, det_imag: MutDouble, input: AfArray) -> c_int; fn af_norm(out: MutDouble, input: AfArray, ntype: uint8_t, p: c_double, q: c_double) -> c_int; + fn af_is_lapack_available(out: *mut c_int) -> c_int; } /// Perform Singular Value Decomposition @@ -414,3 +415,20 @@ pub fn norm(input: &Array, ntype: NormType, p: f64, q: f64) -> Result bool { + unsafe { + let mut temp: i32 = 0; + af_is_lapack_available(&mut temp as *mut c_int); + temp > 0 // Return boolean fla + } +} diff --git a/src/lib.rs b/src/lib.rs index 09d7a5b1e..fe22fd220 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,7 @@ pub use arith::{sqrt, log, log1p, log10, log2, pow2, exp, expm1, erf, erfc, root pub use arith::{cbrt, factorial, tgamma, lgamma, iszero, isinf, isnan}; mod arith; -pub use backend::{set_backend, get_backend_count, get_available_backends}; +pub use backend::{set_backend, get_backend_count, get_available_backends, get_active_backend}; mod backend; pub use blas::{matmul, dot, transpose, transpose_inplace}; @@ -37,12 +37,14 @@ pub use data::{reorder, shift, moddims, flat, flip}; pub use data::{select, selectl, selectr, replace, replace_scalar}; mod data; -pub use device::{get_version, info, device_count, is_double_available, set_device, get_device, sync}; +pub use device::{get_version, info, init, device_count, is_double_available, set_device, get_device}; +pub use device::{device_mem_info, print_mem_info, set_mem_step_size, get_mem_step_size, device_gc, sync}; mod device; pub use defines::{Aftype, AfError, Backend, ColorMap, YCCStd, HomographyType}; pub use defines::{InterpType, BorderType, MatchType, NormType}; pub use defines::{Connectivity, ConvMode, ConvDomain, ColorSpace, MatProp}; +pub use defines::{MarkerType}; mod defines; pub use dim4::Dim4; @@ -65,11 +67,11 @@ 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::{unwrap, wrap, sat, rgb2ycbcr, ycbcr2rgb}; +pub use image::{unwrap, wrap, sat, rgb2ycbcr, ycbcr2rgb, is_imageio_available, transform_coords}; mod image; pub use lapack::{svd, lu, qr, cholesky, solve, solve_lu, inverse, det, rank, norm}; -pub use lapack::{svd_inplace, lu_inplace, qr_inplace, cholesky_inplace}; +pub use lapack::{svd_inplace, lu_inplace, qr_inplace, cholesky_inplace, is_lapack_available}; mod lapack; mod num; From bb8f2da987562af2ead5ec8bf40d6273499b19f9 Mon Sep 17 00:00:00 2001 From: pradeep Date: Sat, 12 Mar 2016 13:45:26 +0530 Subject: [PATCH 2/5] Improved data generation API and Array creation API Defined and implemented a trait `HasAfEnum` for the types supported by ArrayFire. This trait is used by the Array creation and data generation functions now making the function API more terse. Changed the examples to reflect the new modifications. --- examples/helloworld.rs | 6 ++--- examples/pi.rs | 4 ++-- examples/snow.rs | 2 +- examples/unified.rs | 2 +- src/array.rs | 26 +++++++++------------ src/data/mod.rs | 22 +++++++++--------- src/defines.rs | 1 + src/image/mod.rs | 6 ++--- src/index.rs | 14 ++++++------ src/lib.rs | 1 + src/util.rs | 52 ++++++++++++++++++++++++++++++++++++++++++ src/vision/mod.rs | 12 ++++++---- 12 files changed, 100 insertions(+), 48 deletions(-) diff --git a/examples/helloworld.rs b/examples/helloworld.rs index 356d3986c..f61612d0a 100644 --- a/examples/helloworld.rs +++ b/examples/helloworld.rs @@ -10,7 +10,7 @@ fn main() { let num_rows: u64 = 5; let num_cols: u64 = 3; let values: &[f32] = &[1.0, 2.0, 3.0]; - let indices = Array::new(Dim4::new(&[3, 1, 1, 1]), values, Aftype::F32).unwrap(); + let indices = Array::new(values, Dim4::new(&[3, 1, 1, 1])).unwrap(); let dims = Dim4::new(&[num_rows, num_cols, 1, 1]); @@ -74,13 +74,13 @@ fn main() { println!("Set last row to 1's"); let r_dims = Dim4::new(&[3, 1, 1, 1]); let r_input: [f32; 3] = [1.0, 1.0, 1.0]; - let r = Array::new(r_dims, &r_input, Aftype::F32).unwrap(); + let r = Array::new(&r_input, r_dims).unwrap(); print(&set_row(&a, &r, num_rows - 1).unwrap()); println!("Create 2-by-3 matrix from host data"); let d_dims = Dim4::new(&[2, 3, 1, 1]); let d_input: [i32; 6] = [1, 2, 3, 4, 5, 6]; - let d = &Array::new(d_dims, &d_input, Aftype::S32).unwrap(); + let d = &Array::new(&d_input, d_dims).unwrap(); print(d); // printf("Copy last column onto first\n"); diff --git a/examples/pi.rs b/examples/pi.rs index 9ec60d61d..5989fb5de 100644 --- a/examples/pi.rs +++ b/examples/pi.rs @@ -12,8 +12,8 @@ fn main() { let samples = 20_000_000; let dims = Dim4::new(&[samples, 1, 1, 1]); - let x = &randu(dims, Aftype::F32).unwrap(); - let y = &randu(dims, Aftype::F32).unwrap(); + let x = &randu::(dims).unwrap(); + let y = &randu::(dims).unwrap(); let start = PreciseTime::now(); diff --git a/examples/snow.rs b/examples/snow.rs index d812680d9..f51dd137d 100644 --- a/examples/snow.rs +++ b/examples/snow.rs @@ -16,7 +16,7 @@ fn main() { let dims = Dim4::new(&[1280, 720, 3, 1]); loop { - randu(dims, Aftype::F32).as_ref() + randu::(dims).as_ref() .map(|arr| wnd.draw_image(arr, None)); if wnd.is_closed().unwrap() == true { break; } diff --git a/examples/unified.rs b/examples/unified.rs index d865e3401..6a5d7fce5 100644 --- a/examples/unified.rs +++ b/examples/unified.rs @@ -11,7 +11,7 @@ fn test_backend(){ let dims = Dim4::new(&[num_rows, num_cols, 1, 1]); println!("Create a 10-by-10 matrix of random floats on the compute device"); - let a = match randu(dims, Aftype::F32) { + let a = match randu::(dims) { Ok(value) => value, Err(error) => panic!("{}", error), }; diff --git a/src/array.rs b/src/array.rs index 45914b1bf..043e9e3fa 100644 --- a/src/array.rs +++ b/src/array.rs @@ -2,6 +2,7 @@ extern crate libc; use dim4::Dim4; use defines::{AfError, Aftype, Backend}; +use util::HasAfEnum; use self::libc::{uint8_t, c_void, c_int, c_uint, c_longlong}; type MutAfArray = *mut self::libc::c_longlong; @@ -119,11 +120,12 @@ impl Array { /// /// ``` /// let values: &[f32] = &[1.0, 2.0, 3.0]; - /// let indices = Array::new(Dim4::new(&[3, 1, 1, 1]), values, Aftype::F32).unwrap(); + /// let indices = Array::new(values, Dim4::new(&[3, 1, 1, 1])).unwrap(); /// ``` #[allow(unused_mut)] - pub fn new(dims: Dim4, slice: &[T], aftype: Aftype) -> Result { + pub fn new(slice: &[T], dims: Dim4) -> Result { unsafe { + let aftype = T::get_af_dtype(); let mut temp: i64 = 0; let err_val = af_create_array(&mut temp as MutAfArray, slice.as_ptr() as *const c_void, @@ -140,18 +142,11 @@ impl Array { /// Constructs a new Array object from strided data /// /// This data can possiblly offseted using an additiona `offset` parameter. - /// - /// # Examples - /// - /// ``` - /// let values: &[f32] = &[1.0, 2.0, 3.0]; - /// let indices = Array::new(Dim4::new(&[3, 1, 1, 1]), values, Aftype::F32).unwrap(); - /// ``` #[allow(unused_mut)] - pub fn new_strided(slice: &[T], offset: i64, - dims: Dim4, strides: Dim4, - aftype: Aftype) -> Result { + pub fn new_strided(slice: &[T], offset: i64, + dims: Dim4, strides: Dim4) -> Result { unsafe { + let aftype = T::get_af_dtype(); let mut temp: i64 = 0; let err_val = af_create_strided_array(&mut temp as MutAfArray, slice.as_ptr() as *const c_void, @@ -342,10 +337,11 @@ impl Array { is_func!(is_owner, af_is_owner); /// Cast the Array data type to `target_type` - pub fn cast(&self, target_type: Aftype) -> Result { + pub fn cast(&self) -> Result { unsafe { + let trgt_type = T::get_af_dtype(); let mut temp: i64 = 0; - let err_val = af_cast(&mut temp as MutAfArray, self.handle as AfArray, target_type as uint8_t); + let err_val = af_cast(&mut temp as MutAfArray, self.handle as AfArray, trgt_type as uint8_t); match err_val { 0 => Ok(Array::from(temp)), _ => Err(AfError::from(err_val)), @@ -394,7 +390,7 @@ impl Drop for Array { /// /// ``` /// println!("Create a 5-by-3 matrix of random floats on the GPU"); -/// let a = match randu(dims, Aftype::F32) { +/// let a = match randu::(dims) { /// Ok(value) => value, /// Err(error) => panic!("{}", error), /// }; diff --git a/src/data/mod.rs b/src/data/mod.rs index 1b611d844..b5432a568 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -4,10 +4,9 @@ extern crate num; use array::Array; use dim4::Dim4; use defines::AfError; -use defines::Aftype; use self::libc::{uint8_t, c_int, c_uint, c_double}; use self::num::Complex; - +use util::HasAfEnum; use std::vec::Vec; type MutAfArray = *mut self::libc::c_longlong; @@ -220,15 +219,15 @@ pub fn constant(cnst: T, dims: Dim4) -> Result Result { +pub fn range(dims: Dim4, seq_dim: i32) -> Result { unsafe { + let aftype = T::get_af_dtype(); let mut temp: i64 = 0; - let err_val =af_range(&mut temp as MutAfArray, + let err_val = af_range(&mut temp as MutAfArray, dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, seq_dim as c_int, aftype as uint8_t); match err_val { @@ -246,14 +245,14 @@ pub fn range(dims: Dim4, seq_dim: i32, aftype: Aftype) -> Result /// /// - `dims` is the dimensions of the sequence to be generated /// - `tdims` is the number of repitions of the unit dimensions -/// - `aftype` is the type of Array to generate /// /// # Return Values /// /// Array #[allow(unused_mut)] -pub fn iota(dims: Dim4, tdims: Dim4, aftype: Aftype) -> Result { +pub fn iota(dims: Dim4, tdims: Dim4) -> Result { unsafe { + let aftype = T::get_af_dtype(); let mut temp: i64 = 0; let err_val =af_iota(&mut temp as MutAfArray, dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, @@ -293,8 +292,9 @@ pub fn get_seed() -> Result { macro_rules! data_gen_def { ($fn_name:ident, $ffi_name: ident) => ( #[allow(unused_mut)] - pub fn $fn_name(dims: Dim4, aftype: Aftype) -> Result { + pub fn $fn_name(dims: Dim4) -> Result { 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, @@ -412,9 +412,9 @@ pub fn join_many(dim: i32, inputs: Vec<&Array>) -> Result { /// ``` /// # #[macro_use] extern crate arrayfire; /// # fn main() { -/// let a = randu(Dim4::new(&[5, 3, 1, 1]), Aftype::F32).unwrap(); -/// let b = randu(Dim4::new(&[5, 3, 1, 1]), Aftype::F32).unwrap(); -/// let c = randu(Dim4::new(&[5, 3, 1, 1]), Aftype::F32).unwrap(); +/// let a = randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); +/// let b = randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); +/// let c = randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); /// let d = join_many![2, a, b, c]; /// # } /// ``` diff --git a/src/defines.rs b/src/defines.rs index c2a4f8ddd..8ed0e1687 100644 --- a/src/defines.rs +++ b/src/defines.rs @@ -49,6 +49,7 @@ pub enum AfError { ERR_UNKNOWN = 999 } +/// Compute/Acceleration Backend #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq)] pub enum Backend { diff --git a/src/image/mod.rs b/src/image/mod.rs index c81c7deae..4dc6d0e83 100644 --- a/src/image/mod.rs +++ b/src/image/mod.rs @@ -2,12 +2,12 @@ extern crate libc; use array::Array; use defines::AfError; -use defines::Aftype; use defines::BorderType; use defines::ColorSpace; use defines::Connectivity; use defines::InterpType; use defines::YCCStd; +use util::HasAfEnum; use self::libc::{uint8_t, c_uint, c_int, c_float, c_double}; type MutAfArray = *mut self::libc::c_longlong; @@ -812,14 +812,14 @@ pub fn color_space(input: &Array, /// /// - `input` is the input image /// - `conn` can take one of the values of [Connectivity](./enum.Connectivity.html) -/// - `aftype` can take one of the values of [Aftype](./enum.Aftype.html) /// /// # Return Values /// /// Array with labels indicating different regions #[allow(unused_mut)] -pub fn regions(input: &Array, conn: Connectivity, aftype: Aftype) -> Result { +pub fn regions(input: &Array, conn: Connectivity) -> Result { unsafe { + let aftype = T::get_af_dtype(); let mut temp: i64 = 0; let err_val = af_regions(&mut temp as MutAfArray, input.get() as AfArray, conn as uint8_t, aftype as uint8_t); diff --git a/src/index.rs b/src/index.rs index 2aca11327..91378debb 100644 --- a/src/index.rs +++ b/src/index.rs @@ -125,7 +125,7 @@ impl Drop for Indexer { /// # Examples /// /// ``` -/// let a = randu(dims, Aftype::F32).unwrap(); +/// let a = randu::(dims).unwrap(); /// let seqs = &[Seq::new(1.0, 3.0, 1.0), Seq::default()]; /// let sub = index(&a, seqs).unwrap(); /// println!("a(seq(1, 3, 1), span)"); @@ -153,7 +153,7 @@ pub fn index(input: &Array, seqs: &[Seq]) -> Result /// # Examples /// /// ``` -/// let a = randu(dims, Aftype::F32).unwrap(); +/// let a = randu::(dims).unwrap(); /// println!("Grab last row of the random matrix"); /// print(&a); /// print(&row(&a, num_rows - 1).unwrap()); @@ -189,7 +189,7 @@ pub fn set_rows(input: &Array, new_rows: &Array, first: u64, last: u64) -> Resul /// # Examples /// /// ``` -/// let a = randu(dims, Aftype::F32).unwrap(); +/// let a = randu::(dims).unwrap(); /// println!("Grab last col of the random matrix"); /// print(&a); /// print(&row(&a, num_cols - 1).unwrap()); @@ -328,9 +328,9 @@ pub fn assign_seq(lhs: &Array, seqs: &[Seq], rhs: &Array) -> Result< /// /// ``` /// let values: &[f32] = &[1.0, 2.0, 3.0]; -/// let indices = Array::new(Dim4::new(&[3, 1, 1, 1]), values, Aftype::F32).unwrap(); +/// let indices = Array::new(values, Dim4::new(&[3, 1, 1, 1])).unwrap(); /// let seq4gen = Seq::new(0.0, 2.0, 1.0); -/// let a = randu(Dim4::new(&[5, 3, 1, 1]), Aftype::F32).unwrap(); +/// let a = randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); /// // [5 3 1 1] /// // 0.0000 0.2190 0.3835 /// // 0.1315 0.0470 0.5194 @@ -371,9 +371,9 @@ pub fn index_gen(input: &Array, indices: Indexer) -> Result { /// /// ``` /// let values: &[f32] = &[1.0, 2.0, 3.0]; -/// let indices = Array::new(Dim4::new(&[3, 1, 1, 1]), values, Aftype::F32).unwrap(); +/// let indices = Array::new(values, Dim4::new(&[3, 1, 1, 1])).unwrap(); /// let seq4gen = Seq::new(0.0, 2.0, 1.0); -/// let a = randu(Dim4::new(&[5, 3, 1, 1]), Aftype::F32).unwrap(); +/// let a = randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); /// // [5 3 1 1] /// // 0.0000 0.2190 0.3835 /// // 0.1315 0.0470 0.5194 diff --git a/src/lib.rs b/src/lib.rs index fe22fd220..00a214db0 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,6 +91,7 @@ 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}; mod util; pub use vision::Features; diff --git a/src/util.rs b/src/util.rs index a26a74c0c..201a543bc 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,3 +1,5 @@ +extern crate num; + use defines::AfError; use defines::Aftype; use defines::InterpType; @@ -7,6 +9,7 @@ use defines::MatProp; use defines::MatchType; use defines::ColorMap; use std::mem; +use self::num::Complex; impl From for AfError { fn from(t: i32) -> AfError { @@ -72,3 +75,52 @@ impl From for ColorMap { unsafe { mem::transmute(t) } } } + +/// Types of the data that can be generated using ArrayFire data generation functions. +/// +/// The trait HasAfEnum has been defined internally for the following types. We strongly suggest +/// not to implement this trait in your program for user defined types because ArrayFire functions +/// will only work for the following data types currently. Any such trait implementation for types +/// other than the ones listed below will result in undefined behavior. +/// +/// - f32 +/// - f64 +/// - num::Complex\ +/// - num::Complex\ +/// - bool +/// - i32 +/// - u32 +/// - u8 +/// - i64 +/// - u64 +/// - i16 +/// - u16 +/// +pub trait HasAfEnum { + fn get_af_dtype() -> Aftype; +} + +macro_rules! impl_has_af_enum { + ($rust_t: ty, $af_dtype: expr) => ( + impl HasAfEnum for $rust_t { + fn get_af_dtype() -> Aftype { + $af_dtype + } + } + ) +} + +impl_has_af_enum!(f32, Aftype::F32); +impl_has_af_enum!(Complex, Aftype::C32); +impl_has_af_enum!(f64, Aftype::F64); +impl_has_af_enum!(Complex, Aftype::C64); +// FIXME: Rust bool may become incompatible in memory layout with C-ABI +// Currently, it is of size 1-byte +impl_has_af_enum!(bool, Aftype::B8); +impl_has_af_enum!(i32, Aftype::S32); +impl_has_af_enum!(u32, Aftype::U32); +impl_has_af_enum!(u8, Aftype::U8); +impl_has_af_enum!(i64, Aftype::S64); +impl_has_af_enum!(u64, Aftype::U64); +impl_has_af_enum!(i16, Aftype::S16); +impl_has_af_enum!(u16, Aftype::U16); diff --git a/src/vision/mod.rs b/src/vision/mod.rs index 23ab89e5b..c61c7da6f 100644 --- a/src/vision/mod.rs +++ b/src/vision/mod.rs @@ -1,7 +1,8 @@ extern crate libc; use array::Array; -use defines::{AfError, HomographyType, Aftype, MatchType}; +use defines::{AfError, HomographyType, MatchType}; +use util::HasAfEnum; use self::libc::{c_void, uint8_t, c_uint, c_int, c_float, c_double, c_longlong}; type MutAfArray = *mut self::libc::c_longlong; @@ -503,11 +504,12 @@ pub fn dog(input: &Array, radius1: i32, radius2: i32) -> Result /// /// - `H` is a 3x3 array containing the estimated homography. /// - `inliers` is the number of inliers that the homography was estimated to comprise, in the case that htype is AF_HOMOGRAPHY_RANSAC, a higher inlier_thr value will increase the estimated inliers. Note that if the number of inliers is too low, it is likely that a bad homography will be returned. -pub fn homography(x_src: &Array, y_src: &Array, - x_dst: &Array, y_dst: &Array, - htype: HomographyType, inlier_thr: f32, - iterations: u32, otype: Aftype) -> Result<(Array, i32), AfError> { +pub fn homography(x_src: &Array, y_src: &Array, + x_dst: &Array, y_dst: &Array, + htype: HomographyType, inlier_thr: f32, + iterations: u32) -> Result<(Array, i32), AfError> { unsafe { + let otype = OutType::get_af_dtype(); let mut inliers: i32 = 0; let mut temp: i64 = 0; let err_val = af_homography(&mut temp as MutAfArray, &mut inliers as *mut c_int, From b2c042ea4c7fcb35b18cc28927f5a9e32483012a Mon Sep 17 00:00:00 2001 From: pradeep Date: Sat, 12 Mar 2016 13:52:25 +0530 Subject: [PATCH 3/5] Fixing typos --- src/array.rs | 2 +- src/image/mod.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/array.rs b/src/array.rs index 043e9e3fa..a597e10c2 100644 --- a/src/array.rs +++ b/src/array.rs @@ -141,7 +141,7 @@ impl Array { /// Constructs a new Array object from strided data /// - /// This data can possiblly offseted using an additiona `offset` parameter. + /// The data pointed by the slice passed to this function can possibily be offseted using an additional `offset` parameter. #[allow(unused_mut)] pub fn new_strided(slice: &[T], offset: i64, dims: Dim4, strides: Dim4) -> Result { diff --git a/src/image/mod.rs b/src/image/mod.rs index 4dc6d0e83..724a9b29d 100644 --- a/src/image/mod.rs +++ b/src/image/mod.rs @@ -817,12 +817,12 @@ pub fn color_space(input: &Array, /// /// Array with labels indicating different regions #[allow(unused_mut)] -pub fn regions(input: &Array, conn: Connectivity) -> Result { +pub fn regions(input: &Array, conn: Connectivity) -> Result { unsafe { - let aftype = T::get_af_dtype(); + let otype = OutType::get_af_dtype(); let mut temp: i64 = 0; let err_val = af_regions(&mut temp as MutAfArray, input.get() as AfArray, - conn as uint8_t, aftype as uint8_t); + conn as uint8_t, otype as uint8_t); match err_val { 0 => Ok(Array::from(temp)), _ => Err(AfError::from(err_val)), From c3f79219e09126f84d9ffb7d2a3167e4d6de6315 Mon Sep 17 00:00:00 2001 From: pradeep Date: Sat, 12 Mar 2016 14:55:52 +0530 Subject: [PATCH 4/5] Added mem_info macro Moved the following macros to separate module(macros) * mem_info * join_many --- examples/pi.rs | 5 +++ src/data/mod.rs | 45 +++--------------------- src/lib.rs | 1 + src/macros.rs | 91 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 40 deletions(-) create mode 100644 src/macros.rs diff --git a/examples/pi.rs b/examples/pi.rs index 5989fb5de..744063e99 100644 --- a/examples/pi.rs +++ b/examples/pi.rs @@ -1,3 +1,4 @@ +#[macro_use(mem_info)] extern crate arrayfire as af; extern crate time; @@ -17,6 +18,8 @@ fn main() { let start = PreciseTime::now(); + mem_info!("Before benchmark"); + for bench_iter in 0..100 { let pi_val = add(&mul(x, x, false).unwrap(), &mul(y, y, false).unwrap(), false) .and_then( |z| sqrt(&z) ) @@ -29,4 +32,6 @@ fn main() { let end = PreciseTime::now(); println!("Estimated Pi Value in {} seconds", start.to(end) / 100); + + mem_info!("After benchmark"); } diff --git a/src/data/mod.rs b/src/data/mod.rs index b5432a568..a554a147a 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -395,9 +395,13 @@ pub fn join(dim: i32, first: &Array, second: &Array) -> Result { #[allow(unused_mut)] pub fn join_many(dim: i32, inputs: Vec<&Array>) -> Result { unsafe { + let mut v = Vec::new(); + for i in inputs { + v.push(i.get()); + } let mut temp: i64 = 0; let err_val = af_join_many(&mut temp as MutAfArray, dim as c_int, - inputs.len() as c_uint, inputs.as_ptr() as *const AfArray); + v.len() as c_uint, v.as_ptr() as *const AfArray); match err_val { 0 => Ok(Array::from(temp)), _ => Err(AfError::from(err_val)), @@ -405,45 +409,6 @@ pub fn join_many(dim: i32, inputs: Vec<&Array>) -> Result { } } -/// Join multiple Arrays along a given dimension -/// -/// # Examples -/// -/// ``` -/// # #[macro_use] extern crate arrayfire; -/// # fn main() { -/// let a = randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); -/// let b = randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); -/// let c = randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); -/// let d = join_many![2, a, b, c]; -/// # } -/// ``` -/// -/// # Panics -/// -/// Using this macro to create an Array from multiple Arrays doesn't implicitly check for errors -/// during FFI calls. Therefore, make sure your inputs are correct. In case, you do need proper -/// error checking, use the [function version](./fn.join_many.html) of this macro. -// Using macro to implement join many wrapper -#[macro_export] -macro_rules! join_many { - [$dim: expr; $($x:ident),+] => { - { - let mut temp_vec = Vec::new(); - $( - temp_vec.push($x); - )* - let mut temp: i64 = 0; - unsafe { - let mut temp: i64 = 0; - af_join_many(&mut temp as MutAfArray, $dim as c_int, - temp_vec.len() as c_uint, temp_vec.as_ptr() as *const AfArray); - Array::from(temp) - } - } - }; -} - macro_rules! data_func_def { ($fn_name:ident, $ffi_name: ident) => ( #[allow(unused_mut)] diff --git a/src/lib.rs b/src/lib.rs index 00a214db0..c72da3459 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,6 +73,7 @@ mod image; pub use lapack::{svd, lu, qr, cholesky, solve, solve_lu, inverse, det, rank, norm}; pub use lapack::{svd_inplace, lu_inplace, qr_inplace, cholesky_inplace, is_lapack_available}; mod lapack; +mod macros; mod num; pub use signal::{approx1, approx2}; diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 000000000..a874591f6 --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,91 @@ +/// Macro to print the current stats of ArrayFire's memory manager. +/// +/// `mem_info!` print 4 values: +/// +/// Name | Description +/// -------------------------|------------------------- +/// Allocated Bytes | Total number of bytes allocated by the memory manager +/// Allocated Buffers | Total number of buffers allocated +/// Locked (In Use) Bytes | Number of bytes that are in use by active arrays +/// Locked (In Use) Buffers | Number of buffers that are in use by active arrays +/// +/// The `Allocated Bytes` is always a multiple of the memory step size. The +/// default step size is 1024 bytes. This means when a buffer is to be +/// allocated, the size is always rounded up to a multiple of the step size. +/// You can use [get_mem_step_size](./fn.get_mem_step_size.html) to check the +/// current step size and [set_mem_step_size](./fn.set_mem_step_size.html) to +/// set a custom resolution size. +/// +/// The `Allocated Buffers` is the number of buffers that use up the allocated +/// bytes. This includes buffers currently in scope, as well as buffers marked +/// as free, ie, from arrays gone out of scope. The free buffers are available +/// for use by new arrays that might be created. +/// +/// The `Locked Bytes` is the number of bytes in use that cannot be +/// reallocated at the moment. The difference of Allocated Bytes and Locked +/// Bytes is the total bytes available for reallocation. +/// +/// The `Locked Buffers` is the number of buffer in use that cannot be +/// reallocated at the moment. The difference of Allocated Buffers and Locked +/// Buffers is the number of buffers available for reallocation. +/// +/// # Parameters +/// +/// - `msg` is the message that is printed to screen before printing stats +/// +/// # Examples +/// +/// ``` +/// mem_info!("Here"); +/// ``` +/// +/// Sample Output: +/// +/// ``` +/// AF Memory: Here +/// Allocated [ Bytes | Buffers ] = [ 4096 | 4 ] +/// In Use [ Bytes | Buffers ] = [ 2048 | 2 ] +/// ``` +#[macro_export] +macro_rules! mem_info { + [$msg: expr] => { + { + let (abytes, abuffs, lbytes, lbuffs) = device_mem_info().unwrap(); + println!("AF Memory: {:?}", $msg); + println!("Allocated [Bytes | Buffers] = [ {} | {} ]", abytes, abuffs); + println!("In Use [Bytes | Buffers] = [ {} | {} ]", lbytes, lbuffs); + } + }; +} + +/// Join multiple Arrays along a given dimension +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate arrayfire; +/// # fn main() { +/// let a = randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); +/// let b = randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); +/// let c = randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); +/// let d = join_many![2, a, b, c]; +/// # } +/// ``` +/// +/// # Panics +/// +/// This macro just calls [join_many](./fn.join_many.html) function after collecting all +/// the input arrays into a vector. +// Using macro to implement join many wrapper +#[macro_export] +macro_rules! join_many { + [$dim: expr; $($x:ident),+] => { + { + let mut temp_vec = Vec::new(); + $( + temp_vec.push($x); + )* + join_many($dim, temp_vec) + } + }; +} From 21972e7f12d4b04f5eec8b7e0367fcec1b4f02b8 Mon Sep 17 00:00:00 2001 From: pradeep Date: Sat, 12 Mar 2016 15:04:51 +0530 Subject: [PATCH 5/5] Fixed example code in join_many macro documentation --- src/macros.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index a874591f6..83bbc4c5d 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -60,15 +60,17 @@ macro_rules! mem_info { /// Join multiple Arrays along a given dimension /// +/// All the Arrays provided to this macro should be of type `&Array` +/// /// # Examples /// /// ``` /// # #[macro_use] extern crate arrayfire; /// # fn main() { -/// let a = randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); -/// let b = randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); -/// let c = randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); -/// let d = join_many![2, a, b, c]; +/// let a = &randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); +/// let b = &randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); +/// let c = &randu::(Dim4::new(&[5, 3, 1, 1])).unwrap(); +/// let d = join_many![2; a, b, c]; /// # } /// ``` ///