diff --git a/Cargo.toml b/Cargo.toml index e5cea8a44..2b7205976 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.4.2" +version = "3.4.3" 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 6f379fbe6..573442f83 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,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.4.2"` to the dependencies section of your project's Cargo.toml file - 3.4.2 +4. Add `arrayfire = "3.4.3"` to the dependencies section of your project's Cargo.toml file - 3.4.3 is the lastest version of crate. 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). diff --git a/build.rs b/build.rs index 1230ba6b8..b4cdd132c 100644 --- a/build.rs +++ b/build.rs @@ -357,19 +357,49 @@ fn blob_backends(conf: &Config, build_dir: &std::path::PathBuf) -> (Vec, if conf.use_lib { let afpath = match env::var("AF_PATH") { Ok(af_path) => PathBuf::from(&af_path), - Err(_) => panic!("Error use_lib is defined, but AF_PATH is not defined"), + Err(_) => { + println!("WARNING! USE_LIB IS DEFINED, BUT AF_PATH IS NOT FOUND,"); + println!(" TRYING TO FIND LIBRARIES FROM KNOWN DEFAULT LOCATIONS"); + + if cfg!(target_os = "windows") { + PathBuf::from("C:/Program Files/ArrayFire/v3/") + } else { + PathBuf::from("/usr/local/") + } + }, }; + let libpath = afpath.join("lib"); backend_dirs.push(libpath.to_str().to_owned().unwrap().to_string()); + + if !cfg!(target_os = "windows") { + backend_dirs.push(String::from("/opt/arrayfire-3/lib")); + backend_dirs.push(String::from("/usr/lib")); + } } else { backend_dirs.push(build_dir.join("package/lib").to_str().to_owned().unwrap().to_string()); } - let lib_dir = PathBuf::from(backend_dirs.last().unwrap()); + let mut uni_lib_exists = false; + let mut cud_lib_exists = false; + let mut ocl_lib_exists = false; + + for backend_dir in backend_dirs.iter() { + let lib_dir = PathBuf::from(backend_dir); + + let cud_lib_file_to_check = if cfg!(windows) {WIN_CUDA_LIB_NAME} else {UNIX_CUDA_LIB_NAME}; + cud_lib_exists = cud_lib_exists || backend_exists(&lib_dir.join(cud_lib_file_to_check).to_string_lossy()); + + let ocl_lib_file_to_check = if cfg!(windows) {WIN_OCL_LIB_NAME} else {UNIX_OCL_LIB_NAME}; + ocl_lib_exists = ocl_lib_exists || backend_exists(&lib_dir.join(ocl_lib_file_to_check).to_string_lossy()); + + let uni_lib_file_to_check = if cfg!(windows) {WIN_UNI_LIB_NAME} else {UNIX_UNI_LIB_NAME}; + uni_lib_exists = uni_lib_exists || backend_exists(&lib_dir.join(uni_lib_file_to_check).to_string_lossy()); + } + if ! conf.use_lib { // blob in cuda deps - let mut lib_file_to_check = if cfg!(windows) {WIN_CUDA_LIB_NAME} else {UNIX_CUDA_LIB_NAME}; - if backend_exists(&lib_dir.join(lib_file_to_check).to_string_lossy()) { + if cud_lib_exists { if cfg!(windows) { backend_dirs.push(format!("{}\\lib\\x64", conf.cuda_sdk)); backend_dirs.push(format!("{}\\nvvm\\lib\\x64", conf.cuda_sdk)); @@ -389,8 +419,8 @@ fn blob_backends(conf: &Config, build_dir: &std::path::PathBuf) -> (Vec, } //blob in opencl deps - lib_file_to_check = if cfg!(windows) {WIN_OCL_LIB_NAME} else {UNIX_OCL_LIB_NAME}; - if backend_exists(&lib_dir.join(lib_file_to_check).to_string_lossy()) { + + if ocl_lib_exists { if ! cfg!(target_os = "macos"){ backends.push("OpenCL".to_string()); } @@ -413,14 +443,12 @@ fn blob_backends(conf: &Config, build_dir: &std::path::PathBuf) -> (Vec, if conf.build_graphics=="ON" { if !conf.use_lib { - backend_dirs.push(build_dir.join("third_party/forge/lib") - .to_str().to_owned().unwrap().to_string()); + backend_dirs.push(build_dir.join("third_party/forge/lib").to_str().to_owned().unwrap().to_string()); } } } - let lib_file_to_check = if cfg!(windows) {WIN_UNI_LIB_NAME} else {UNIX_UNI_LIB_NAME}; - if backend_exists(&lib_dir.join(lib_file_to_check).to_string_lossy()) { + if uni_lib_exists { backends.push("af".to_string()); if !conf.use_lib && conf.build_graphics=="ON" { backends.push("forge".to_string()); diff --git a/src/array.rs b/src/array.rs index 14ace7ade..a2e515403 100644 --- a/src/array.rs +++ b/src/array.rs @@ -104,6 +104,12 @@ extern { /// A multidimensional data container /// /// Currently, Array objects can store only data until four dimensions +/// +/// ### NOTE +/// +/// All operators(traits) from std::ops module implemented for Array object +/// carry out element wise operations. For example, `*` does multiplication of +/// elements at corresponding locations in two different Arrays. pub struct Array { handle: i64, } @@ -296,7 +302,7 @@ impl Array { /// Makes an copy of the Array /// - /// Internally, this is handled by reference counting + /// This does a deep copy of the data into a new Array pub fn copy(&self) -> Array { unsafe { let mut temp: i64 = 0; @@ -383,7 +389,14 @@ impl From for Array { } } -/// Used for incrementing the reference count of Array's native resource +/// Returns a new Array object after incrementing the reference count of native resource +/// +/// Cloning an Array does not do a deep copy of the underlying array data. It increments the +/// reference count of native resource and returns you the new reference in the form a new Array +/// object. +/// +/// To create a deep copy use +/// [copy()](http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html#method.copy) impl Clone for Array { fn clone(&self) -> Array { unsafe { diff --git a/src/blas/mod.rs b/src/blas/mod.rs index 5255a1167..180569674 100644 --- a/src/blas/mod.rs +++ b/src/blas/mod.rs @@ -46,7 +46,7 @@ pub fn matmul(lhs: &Array, rhs: &Array, /// Calculate the dot product of vectors. /// -/// Scalar dot product between two vectors. Also referred to as the inner product. This function returns the scalar product of two equal sized vectors or between a matrix and a vector. The second operand needs to be a vector in either case. +/// Scalar dot product between two vectors. Also referred to as the inner product. This function returns the scalar product of two equal sized vectors. /// /// # Parameters /// diff --git a/src/data/mod.rs b/src/data/mod.rs index 71981e756..30326bbb7 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -38,7 +38,7 @@ extern { fn af_tile(out: MutAfArray, arr: AfArray, x: c_uint, y: c_uint, z: c_uint, w: c_uint) -> c_int; fn af_reorder(o: MutAfArray, a: AfArray, x: c_uint, y: c_uint, z: c_uint, w: c_uint) -> c_int; - fn af_shift(o: MutAfArray, a: AfArray, x: c_uint, y: c_uint, z: c_uint, w: c_uint) -> c_int; + fn af_shift(o: MutAfArray, a: AfArray, x: c_int, y: c_int, z: c_int, w: c_int) -> c_int; fn af_moddims(out: MutAfArray, arr: AfArray, ndims: c_uint, dims: *const DimT) -> c_int; fn af_flat(out: MutAfArray, arr: AfArray) -> c_int; @@ -375,7 +375,42 @@ macro_rules! data_func_def { 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); + + +///"Circular shift of values along specified dimension +/// +///# Parameters +/// +/// - `input` is the input Array +/// - `offsets` is 4-value tuple that specifies the shift along respective dimension +/// +///# Return Values +/// +/// An Array with shifted data. +/// +///# Examples +/// +/// ```rust +/// use arrayfire::{Array, Dim4, print, randu, shift}; +/// let a = randu::(Dim4::new(&[5, 1, 1, 1])); +/// let _a = shift(&a, &[-1i32, 1 , 1, 1]); //shift data one step backward +/// let a_ = shift(&a, &[ 1i32, 1 , 1, 1]); //shift data one step forward +/// print(& a); +/// print(&_a); +/// print(&a_); +/// ``` +#[allow(unused_mut)] +pub fn shift(input: &Array, offsets: &[i32; 4]) -> Array { + unsafe { + let mut temp: i64 = 0; + let err_val = af_shift(&mut temp as MutAfArray, input.get() as AfArray, + offsets[0] as c_int, offsets[1] as c_int, + offsets[2] as c_int, offsets[3] as c_int); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } +} + /// Change the shape of the Array /// diff --git a/src/defines.rs b/src/defines.rs index ab42c3be7..d777f310a 100644 --- a/src/defines.rs +++ b/src/defines.rs @@ -102,7 +102,7 @@ impl Error for AfError { AfError::ERR_NOT_CONFIGURED => "This build of ArrayFire does not support this feature", AfError::ERR_NO_DBL => "This device does not support double", AfError::ERR_NO_GFX => "This build of ArrayFire has no graphics support", - AfError::ERR_INTERNAL => "Eror either in ArrayFire or in a project upstream", + AfError::ERR_INTERNAL => "Error either in ArrayFire or in a project upstream", AfError::ERR_UNKNOWN => "Unknown Error", } } diff --git a/src/image/mod.rs b/src/image/mod.rs index b44729c16..fec01bca5 100644 --- a/src/image/mod.rs +++ b/src/image/mod.rs @@ -4,7 +4,8 @@ use array::Array; use defines::{AfError, BorderType, ColorSpace, Connectivity, InterpType, YCCStd, MomentType}; use error::HANDLE_ERROR; use util::{AfArray, DimT, HasAfEnum, MutAfArray}; -use self::libc::{uint8_t, c_uint, c_int, c_float, c_double}; +use self::libc::{uint8_t, c_uint, c_int, c_float, c_double, c_char}; +use std::ffi::CString; // unused functions from image.h header // af_load_image_memory @@ -14,10 +15,10 @@ use self::libc::{uint8_t, c_uint, c_int, c_float, c_double}; #[allow(dead_code)] extern { fn af_gradient(dx: MutAfArray, dy: MutAfArray, arr: AfArray) -> c_int; - fn af_load_image(out: MutAfArray, filename: *const u8, iscolor: c_int) -> c_int; - fn af_save_image(filename: *const u8, input: AfArray) -> c_int; - fn af_load_image_native(out: MutAfArray, filename: *const u8) -> c_int; - fn af_save_image_native(filename: *const u8, input: AfArray) -> c_int; + fn af_load_image(out: MutAfArray, filename: *const c_char, iscolor: c_int) -> c_int; + fn af_save_image(filename: *const c_char, input: AfArray) -> c_int; + fn af_load_image_native(out: MutAfArray, filename: *const c_char) -> c_int; + fn af_save_image_native(filename: *const c_char, input: AfArray) -> c_int; fn af_resize(out: MutAfArray, input: AfArray, odim0: DimT, odim1: DimT, method: uint8_t) -> c_int; @@ -135,11 +136,13 @@ pub fn gradient(input: &Array) -> (Array, Array) { /// An Array with pixel values loaded from the image #[allow(unused_mut)] pub fn load_image(filename: String, is_color: bool) -> Array { + let cstr_param = match CString::new(filename) { + Ok(cstr) => cstr, + Err(_) => panic!("CString creation from input filename failed"), + }; unsafe { let mut temp: i64 = 0; - let err_val = af_load_image(&mut temp as MutAfArray, - filename.clone().as_bytes().as_ptr() as *const u8, - is_color as c_int); + let err_val = af_load_image(&mut temp as MutAfArray, cstr_param.as_ptr(), is_color as c_int); HANDLE_ERROR(AfError::from(err_val)); Array::from(temp) } @@ -165,10 +168,13 @@ pub fn load_image(filename: String, is_color: bool) -> Array { /// An Array with pixel values loaded from the image #[allow(unused_mut)] pub fn load_image_native(filename: String) -> Array { + let cstr_param = match CString::new(filename) { + Ok(cstr) => cstr, + Err(_) => panic!("CString creation from input filename failed"), + }; unsafe { let mut temp: i64 = 0; - let err_val = af_load_image_native(&mut temp as MutAfArray, - filename.clone().as_bytes().as_ptr() as *const u8); + let err_val = af_load_image_native(&mut temp as MutAfArray, cstr_param.as_ptr()); HANDLE_ERROR(AfError::from(err_val)); Array::from(temp) } @@ -182,9 +188,12 @@ pub fn load_image_native(filename: String) -> Array { /// - `input` is the Array to be stored into the image file #[allow(unused_mut)] pub fn save_image(filename: String, input: &Array) { + let cstr_param = match CString::new(filename) { + Ok(cstr) => cstr, + Err(_) => panic!("CString creation from input filename failed"), + }; unsafe { - let err_val = af_save_image(filename.clone().as_bytes().as_ptr() as *const u8, - input.get() as AfArray); + let err_val = af_save_image(cstr_param.as_ptr(), input.get() as AfArray); HANDLE_ERROR(AfError::from(err_val)); } } @@ -207,9 +216,12 @@ pub fn save_image(filename: String, input: &Array) { /// - `input` is the Array to be saved. Should be U8 for saving 8-bit image, U16 for 16-bit image, and F32 for 32-bit image. #[allow(unused_mut)] pub fn save_image_native(filename: String, input: &Array) { + let cstr_param = match CString::new(filename) { + Ok(cstr) => cstr, + Err(_) => panic!("CString creation from input filename failed"), + }; unsafe { - let err_val = af_save_image_native(filename.clone().as_bytes().as_ptr() as *const u8, - input.get() as AfArray); + let err_val = af_save_image_native(cstr_param.as_ptr(), input.get() as AfArray); HANDLE_ERROR(AfError::from(err_val)); } }