diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12c257f5c..e5d7eb7a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,7 @@ jobs: export AF_PATH=${GITHUB_WORKSPACE}/afbin export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${AF_PATH}/lib64 echo "Using cargo version: $(cargo --version)" + cargo build --all cargo test --no-fail-fast format: diff --git a/Cargo.toml b/Cargo.toml index 1506cebb2..5050629c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,16 @@ exclude = [ "arrayfire/*", ] +[workspace] +members = [ + "cuda-interop", + "opencl-interop", +] + +[lib] +name = "arrayfire" +path = "src/lib.rs" + [package.metadata.docs.rs] rustdoc-args = [ "--html-in-header", "./scripts/mathjax.script", ] @@ -27,7 +37,7 @@ indexing = [] graphics = [] image = [] lapack = [] -machine_learning = [] +ml = [] macros = [] random = [] signal = [] @@ -35,7 +45,7 @@ sparse = [] statistics = [] vision = [] default = ["algorithm", "arithmetic", "blas", "data", "indexing", "graphics", "image", "lapack", -"machine_learning", "macros", "random", "signal", "sparse", "statistics", "vision"] +"ml", "macros", "random", "signal", "sparse", "statistics", "vision"] [dependencies] libc = "0.2" @@ -53,10 +63,6 @@ serde_derive = "1.0" serde = "1.0" rustc_version = "0.2" -[lib] -name = "arrayfire" -path = "src/lib.rs" - [[example]] name = "helloworld" path = "examples/helloworld.rs" diff --git a/README.md b/README.md index 174883c9f..d33bb61fc 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,61 @@ +[![ci][19]][16] [![docs][18]][3] [![book][22]][21] [![slack][17]][4] [![google-groups][20]][5] + # Arrayfire Rust Bindings -[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. Given below table shows the rust bindings compatability with -ArrayFire. If you find any bugs, please report them -[here](https://github.com/arrayfire/arrayfire-rust/issues). +[ArrayFire][1] 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. Given below table shows +the rust bindings compatability with ArrayFire. If you find any bugs, please report them [here][2]. | arrayfire-rust | ArrayFire | |:--------------:|:---------:| | M.m.p1 | M.m.p2 | -Only, Major(M) & Minor(m) version numbers need to match. *p1* and *p2* -are patch/fix updates for `arrayfire-rust` & `ArrayFire` respectively, -and they don't need to match. - -## Documentation - -You can find the most recent updated documentation -[here](http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html). - -## Communication - -* [Slack Chat](https://join.slack.com/t/arrayfire-org/shared_invite/MjI4MjIzMDMzMTczLTE1MDI5ODg4NzYtN2QwNGE3ODA5OQ) -* [Google Groups](https://groups.google.com/forum/#!forum/arrayfire-users) +Only, Major(M) & Minor(m) version numbers need to match. *p1* and *p2* are patch/fix updates for +`arrayfire-rust` & `ArrayFire` respectively, and they don't need to match. ## Supported platforms Linux, Windows and OSX. Rust 1.15.1 or higher is required. -## Use from Crates.io [![](http://meritbadge.herokuapp.com/arrayfire)](https://crates.io/crates/arrayfire) [![](https://docs.rs/arrayfire/badge.svg)](https://docs.rs/arrayfire) +## Use from Crates.io [![][6]][7] [![][8]][9] -To use the rust bindings for ArrayFire from crates.io, the following -requirements are to be met first. +To use the rust bindings for ArrayFire from crates.io, the following requirements are to be met first. -1. [Download and install ArrayFire binaries](https://arrayfire.com/download) - based on your operating system. -2. Set the evironment variable `AF_PATH` to point to ArrayFire installation - root folder. +1. [Download and install ArrayFire binaries][10] based on your operating system. +2. Set the evironment variable `AF_PATH` to point to ArrayFire installation root folder. 3. Make sure to add the path to lib files to your path environment variables. - On Linux: do `export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib64` - On OSX: do `export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$AF_PATH/lib64` - On Windows: Add `%AF_PATH%\lib` to your PATH environment variable. -4. Add `arrayfire = "3.7"` to the dependencies section of your project's - Cargo.toml file. Make sure to change the version to latest available. +4. Add `arrayfire = "3.7"` to the dependencies section of your project's Cargo.toml file. Make sure + to change the version to latest available. -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). +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][2]. ## Build from Source -Edit [build.conf](build.conf) to modify the build flags. The structure is a -simple JSON blob. Currently Rust does not allow key:value pairs to be passed -from the CLI. To use an existing ArrayFire installation modify the first three -JSON values. You can install ArrayFire using one of the following two ways. +Edit [build.conf](build.conf) to modify the build flags. The structure is a simple JSON blob. +Currently Rust does not allow key:value pairs to be passed from the CLI. To use an existing +ArrayFire installation modify the first three JSON values. You can install ArrayFire using +one of the following two ways. -- [Download and install binaries](https://arrayfire.com/download) -- [Build and install from source](https://github.com/arrayfire/arrayfire) +- [Download and install binaries][10] +- [Build and install from source][1] -To build arrayfire submodule available in the rust wrapper, you have to do -the following. +To build arrayfire submodule available in the rust wrapper, you have to do the following. ```bash git submodule update --init --recursive -cargo build +cargo build // use --all to build all crates in the workspace ``` -This is recommended way to build Rust wrapper since the submodule points to -the most compatible version of ArrayFire the Rust wrapper has been tested with. -You can find the ArrayFire dependencies below. +This is recommended way to build Rust wrapper since the submodule points to the most compatible +version of ArrayFire the Rust wrapper has been tested with. You can find the ArrayFire dependencies below. -- [Linux](https://github.com/arrayfire/arrayfire/wiki/Build-Instructions-for-Linux) -- [OSX](https://github.com/arrayfire/arrayfire/wiki/Build-Instructions-for-OSX) -- [Windows](https://github.com/arrayfire/arrayfire/wiki/Build-Instructions-for-Windows) +- [Linux][11] +- [OSX][12] +- [Windows][13] ## Example @@ -102,24 +84,37 @@ Create a 5-by-3 matrix of random floats on the GPU ## Acknowledgements -The ArrayFire library is written by developers at -[ArrayFire](http://arrayfire.com) LLC with -[contributions from several individuals](https://github.com/arrayfire/arrayfire_rust/graphs/contributors). - -The developers at ArrayFire LLC have received partial financial support -from several grants and institutions. Those that wish to receive public -acknowledgement are listed below: - - +The ArrayFire library is written by developers at [ArrayFire][14] LLC with [contributions][15] +from several individuals. The developers at ArrayFire LLC have received partial financial support +from several grants and institutions. Those that wish to receive public acknowledgement are listed +below: ### Grants -This material is based upon work supported by the DARPA SBIR Program Office -under Contract Numbers W31P4Q-14-C-0012 and W31P4Q-15-C-0008. -Any opinions, findings and conclusions or recommendations expressed in this -material are those of the author(s) and do not necessarily reflect the views of +This material is based upon work supported by the DARPA SBIR Program Office under Contract Numbers +W31P4Q-14-C-0012 and W31P4Q-15-C-0008. Any opinions, findings and conclusions or recommendations +expressed in this material are those of the author(s) and do not necessarily reflect the views of the DARPA SBIR Program Office. + +[1]: https://github.com/arrayfire/arrayfire +[2]: https://github.com/arrayfire/arrayfire-rust/issues +[3]: http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html +[4]: https://join.slack.com/t/arrayfire-org/shared_invite/MjI4MjIzMDMzMTczLTE1MDI5ODg4NzYtN2QwNGE3ODA5OQ +[5]: https://groups.google.com/forum/#!forum/arrayfire-users +[6]: http://meritbadge.herokuapp.com/arrayfire +[7]: https://crates.io/crates/arrayfire +[8]: https://docs.rs/arrayfire/badge.svg +[9]: https://docs.rs/arrayfire +[10]: https://arrayfire.com/download +[11]: https://github.com/arrayfire/arrayfire/wiki/Build-Instructions-for-Linux +[12]: https://github.com/arrayfire/arrayfire/wiki/Build-Instructions-for-OSX +[13]: https://github.com/arrayfire/arrayfire/wiki/Build-Instructions-for-Windows +[14]: https://arrayfire.com/ +[15]: https://github.com/arrayfire/arrayfire_rust/graphs/contributors +[16]: https://github.com/arrayfire/arrayfire-rust/actions?workflow=CI +[17]: https://img.shields.io/badge/arrayfire-community-e69138?logo=slack +[18]: https://img.shields.io/badge/arrayfire-Docs-blue?logo=readthedocs +[19]: https://github.com/arrayfire/arrayfire-rust/workflows/ci/badge.svg?event=push +[20]: https://img.shields.io/badge/arrayfire-google--groups-orange +[21]: http://arrayfire.org/arrayfire-rust/book/index.html +[22]: https://img.shields.io/badge/arrayfire-mdbook-073763?logo=readthedocs diff --git a/cuda-interop/Cargo.toml b/cuda-interop/Cargo.toml new file mode 100644 index 000000000..4c44af416 --- /dev/null +++ b/cuda-interop/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "af-cuda-interop" +version = "0.1.0" +authors = ["Pradeep Garigipati "] +edition = "2018" + +[dependencies] +libc = "0.2" +arrayfire = { path = "../" } +cuda-runtime-sys = "0.3.0-alpha.1" + +[dev-dependencies] +rustacuda = "0.1" +rustacuda_core = "0.1" + +[[example]] +name = "custom_kernel" +path = "examples/custom_kernel.rs" + +[[example]] +name = "cuda_af_app" +path = "examples/cuda_af_app.rs" diff --git a/cuda-interop/README.md b/cuda-interop/README.md new file mode 100644 index 000000000..570bb45c3 --- /dev/null +++ b/cuda-interop/README.md @@ -0,0 +1,50 @@ +[![ci][19]][16] [![][18]][3] [![][17]][4] + +# ArrayFire CUDA Interop + +This crate is an addition on top of [ArrayFire][1] crate to enable users to mix RAW CUDA code in rust +and [ArrayFire][1]. + +## Supported platforms + +Supported on all platforms [arrayfire-rust][1] is supported. + +## Usage + +Command to build the crate +``` +cargo build -p af_cuda_interop +``` + +Use the following command to run an example +``` +cargo run -p af_cuda_interop --example custom_kernel +``` + +This crate can be used by directly using the packages on crates.io or building them on your own. +The process for this can be found on [arrayfire-rust#readme][2] + +## Acknowledgements + +The ArrayFire library is written by developers at [ArrayFire][14] LLC with [contributions][15] +from several individuals. The developers at ArrayFire LLC have received partial financial support +from several grants and institutions. Those that wish to receive public acknowledgement are listed +below: + +### Grants + +This material is based upon work supported by the DARPA SBIR Program Office under Contract Numbers +W31P4Q-14-C-0012 and W31P4Q-15-C-0008. Any opinions, findings and conclusions or recommendations +expressed in this material are those of the author(s) and do not necessarily reflect the views of +the DARPA SBIR Program Office. + +[1]: https://github.com/arrayfire/arrayfire-rust +[2]: https://github.com/arrayfire/arrayfire-rust/blob/master/README.md +[3]: http://arrayfire.github.io/arrayfire-rust/af_cuda_interop/index.html +[4]: https://join.slack.com/t/arrayfire-org/shared_invite/MjI4MjIzMDMzMTczLTE1MDI5ODg4NzYtN2QwNGE3ODA5OQ +[14]: https://arrayfire.com/ +[15]: https://github.com/arrayfire/arrayfire_rust/graphs/contributors +[16]: https://github.com/arrayfire/arrayfire-rust/actions?workflow=CI +[17]: https://img.shields.io/badge/af_cuda_interop-community-e69138?logo=slack +[18]: https://img.shields.io/badge/af_cuda_interop-Docs-blue?logo=readthedocs +[19]: https://github.com/arrayfire/arrayfire-rust/workflows/ci/badge.svg?event=push diff --git a/cuda-interop/examples/cuda_af_app.rs b/cuda-interop/examples/cuda_af_app.rs new file mode 100644 index 000000000..7868402c5 --- /dev/null +++ b/cuda-interop/examples/cuda_af_app.rs @@ -0,0 +1,61 @@ +use arrayfire::{af_print, dim4, info, set_device, Array}; +use rustacuda::prelude::*; +use rustacuda::*; + +fn main() { + // MAKE SURE to do all rustacuda initilization before arrayfire API's + // first call. It seems like some CUDA context state is getting messed up + // if we mix CUDA context init(device, context, module, stream) with ArrayFire API + match rustacuda::init(CudaFlags::empty()) { + Ok(()) => {} + Err(e) => panic!("rustacuda init failure: {:?}", e), + } + let device = match Device::get_device(0) { + Ok(d) => d, + Err(e) => panic!("Failed to get device: {:?}", e), + }; + let _context = + match Context::create_and_push(ContextFlags::MAP_HOST | ContextFlags::SCHED_AUTO, device) { + Ok(c) => c, + Err(e) => panic!("Failed to create context: {:?}", e), + }; + let stream = match Stream::new(StreamFlags::NON_BLOCKING, None) { + Ok(s) => s, + Err(e) => panic!("Failed to create stream: {:?}", e), + }; + + let mut in_x = DeviceBuffer::from_slice(&[1.0f32; 10]).unwrap(); + let mut in_y = DeviceBuffer::from_slice(&[2.0f32; 10]).unwrap(); + + // wait for any prior kernels to finish before passing + // the device pointers to ArrayFire + match stream.synchronize() { + Ok(()) => {} + Err(e) => panic!("Stream sync failure: {:?}", e), + }; + + set_device(0); + info(); + + let x = Array::new_from_device_ptr(in_x.as_device_ptr().as_raw_mut(), dim4!(10)); + let y = Array::new_from_device_ptr(in_y.as_device_ptr().as_raw_mut(), dim4!(10)); + + // Lock so that ArrayFire doesn't free pointers from RustaCUDA + // But we have to make sure these pointers stay in valid scope + // as long as the associated ArrayFire Array objects are valid + x.lock(); + y.lock(); + + af_print!("x", x); + af_print!("y", y); + + let o = x + y; + af_print!("out", o); + + let _o_dptr = unsafe { o.device_ptr() }; // Calls an implicit lock + + // User has to call unlock if they want to relenquish control to ArrayFire + + // Once the non-arrayfire operations are done, call unlock. + o.unlock(); // After this, there is no guarantee that value of o_dptr is valid +} diff --git a/cuda-interop/examples/custom_kernel.rs b/cuda-interop/examples/custom_kernel.rs new file mode 100644 index 000000000..c1a012734 --- /dev/null +++ b/cuda-interop/examples/custom_kernel.rs @@ -0,0 +1,83 @@ +use arrayfire as af; +use rustacuda::prelude::*; +use rustacuda::*; + +use std::ffi::CString; + +fn main() { + // MAKE SURE to do all rustacuda initilization before arrayfire API's + // first call. It seems like some CUDA context state is getting messed up + // if we mix CUDA context init(device, context, module, stream) with ArrayFire API + match rustacuda::init(CudaFlags::empty()) { + Ok(()) => {} + Err(e) => panic!("rustacuda init failure: {:?}", e), + } + let device = match Device::get_device(0) { + Ok(d) => d, + Err(e) => panic!("Failed to get device: {:?}", e), + }; + let _context = + match Context::create_and_push(ContextFlags::MAP_HOST | ContextFlags::SCHED_AUTO, device) { + Ok(c) => c, + Err(e) => panic!("Failed to create context: {:?}", e), + }; + let ptx = CString::new(include_str!("./resources/add.ptx")).unwrap(); + let module = match Module::load_from_string(&ptx) { + Ok(m) => m, + Err(e) => panic!("Failed to load module from string: {:?}", e), + }; + let stream = match Stream::new(StreamFlags::NON_BLOCKING, None) { + Ok(s) => s, + Err(e) => panic!("Failed to create stream: {:?}", e), + }; + + af::set_device(0); + af::info(); + + let num: i32 = 10; + let x = af::constant(1f32, af::dim4!(10)); + let y = af::constant(2f32, af::dim4!(10)); + let out = af::constant(0f32, af::dim4!(10)); + + af::af_print!("x", x); + af::af_print!("y", y); + af::af_print!("out(init)", out); + + //TODO Figure out how to use Stream returned by ArrayFire with Rustacuda + // let af_id = get_device(); + // let cuda_id = get_device_native_id(af_id); + // let af_cuda_stream = get_stream(cuda_id); + + //TODO Figure out how to use Stream returned by ArrayFire with Rustacuda + // let stream = Stream {inner: mem::transmute(af_cuda_stream)}; + + // Run a custom CUDA kernel in the ArrayFire CUDA stream + unsafe { + // Obtain device pointers from ArrayFire using Array::device() method + let d_x: *mut f32 = x.device_ptr() as *mut f32; + let d_y: *mut f32 = y.device_ptr() as *mut f32; + let d_o: *mut f32 = out.device_ptr() as *mut f32; + + match launch!(module.sum<<<1, 1, 0, stream>>>( + memory::DevicePointer::wrap(d_x), + memory::DevicePointer::wrap(d_y), + memory::DevicePointer::wrap(d_o), + num + )) { + Ok(()) => {} + Err(e) => panic!("Kernel Launch failure: {:?}", e), + } + + // wait for the kernel to finish as it is async call + match stream.synchronize() { + Ok(()) => {} + Err(e) => panic!("Stream sync failure: {:?}", e), + }; + + // Return control of Array memory to ArrayFire using unlock + x.unlock(); + y.unlock(); + out.unlock(); + } + af::af_print!("sum after kernel launch", out); +} diff --git a/cuda-interop/examples/resources/add.cu b/cuda-interop/examples/resources/add.cu new file mode 100644 index 000000000..5db0dbd39 --- /dev/null +++ b/cuda-interop/examples/resources/add.cu @@ -0,0 +1,7 @@ +extern "C" __constant__ int my_constant = 314; + +extern "C" __global__ void sum(const float* x, const float* y, float* out, int count) { + for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < count; i += blockDim.x * gridDim.x) { + out[i] = x[i] + y[i]; + } +} \ No newline at end of file diff --git a/cuda-interop/examples/resources/add.ptx b/cuda-interop/examples/resources/add.ptx new file mode 100644 index 000000000..cd09eec76 --- /dev/null +++ b/cuda-interop/examples/resources/add.ptx @@ -0,0 +1,61 @@ +// +// Generated by NVIDIA NVVM Compiler +// +// Compiler Build ID: CL-24817639 +// Cuda compilation tools, release 10.0, V10.0.130 +// Based on LLVM 3.4svn +// + +.version 3.2 +.target sm_20 +.address_size 64 + + // .globl sum +.const .align 4 .u32 my_constant = 314; + +.visible .entry sum( + .param .u64 sum_param_0, + .param .u64 sum_param_1, + .param .u64 sum_param_2, + .param .u32 sum_param_3 +) +{ + .reg .pred %p<3>; + .reg .f32 %f<4>; + .reg .b32 %r<11>; + .reg .b64 %rd<11>; + + + ld.param.u64 %rd4, [sum_param_0]; + ld.param.u64 %rd5, [sum_param_1]; + ld.param.u64 %rd6, [sum_param_2]; + ld.param.u32 %r6, [sum_param_3]; + mov.u32 %r1, %ntid.x; + mov.u32 %r7, %ctaid.x; + mov.u32 %r8, %tid.x; + mad.lo.s32 %r10, %r1, %r7, %r8; + setp.ge.s32 %p1, %r10, %r6; + @%p1 bra BB0_3; + + cvta.to.global.u64 %rd1, %rd6; + cvta.to.global.u64 %rd2, %rd5; + cvta.to.global.u64 %rd3, %rd4; + mov.u32 %r9, %nctaid.x; + mul.lo.s32 %r3, %r9, %r1; + +BB0_2: + mul.wide.s32 %rd7, %r10, 4; + add.s64 %rd8, %rd3, %rd7; + add.s64 %rd9, %rd2, %rd7; + ld.global.f32 %f1, [%rd9]; + ld.global.f32 %f2, [%rd8]; + add.f32 %f3, %f2, %f1; + add.s64 %rd10, %rd1, %rd7; + st.global.f32 [%rd10], %f3; + add.s32 %r10, %r3, %r10; + setp.lt.s32 %p2, %r10, %r6; + @%p2 bra BB0_2; + +BB0_3: + ret; +} \ No newline at end of file diff --git a/cuda-interop/src/lib.rs b/cuda-interop/src/lib.rs new file mode 100644 index 000000000..da66e48b5 --- /dev/null +++ b/cuda-interop/src/lib.rs @@ -0,0 +1,60 @@ +//! af-cuda-interop package is to used only when the application intends to mix +//! arrayfire code with raw CUDA code. + +use arrayfire::{handle_error_general, AfError}; +use cuda_runtime_sys::cudaStream_t; +use libc::c_int; + +extern "C" { + fn afcu_get_native_id(native_id: *mut c_int, id: c_int) -> c_int; + fn afcu_set_native_id(native_id: c_int) -> c_int; + fn afcu_get_stream(out: *mut cudaStream_t, id: c_int) -> c_int; +} + +/// Get active device's id in CUDA context +/// +/// # Parameters +/// +/// - `id` is the integer identifier of concerned CUDA device as per ArrayFire context +/// +/// # Return Values +/// +/// Integer identifier of device in CUDA context +pub fn get_device_native_id(id: i32) -> i32 { + unsafe { + let mut temp: i32 = 0; + let err_val = afcu_get_native_id(&mut temp as *mut c_int, id); + handle_error_general(AfError::from(err_val)); + temp + } +} + +/// Set active device using CUDA context's id +/// +/// # Parameters +/// +/// - `id` is the identifier of GPU in CUDA context +pub fn set_device_native_id(native_id: i32) { + unsafe { + let err_val = afcu_set_native_id(native_id); + handle_error_general(AfError::from(err_val)); + } +} + +/// Get CUDA stream of active CUDA device +/// +/// # Parameters +/// +/// - `id` is the identifier of device in ArrayFire context +/// +/// # Return Values +/// +/// [cudaStream_t](https://docs.rs/cuda-runtime-sys/0.3.0-alpha.1/cuda_runtime_sys/type.cudaStream_t.html) handle. +pub fn get_stream(native_id: i32) -> cudaStream_t { + unsafe { + let mut ret_val: cudaStream_t = std::ptr::null_mut(); + let err_val = afcu_get_stream(&mut ret_val as *mut cudaStream_t, native_id); + handle_error_general(AfError::from(err_val)); + ret_val + } +} diff --git a/examples/using_half.rs b/examples/using_half.rs index fd45ddc49..1c447f817 100644 --- a/examples/using_half.rs +++ b/examples/using_half.rs @@ -5,7 +5,7 @@ fn main() { set_device(0); info(); - let values: Vec<_> = (1u8..101).map(f32::from).collect(); + let values: Vec<_> = (1u8..101).map(std::convert::From::from).collect(); let half_values = values.iter().map(|&x| f16::from_f32(x)).collect::>(); diff --git a/opencl-interop/Cargo.toml b/opencl-interop/Cargo.toml new file mode 100644 index 000000000..2b1a0a714 --- /dev/null +++ b/opencl-interop/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "af-opencl-interop" +version = "0.1.0" +authors = ["Pradeep Garigipati "] +edition = "2018" + +[dependencies] +libc = "0.2" +arrayfire = { path = "../" } +cl-sys = "0.4.2" + +[dev-dependencies] +ocl-core = "0.11.2" + +[[example]] +name = "custom_kernel" +path = "examples/custom_kernel.rs" + +[[example]] +name = "ocl_af_app" +path = "examples/ocl_af_app.rs" diff --git a/opencl-interop/README.md b/opencl-interop/README.md new file mode 100644 index 000000000..33360cb3f --- /dev/null +++ b/opencl-interop/README.md @@ -0,0 +1,55 @@ +[![ci][19]][16] [![][18]][3] [![][17]][4] + +> This crate has known issue: Unified API library of ArrayFire used by Rust bindings has bug + that doesn't let us use functions necessary for this crate to work as expected. The associated + fix has already been submitted and should be in next release of ArrayFire i.e. either v3.7.3 or + v.3.8. + +# ArrayFire OpenCL Interop + +This crate is an addition on top of [ArrayFire][1] crate to enable users to mix RAW OpenCL code in rust +and [ArrayFire][1]. + +## Supported platforms + +Supported on all platforms [arrayfire-rust][1] is supported. + +## Usage + +Command to build the crate +``` +cargo build -p af_opencl_interop +``` + +Use the following command to run an example +``` +cargo run -p af_opencl_interop --example custom_kernel +``` + +This crate can be used by directly using the packages on crates.io or building them on your own. +The process for this can be found on [arrayfire-rust#readme][2] + +## Acknowledgements + +The ArrayFire library is written by developers at [ArrayFire][14] LLC with [contributions][15] +from several individuals. The developers at ArrayFire LLC have received partial financial support +from several grants and institutions. Those that wish to receive public acknowledgement are listed +below: + +### Grants + +This material is based upon work supported by the DARPA SBIR Program Office under Contract Numbers +W31P4Q-14-C-0012 and W31P4Q-15-C-0008. Any opinions, findings and conclusions or recommendations +expressed in this material are those of the author(s) and do not necessarily reflect the views of +the DARPA SBIR Program Office. + +[1]: https://github.com/arrayfire/arrayfire-rust +[2]: https://github.com/arrayfire/arrayfire-rust/blob/master/README.md +[3]: http://arrayfire.github.io/arrayfire-rust/af_opencl_interop/index.html +[4]: https://join.slack.com/t/arrayfire-org/shared_invite/MjI4MjIzMDMzMTczLTE1MDI5ODg4NzYtN2QwNGE3ODA5OQ +[14]: https://arrayfire.com/ +[15]: https://github.com/arrayfire/arrayfire_rust/graphs/contributors +[16]: https://github.com/arrayfire/arrayfire-rust/actions?workflow=CI +[17]: https://img.shields.io/badge/af_opencl_interop-community-e69138?logo=slack +[18]: https://img.shields.io/badge/af_opencl_interop-Docs-blue?logo=readthedocs +[19]: https://github.com/arrayfire/arrayfire-rust/workflows/ci/badge.svg?event=push diff --git a/opencl-interop/examples/custom_kernel.rs b/opencl-interop/examples/custom_kernel.rs new file mode 100644 index 000000000..6075aec24 --- /dev/null +++ b/opencl-interop/examples/custom_kernel.rs @@ -0,0 +1,69 @@ +//! A trivial example. Copied from ocl-core crate repository. +use af_opencl_interop as afcl; +use arrayfire as af; + +use ocl_core::{ArgVal, Event}; + +use std::ffi::CString; + +fn main() { + af::info(); + let dims = af::dim4!(8); + let af_buffer = af::constant(0f32, dims.clone()); + af::af_print!("af_buffer", af_buffer); + + let src = r#" + __kernel void add(__global float* buffer, float scalar) { + buffer[get_global_id(0)] += scalar; + } + "#; + + let af_did = afcl::get_device_id(); + let af_ctx = afcl::get_context(false); + let af_que = afcl::get_queue(false); + + let devid = unsafe { ocl_core::DeviceId::from_raw(af_did) }; + let contx = unsafe { ocl_core::Context::from_raw_copied_ptr(af_ctx) }; + let queue = unsafe { ocl_core::CommandQueue::from_raw_copied_ptr(af_que) }; + + // Define which platform and device(s) to use. Create a context, + // queue, and program then define some dims.. + let src_cstring = CString::new(src).unwrap(); + let program = ocl_core::create_program_with_source(&contx, &[src_cstring]).unwrap(); + ocl_core::build_program( + &program, + None::<&[()]>, + &CString::new("").unwrap(), + None, + None, + ) + .unwrap(); + + // Fetch cl_mem from ArrayFire Array + let ptr = unsafe { af_buffer.device_ptr() }; + let buffer = unsafe { ocl_core::Mem::from_raw_copied_ptr(ptr) }; + + // Create a kernel with arguments matching those in the source above: + let kernel = ocl_core::create_kernel(&program, "add").unwrap(); + ocl_core::set_kernel_arg(&kernel, 0, ArgVal::mem(&buffer)).unwrap(); + ocl_core::set_kernel_arg(&kernel, 1, ArgVal::scalar(&10.0f32)).unwrap(); + + let ocl_dims: [usize; 3] = [dims[0] as usize, dims[1] as usize, dims[2] as usize]; + unsafe { + ocl_core::enqueue_kernel( + &queue, + &kernel, + 1, + None, + &ocl_dims, + None, + None::, + None::<&mut Event>, + ) + .unwrap(); + } + ocl_core::finish(&queue).unwrap(); + af_buffer.unlock(); //Give back control of cl_mem to ArrayFire memory manager + + af::af_print!("af_buffer after running Custom Kernel on it", af_buffer); +} diff --git a/opencl-interop/examples/ocl_af_app.rs b/opencl-interop/examples/ocl_af_app.rs new file mode 100644 index 000000000..cc773b115 --- /dev/null +++ b/opencl-interop/examples/ocl_af_app.rs @@ -0,0 +1,67 @@ +//! A trivial example. Copied from ocl-core crate repository. +use af_opencl_interop as afcl; +use arrayfire as af; + +use ocl_core::{ContextProperties, Event}; + +fn main() { + // Choose platform & device(s) to use. Create a context, queue, + let platform_id = ocl_core::default_platform().unwrap(); + let device_ids = ocl_core::get_device_ids(&platform_id, None, None).unwrap(); + let device_id = device_ids[0]; + let context_properties = ContextProperties::new().platform(platform_id); + let context = + ocl_core::create_context(Some(&context_properties), &[device_id], None, None).unwrap(); + let queue = ocl_core::create_command_queue(&context, &device_id, None).unwrap(); + let dims = [8, 1, 1]; + + // Create a `Buffer`: + let mut vec = vec![0.0f32; dims[0]]; + let buffer = unsafe { + ocl_core::create_buffer( + &context, + ocl_core::MEM_READ_WRITE | ocl_core::MEM_COPY_HOST_PTR, + dims[0], + Some(&vec), + ) + .unwrap() + }; + ocl_core::finish(&queue).unwrap(); //sync up before switching to arrayfire + + // Add custom device, context and associated queue to ArrayFire + afcl::add_device_context(device_id.as_raw(), context.as_ptr(), queue.as_ptr()); + afcl::set_device_context(device_id.as_raw(), context.as_ptr()); + af::info(); + + let mut af_buffer = af::Array::new_from_device_ptr( + buffer.as_ptr() as *mut f32, + af::Dim4::new(&[dims[0] as u64, 1, 1, 1]), + ); + + af::af_print!("GPU Buffer before modification:", af_buffer); + + af_buffer = af_buffer + 10f32; + + af::sync(af::get_device()); + unsafe { + let ptr = af_buffer.device_ptr(); + let obuf = ocl_core::Mem::from_raw_copied_ptr(ptr); + + // Read results from the device into a vector: + ocl_core::enqueue_read_buffer( + &queue, + &obuf, + true, + 0, + &mut vec, + None::, + None::<&mut Event>, + ) + .unwrap(); + } + println!("GPU buffer on host after ArrayFire operation: {:?}", vec); + + // Remove device from ArrayFire management towards Application Exit + af::set_device(0); // Cannot pop when in Use, hence switch to another device + afcl::delete_device_context(device_id.as_raw(), context.as_ptr()); +} diff --git a/opencl-interop/examples/trivial.rs b/opencl-interop/examples/trivial.rs new file mode 100644 index 000000000..d29020efb --- /dev/null +++ b/opencl-interop/examples/trivial.rs @@ -0,0 +1,85 @@ +//! A trivial example. +//! +//! Copied from ocl. + +extern crate ocl_core as core; + +use crate::core::{ArgVal, ContextProperties, Event}; +use std::ffi::CString; + +#[allow(dead_code, unused_variables, unused_mut)] +fn main() { + let src = r#" + __kernel void add(__global float* buffer, float scalar) { + buffer[get_global_id(0)] += scalar; + } + "#; + + // (1) Define which platform and device(s) to use. Create a context, + // queue, and program then define some dims.. + let platform_id = core::default_platform().unwrap(); + let device_ids = core::get_device_ids(&platform_id, None, None).unwrap(); + let device_id = device_ids[0]; + let context_properties = ContextProperties::new().platform(platform_id); + let context = + core::create_context(Some(&context_properties), &[device_id], None, None).unwrap(); + let src_cstring = CString::new(src).unwrap(); + let program = core::create_program_with_source(&context, &[src_cstring]).unwrap(); + core::build_program( + &program, + None::<&[()]>, + &CString::new("").unwrap(), + None, + None, + ) + .unwrap(); + let queue = core::create_command_queue(&context, &device_id, None).unwrap(); + let dims = [1 << 20, 1, 1]; + + // (2) Create a `Buffer`: + let mut vec = vec![0.0f32; dims[0]]; + let buffer = unsafe { + core::create_buffer( + &context, + core::MEM_READ_WRITE | core::MEM_COPY_HOST_PTR, + dims[0], + Some(&vec), + ) + .unwrap() + }; + + // (3) Create a kernel with arguments matching those in the source above: + let kernel = core::create_kernel(&program, "add").unwrap(); + core::set_kernel_arg(&kernel, 0, ArgVal::mem(&buffer)).unwrap(); + core::set_kernel_arg(&kernel, 1, ArgVal::scalar(&10.0f32)).unwrap(); + + unsafe { + // (4) Run the kernel: + core::enqueue_kernel( + &queue, + &kernel, + 1, + None, + &dims, + None, + None::, + None::<&mut Event>, + ) + .unwrap(); + + // (5) Read results from the device into a vector: + core::enqueue_read_buffer( + &queue, + &buffer, + true, + 0, + &mut vec, + None::, + None::<&mut Event>, + ) + .unwrap(); + } + + // Print an element: + println!("The value at index [{}] is now '{}'!", 200007, vec[200007]); +} diff --git a/opencl-interop/src/lib.rs b/opencl-interop/src/lib.rs new file mode 100644 index 000000000..2f4698233 --- /dev/null +++ b/opencl-interop/src/lib.rs @@ -0,0 +1,143 @@ +//! af-opencl-interop package is to used only when the application intends to mix +//! arrayfire code with raw OpenCL code. +//! +//! Functions from this crate return OpenCL C API opaque pointers typedefs +//! +//! - [cl_device_id](https://docs.rs/cl-sys/0.4.2/cl_sys/type.cl_device_id.html) +//! - [cl_context](https://docs.rs/cl-sys/0.4.2/cl_sys/type.cl_context.html) +//! - [cl_command_queue](https://docs.rs/cl-sys/0.4.2/cl_sys/type.cl_command_queue.html) + +use arrayfire::{AfError, HANDLE_ERROR}; +use cl_sys::{ + cl_command_queue, cl_context, cl_device_id, CL_DEVICE_TYPE_ACCELERATOR, CL_DEVICE_TYPE_ALL, + CL_DEVICE_TYPE_CPU, CL_DEVICE_TYPE_DEFAULT, CL_DEVICE_TYPE_GPU, +}; +use libc::c_int; +use std::mem; + +/// OpenCL Vendor Platform +#[repr(i32)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum VendorPlatform { + AMD = 0, + APPLE = 1, + INTEL = 2, + NVIDIA = 3, + BEIGNET = 4, + POCL = 5, + UNKNOWN = -1, +} + +/// OpenCL Device Type +#[repr(u64)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum DeviceType { + DEFAULT = CL_DEVICE_TYPE_DEFAULT, + CPU = CL_DEVICE_TYPE_CPU, + GPU = CL_DEVICE_TYPE_GPU, + ACCEL = CL_DEVICE_TYPE_ACCELERATOR, + ALL = CL_DEVICE_TYPE_ALL, +} + +extern "C" { + fn afcl_get_context(ctx: *mut cl_context, retain: bool) -> c_int; + fn afcl_get_queue(queue: *mut cl_command_queue, retain: bool) -> c_int; + fn afcl_get_device_id(out: *mut cl_device_id) -> c_int; + fn afcl_set_device_id(id: cl_device_id) -> c_int; + + fn afcl_add_device_context( + dev_id: cl_device_id, + ctx: cl_context, + queue: cl_command_queue, + ) -> c_int; + fn afcl_set_device_context(dev_id: cl_device_id, ctx: cl_context) -> c_int; + fn afcl_delete_device_context(dev_id: cl_device_id, ctx: cl_context) -> c_int; + + fn afcl_get_device_type(dtype: *mut c_int) -> c_int; + fn afcl_get_platform(ptype: *mut c_int) -> c_int; +} + +/// Get the handle to active ArrayFire OpenCL context +pub fn get_context(retain: bool) -> cl_context { + unsafe { + let mut out: cl_context = std::ptr::null_mut(); + let err_val = afcl_get_context(&mut out as *mut cl_context, retain); + HANDLE_ERROR(AfError::from(err_val)); + out + } +} + +/// Get the handle to active ArrayFire OpenCL command queue +pub fn get_queue(retain: bool) -> cl_command_queue { + unsafe { + let mut out: cl_command_queue = std::ptr::null_mut(); + let err_val = afcl_get_queue(&mut out as *mut cl_command_queue, retain); + HANDLE_ERROR(AfError::from(err_val)); + out + } +} + +/// Get the handle to active ArrayFire OpenCL device +pub fn get_device_id() -> cl_device_id { + unsafe { + let mut out: cl_device_id = std::ptr::null_mut(); + let err_val = afcl_get_device_id(&mut out as *mut cl_device_id); + HANDLE_ERROR(AfError::from(err_val)); + out + } +} + +/// Set the cl_device_id as the active ArrayFire OpenCL device +pub fn set_device_id(dev_id: cl_device_id) { + unsafe { + let err_val = afcl_set_device_id(dev_id); + HANDLE_ERROR(AfError::from(err_val)); + } +} + +/// Push user provided device, context and queue tuple to ArrayFire device mamanger +pub fn add_device_context(dev_id: cl_device_id, ctx: cl_context, queue: cl_command_queue) { + unsafe { + let err_val = afcl_add_device_context(dev_id, ctx, queue); + HANDLE_ERROR(AfError::from(err_val)); + } +} + +/// Set the device identified by device & context pair as the active device for ArrayFire +pub fn set_device_context(dev_id: cl_device_id, ctx: cl_context) { + unsafe { + let err_val = afcl_set_device_context(dev_id, ctx); + HANDLE_ERROR(AfError::from(err_val)); + } +} + +/// Remove the user provided device, context pair from ArrayFire device mamanger +pub fn delete_device_context(dev_id: cl_device_id, ctx: cl_context) { + unsafe { + let err_val = afcl_delete_device_context(dev_id, ctx); + HANDLE_ERROR(AfError::from(err_val)); + } +} + +///// Fetch Active ArrayFire device's type i.e. CPU/GPU/Accelerator etc. +pub fn get_device_type() -> DeviceType { + unsafe { + let mut out: i32 = 0; + let err_val = afcl_get_device_type(&mut out as *mut c_int); + HANDLE_ERROR(AfError::from(err_val)); + match out { + -1 => mem::transmute(out as u64), + _ => DeviceType::ALL, + } + } +} + +/// Fetch Active ArrayFire device's vendor platform +pub fn get_platform() -> VendorPlatform { + unsafe { + let mut out: i32 = 0; + let err_val = afcl_get_platform(&mut out as *mut c_int); + HANDLE_ERROR(AfError::from(err_val)); + mem::transmute(out) + } +} diff --git a/scripts/generate_documentation.sh b/scripts/generate_documentation.sh index 8c8f40cbf..c9899e332 100755 --- a/scripts/generate_documentation.sh +++ b/scripts/generate_documentation.sh @@ -3,5 +3,7 @@ # this script meant to be run from the root of arrayfire-rust cargo rustdoc -p arrayfire -- --html-in-header ./scripts/mathjax.script +cargo rustdoc -p af-cuda-interop -- --html-in-header ./scripts/mathjax.script +cargo rustdoc -p af-opencl-interop -- --html-in-header ./scripts/mathjax.script -mdbook build tutorials-book && cp -r tutorials-book/book ./target/doc/arrayfire/ +mdbook build tutorials-book && cp -r tutorials-book/book ./target/doc/ diff --git a/src/algorithm/mod.rs b/src/algorithm/mod.rs index 0bcc89e91..f8cf2ac19 100644 --- a/src/algorithm/mod.rs +++ b/src/algorithm/mod.rs @@ -1,126 +1,135 @@ -extern crate libc; +use super::core::{ + af_array, AfError, Array, BinaryOp, HasAfEnum, RealNumber, ReduceByKeyInput, Scanable, + HANDLE_ERROR, +}; -use self::libc::{c_double, c_int, c_uint}; -use crate::array::Array; -use crate::defines::{AfError, BinaryOp}; -use crate::error::HANDLE_ERROR; -use crate::util::{AfArray, MutAfArray, MutDouble, MutUint}; -use crate::util::{HasAfEnum, RealNumber, ReduceByKeyInput, Scanable}; +use libc::{c_double, c_int, c_uint}; -#[allow(dead_code)] extern "C" { - fn af_sum(out: MutAfArray, input: AfArray, dim: c_int) -> c_int; - fn af_sum_nan(out: MutAfArray, input: AfArray, dim: c_int, nanval: c_double) -> c_int; - fn af_product(out: MutAfArray, input: AfArray, dim: c_int) -> c_int; - fn af_product_nan(out: MutAfArray, input: AfArray, dim: c_int, val: c_double) -> c_int; - fn af_min(out: MutAfArray, input: AfArray, dim: c_int) -> c_int; - fn af_max(out: MutAfArray, input: AfArray, dim: c_int) -> c_int; - fn af_all_true(out: MutAfArray, input: AfArray, dim: c_int) -> c_int; - fn af_any_true(out: MutAfArray, input: AfArray, dim: c_int) -> c_int; - fn af_count(out: MutAfArray, input: AfArray, dim: c_int) -> c_int; - fn af_sum_all(r: MutDouble, i: MutDouble, input: AfArray) -> c_int; - fn af_sum_nan_all(r: MutDouble, i: MutDouble, input: AfArray, val: c_double) -> c_int; - fn af_product_all(r: MutDouble, i: MutDouble, input: AfArray) -> c_int; - fn af_product_nan_all(r: MutDouble, i: MutDouble, input: AfArray, val: c_double) -> c_int; - fn af_min_all(r: MutDouble, i: MutDouble, input: AfArray) -> c_int; - fn af_max_all(r: MutDouble, i: MutDouble, input: AfArray) -> c_int; - fn af_all_true_all(r: MutDouble, i: MutDouble, input: AfArray) -> c_int; - fn af_any_true_all(r: MutDouble, i: MutDouble, input: AfArray) -> c_int; - fn af_count_all(r: MutDouble, i: MutDouble, input: AfArray) -> c_int; - fn af_imin(out: MutAfArray, idx: MutAfArray, input: AfArray, dim: c_int) -> c_int; - fn af_imax(out: MutAfArray, idx: MutAfArray, input: AfArray, dim: c_int) -> c_int; - fn af_imin_all(r: MutDouble, i: MutDouble, idx: MutUint, input: AfArray) -> c_int; - fn af_imax_all(r: MutDouble, i: MutDouble, idx: MutUint, input: AfArray) -> c_int; - fn af_accum(out: MutAfArray, input: AfArray, dim: c_int) -> c_int; - fn af_where(out: MutAfArray, input: AfArray) -> c_int; - fn af_diff1(out: MutAfArray, input: AfArray, dim: c_int) -> c_int; - fn af_diff2(out: MutAfArray, input: AfArray, dim: c_int) -> c_int; - fn af_sort(out: MutAfArray, input: AfArray, dim: c_uint, ascend: c_int) -> c_int; - fn af_sort_index(o: MutAfArray, i: MutAfArray, inp: AfArray, d: c_uint, a: c_int) -> c_int; - fn af_set_unique(out: MutAfArray, input: AfArray, is_sorted: c_int) -> c_int; - fn af_set_union(out: MutAfArray, first: AfArray, second: AfArray, is_unq: c_int) -> c_int; - fn af_set_intersect(out: MutAfArray, one: AfArray, two: AfArray, is_unq: c_int) -> c_int; + fn af_sum(out: *mut af_array, input: af_array, dim: c_int) -> c_int; + fn af_sum_nan(out: *mut af_array, input: af_array, dim: c_int, nanval: c_double) -> c_int; + fn af_product(out: *mut af_array, input: af_array, dim: c_int) -> c_int; + fn af_product_nan(out: *mut af_array, input: af_array, dim: c_int, val: c_double) -> c_int; + fn af_min(out: *mut af_array, input: af_array, dim: c_int) -> c_int; + fn af_max(out: *mut af_array, input: af_array, dim: c_int) -> c_int; + fn af_all_true(out: *mut af_array, input: af_array, dim: c_int) -> c_int; + fn af_any_true(out: *mut af_array, input: af_array, dim: c_int) -> c_int; + fn af_count(out: *mut af_array, input: af_array, dim: c_int) -> c_int; + fn af_sum_all(r: *mut c_double, i: *mut c_double, input: af_array) -> c_int; + fn af_sum_nan_all(r: *mut c_double, i: *mut c_double, input: af_array, val: c_double) -> c_int; + fn af_product_all(r: *mut c_double, i: *mut c_double, input: af_array) -> c_int; + fn af_product_nan_all( + r: *mut c_double, + i: *mut c_double, + input: af_array, + val: c_double, + ) -> c_int; + fn af_min_all(r: *mut c_double, i: *mut c_double, input: af_array) -> c_int; + fn af_max_all(r: *mut c_double, i: *mut c_double, input: af_array) -> c_int; + fn af_all_true_all(r: *mut c_double, i: *mut c_double, input: af_array) -> c_int; + fn af_any_true_all(r: *mut c_double, i: *mut c_double, input: af_array) -> c_int; + fn af_count_all(r: *mut c_double, i: *mut c_double, input: af_array) -> c_int; + fn af_imin(out: *mut af_array, idx: *mut af_array, input: af_array, dim: c_int) -> c_int; + fn af_imax(out: *mut af_array, idx: *mut af_array, input: af_array, dim: c_int) -> c_int; + fn af_imin_all(r: *mut c_double, i: *mut c_double, idx: *mut c_uint, input: af_array) -> c_int; + fn af_imax_all(r: *mut c_double, i: *mut c_double, idx: *mut c_uint, input: af_array) -> c_int; + fn af_accum(out: *mut af_array, input: af_array, dim: c_int) -> c_int; + fn af_where(out: *mut af_array, input: af_array) -> c_int; + fn af_diff1(out: *mut af_array, input: af_array, dim: c_int) -> c_int; + fn af_diff2(out: *mut af_array, input: af_array, dim: c_int) -> c_int; + fn af_sort(out: *mut af_array, input: af_array, dim: c_uint, ascend: bool) -> c_int; + fn af_sort_index( + o: *mut af_array, + i: *mut af_array, + inp: af_array, + d: c_uint, + a: bool, + ) -> c_int; + fn af_set_unique(out: *mut af_array, input: af_array, is_sorted: bool) -> c_int; + fn af_set_union(out: *mut af_array, first: af_array, second: af_array, is_unq: bool) -> c_int; + fn af_set_intersect(out: *mut af_array, one: af_array, two: af_array, is_unq: bool) -> c_int; fn af_sort_by_key( - out_keys: MutAfArray, - out_vals: MutAfArray, - in_keys: AfArray, - in_vals: AfArray, + out_keys: *mut af_array, + out_vals: *mut af_array, + in_keys: af_array, + in_vals: af_array, dim: c_uint, - ascend: c_int, + ascend: bool, ) -> c_int; - fn af_scan(out: MutAfArray, inp: AfArray, dim: c_int, op: c_uint, inclusive: c_int) -> c_int; + fn af_scan(out: *mut af_array, inp: af_array, dim: c_int, op: c_uint, inclusive: bool) + -> c_int; fn af_scan_by_key( - out: MutAfArray, - key: AfArray, - inp: AfArray, + out: *mut af_array, + key: af_array, + inp: af_array, dim: c_int, op: c_uint, - inclusive: c_int, + inclusive: bool, ) -> c_int; fn af_all_true_by_key( - keys_out: MutAfArray, - vals_out: MutAfArray, - keys: AfArray, - vals: AfArray, + keys_out: *mut af_array, + vals_out: *mut af_array, + keys: af_array, + vals: af_array, dim: c_int, ) -> c_int; fn af_any_true_by_key( - keys_out: MutAfArray, - vals_out: MutAfArray, - keys: AfArray, - vals: AfArray, + keys_out: *mut af_array, + vals_out: *mut af_array, + keys: af_array, + vals: af_array, dim: c_int, ) -> c_int; fn af_count_by_key( - keys_out: MutAfArray, - vals_out: MutAfArray, - keys: AfArray, - vals: AfArray, + keys_out: *mut af_array, + vals_out: *mut af_array, + keys: af_array, + vals: af_array, dim: c_int, ) -> c_int; fn af_max_by_key( - keys_out: MutAfArray, - vals_out: MutAfArray, - keys: AfArray, - vals: AfArray, + keys_out: *mut af_array, + vals_out: *mut af_array, + keys: af_array, + vals: af_array, dim: c_int, ) -> c_int; fn af_min_by_key( - keys_out: MutAfArray, - vals_out: MutAfArray, - keys: AfArray, - vals: AfArray, + keys_out: *mut af_array, + vals_out: *mut af_array, + keys: af_array, + vals: af_array, dim: c_int, ) -> c_int; fn af_product_by_key( - keys_out: MutAfArray, - vals_out: MutAfArray, - keys: AfArray, - vals: AfArray, + keys_out: *mut af_array, + vals_out: *mut af_array, + keys: af_array, + vals: af_array, dim: c_int, ) -> c_int; fn af_product_by_key_nan( - keys_out: MutAfArray, - vals_out: MutAfArray, - keys: AfArray, - vals: AfArray, + keys_out: *mut af_array, + vals_out: *mut af_array, + keys: af_array, + vals: af_array, dim: c_int, nan_val: c_double, ) -> c_int; fn af_sum_by_key( - keys_out: MutAfArray, - vals_out: MutAfArray, - keys: AfArray, - vals: AfArray, + keys_out: *mut af_array, + vals_out: *mut af_array, + keys: af_array, + vals: af_array, dim: c_int, ) -> c_int; fn af_sum_by_key_nan( - keys_out: MutAfArray, - vals_out: MutAfArray, - keys: AfArray, - vals: AfArray, + keys_out: *mut af_array, + vals_out: *mut af_array, + keys: af_array, + vals: af_array, dim: c_int, nan_val: c_double, ) -> c_int; @@ -129,22 +138,17 @@ extern "C" { macro_rules! dim_reduce_func_def { ($doc_str: expr, $fn_name: ident, $ffi_name: ident, $out_type: ty) => { #[doc=$doc_str] - #[allow(unused_mut)] pub fn $fn_name(input: &Array, dim: i32) -> Array<$out_type> where T: HasAfEnum, $out_type: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = $ffi_name( - &mut temp as MutAfArray, - input.get() as AfArray, - dim as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = $ffi_name(&mut temp as *mut af_array, input.get(), dim); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } }; } @@ -479,17 +483,12 @@ where T: HasAfEnum, T::AggregateOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_sum_nan( - &mut temp as MutAfArray, - input.get() as AfArray, - dim as c_int, - nanval as c_double, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_sum_nan(&mut temp as *mut af_array, input.get(), dim, nanval); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Product of elements along specific dimension using user specified value instead of `NAN` values @@ -510,31 +509,23 @@ where T: HasAfEnum, T::ProductOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_product_nan( - &mut temp as MutAfArray, - input.get() as AfArray, - dim as c_int, - nanval as c_double, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_product_nan(&mut temp as *mut af_array, input.get(), dim, nanval); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } macro_rules! all_reduce_func_def { ($doc_str: expr, $fn_name: ident, $ffi_name: ident) => { #[doc=$doc_str] - #[allow(unused_mut)] pub fn $fn_name(input: &Array) -> (f64, f64) { let mut real: f64 = 0.0; let mut imag: f64 = 0.0; unsafe { let err_val = $ffi_name( - &mut real as MutDouble, - &mut imag as MutDouble, - input.get() as AfArray, + &mut real as *mut c_double, &mut imag as *mut c_double, input.get(), ); HANDLE_ERROR(AfError::from(err_val)); } @@ -754,10 +745,10 @@ pub fn sum_nan_all(input: &Array, val: f64) -> (f64, f64) { let mut imag: f64 = 0.0; unsafe { let err_val = af_sum_nan_all( - &mut real as MutDouble, - &mut imag as MutDouble, - input.get() as AfArray, - val as c_double, + &mut real as *mut c_double, + &mut imag as *mut c_double, + input.get(), + val, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -784,10 +775,10 @@ pub fn product_nan_all(input: &Array, val: f64) -> (f64, f64) { let mut imag: f64 = 0.0; unsafe { let err_val = af_product_nan_all( - &mut real as MutDouble, - &mut imag as MutDouble, - input.get() as AfArray, - val as c_double, + &mut real as *mut c_double, + &mut imag as *mut c_double, + input.get(), + val, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -797,24 +788,20 @@ pub fn product_nan_all(input: &Array, val: f64) -> (f64, f64) { macro_rules! dim_ireduce_func_def { ($doc_str: expr, $fn_name: ident, $ffi_name: ident, $out_type: ident) => { #[doc=$doc_str] - #[allow(unused_mut)] pub fn $fn_name(input: &Array, dim: i32) -> (Array, Array) where T: HasAfEnum, T::$out_type: HasAfEnum, { - let mut temp: i64 = 0; - let mut idx: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); + let mut idx: af_array = std::ptr::null_mut(); let err_val = $ffi_name( - &mut temp as MutAfArray, - &mut idx as MutAfArray, - input.get() as AfArray, - dim as c_int, + &mut temp as *mut af_array, &mut idx as *mut af_array, input.get(), dim, ); HANDLE_ERROR(AfError::from(err_val)); - } (temp.into(), idx.into()) + } } }; } @@ -848,17 +835,14 @@ dim_ireduce_func_def!(" macro_rules! all_ireduce_func_def { ($doc_str: expr, $fn_name: ident, $ffi_name: ident) => { #[doc=$doc_str] - #[allow(unused_mut)] pub fn $fn_name(input: &Array) -> (f64, f64, u32) { let mut real: f64 = 0.0; let mut imag: f64 = 0.0; let mut temp: u32 = 0; unsafe { let err_val = $ffi_name( - &mut real as MutDouble, - &mut imag as MutDouble, - &mut temp as MutUint, - input.get() as AfArray, + &mut real as *mut c_double, &mut imag as *mut c_double, + &mut temp as *mut c_uint, input.get(), ); HANDLE_ERROR(AfError::from(err_val)); } @@ -917,14 +901,13 @@ all_ireduce_func_def!( /// # Return Values /// /// Array of indices where the input Array has non-zero values. -#[allow(unused_mut)] pub fn locate(input: &Array) -> Array { - let mut temp: i64 = 0; unsafe { - let err_val = af_where(&mut temp as MutAfArray, input.get() as AfArray); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_where(&mut temp as *mut af_array, input.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Sort the values in input Arrays @@ -941,22 +924,16 @@ pub fn locate(input: &Array) -> Array { /// # Return Values /// /// Sorted Array. -#[allow(unused_mut)] pub fn sort(input: &Array, dim: u32, ascending: bool) -> Array where T: HasAfEnum + RealNumber, { - let mut temp: i64 = 0; unsafe { - let err_val = af_sort( - &mut temp as MutAfArray, - input.get() as AfArray, - dim as c_uint, - ascending as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_sort(&mut temp as *mut af_array, input.get(), dim, ascending); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Sort the values in input Arrays @@ -975,24 +952,23 @@ where /// The first Array contains the keys based on sorted values. /// /// The second Array contains the original indices of the sorted values. -#[allow(unused_mut)] pub fn sort_index(input: &Array, dim: u32, ascending: bool) -> (Array, Array) where T: HasAfEnum + RealNumber, { - let mut temp: i64 = 0; - let mut idx: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); + let mut idx: af_array = std::ptr::null_mut(); let err_val = af_sort_index( - &mut temp as MutAfArray, - &mut idx as MutAfArray, - input.get() as AfArray, - dim as c_uint, - ascending as c_int, + &mut temp as *mut af_array, + &mut idx as *mut af_array, + input.get(), + dim, + ascending, ); HANDLE_ERROR(AfError::from(err_val)); + (temp.into(), idx.into()) } - (temp.into(), idx.into()) } /// Sort the values in input Arrays @@ -1013,7 +989,6 @@ where /// The first Array contains the keys based on sorted values. /// /// The second Array contains the sorted values. -#[allow(unused_mut)] pub fn sort_by_key( keys: &Array, vals: &Array, @@ -1024,20 +999,20 @@ where K: HasAfEnum + RealNumber, V: HasAfEnum, { - let mut temp: i64 = 0; - let mut temp2: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); + let mut temp2: af_array = std::ptr::null_mut(); let err_val = af_sort_by_key( - &mut temp as MutAfArray, - &mut temp2 as MutAfArray, - keys.get() as AfArray, - vals.get() as AfArray, - dim as c_uint, - ascending as c_int, + &mut temp as *mut af_array, + &mut temp2 as *mut af_array, + keys.get(), + vals.get(), + dim, + ascending, ); HANDLE_ERROR(AfError::from(err_val)); + (temp.into(), temp2.into()) } - (temp.into(), temp2.into()) } /// Find unique values from a Set @@ -1051,21 +1026,16 @@ where /// # Return Values /// /// An Array of unique values from the input Array. -#[allow(unused_mut)] pub fn set_unique(input: &Array, is_sorted: bool) -> Array where T: HasAfEnum + RealNumber, { - let mut temp: i64 = 0; unsafe { - let err_val = af_set_unique( - &mut temp as MutAfArray, - input.get() as AfArray, - is_sorted as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_set_unique(&mut temp as *mut af_array, input.get(), is_sorted); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Find union of two sets @@ -1079,22 +1049,21 @@ where /// # Return Values /// /// An Array with union of the input sets -#[allow(unused_mut)] pub fn set_union(first: &Array, second: &Array, is_unique: bool) -> Array where T: HasAfEnum + RealNumber, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_set_union( - &mut temp as MutAfArray, - first.get() as AfArray, - second.get() as AfArray, - is_unique as c_int, + &mut temp as *mut af_array, + first.get(), + second.get(), + is_unique, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Find intersection of two sets @@ -1108,22 +1077,21 @@ where /// # Return Values /// /// An Array with intersection of the input sets -#[allow(unused_mut)] pub fn set_intersect(first: &Array, second: &Array, is_unique: bool) -> Array where T: HasAfEnum + RealNumber, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_set_intersect( - &mut temp as MutAfArray, - first.get() as AfArray, - second.get() as AfArray, - is_unique as c_int, + &mut temp as *mut af_array, + first.get(), + second.get(), + is_unique, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Generalized scan @@ -1149,18 +1117,18 @@ where T: HasAfEnum, T::AggregateOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_scan( - &mut temp as MutAfArray, - input.get() as AfArray, - dim as c_int, - op as c_uint, - inclusive as c_int, + &mut temp as *mut af_array, + input.get(), + dim, + op as u32, + inclusive, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Generalized scan by key @@ -1189,19 +1157,19 @@ where V::AggregateOutType: HasAfEnum, K: HasAfEnum + Scanable, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); 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 c_uint, - inclusive as c_int, + &mut temp as *mut af_array, + key.get(), + input.get(), + dim, + op as u32, + inclusive, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } macro_rules! dim_reduce_by_key_func_def { @@ -1226,19 +1194,16 @@ macro_rules! dim_reduce_by_key_func_def { ValueType: HasAfEnum, $out_type: HasAfEnum, { - let mut out_keys: i64 = 0; - let mut out_vals: i64 = 0; unsafe { + let mut out_keys: af_array = std::ptr::null_mut(); + let mut out_vals: af_array = std::ptr::null_mut(); let err_val = $ffi_name( - &mut out_keys as MutAfArray, - &mut out_vals as MutAfArray, - keys.get() as AfArray, - vals.get() as AfArray, - dim as c_int, + &mut out_keys as *mut af_array, &mut out_vals as *mut af_array, + keys.get(), vals.get(), dim, ); HANDLE_ERROR(AfError::from(err_val)); - } (out_keys.into(), out_vals.into()) + } } }; } @@ -1360,20 +1325,17 @@ macro_rules! dim_reduce_by_key_nan_func_def { ValueType: HasAfEnum, $out_type: HasAfEnum, { - let mut out_keys: i64 = 0; - let mut out_vals: i64 = 0; unsafe { + let mut out_keys: af_array = std::ptr::null_mut(); + let mut out_vals: af_array = std::ptr::null_mut(); let err_val = $ffi_name( - &mut out_keys as MutAfArray, - &mut out_vals as MutAfArray, - keys.get() as AfArray, - vals.get() as AfArray, - dim as c_int, - replace_value as c_double, + &mut out_keys as *mut af_array, + &mut out_vals as *mut af_array, + keys.get(), vals.get(), dim, replace_value, ); HANDLE_ERROR(AfError::from(err_val)); - } (out_keys.into(), out_vals.into()) + } } }; } diff --git a/src/blas/mod.rs b/src/blas/mod.rs index a607f4f52..419799356 100644 --- a/src/blas/mod.rs +++ b/src/blas/mod.rs @@ -1,38 +1,39 @@ -extern crate libc; +use super::core::{ + af_array, AfError, Array, CublasMathMode, FloatingPoint, HasAfEnum, MatProp, HANDLE_ERROR, +}; -use self::libc::{c_int, c_uint, c_void}; -use crate::array::Array; -use crate::defines::{AfError, CublasMathMode, MatProp}; -use crate::error::HANDLE_ERROR; -use crate::util::{to_u32, AfArray, MutAfArray}; -use crate::util::{FloatingPoint, HasAfEnum}; +use libc::{c_int, c_uint, c_void}; use std::vec::Vec; -#[allow(dead_code)] extern "C" { fn af_gemm( - out: MutAfArray, + out: *mut af_array, optlhs: c_uint, optrhs: c_uint, alpha: *const c_void, - lhs: AfArray, - rhs: AfArray, + lhs: af_array, + rhs: af_array, beta: *const c_void, ) -> c_int; fn af_matmul( - out: MutAfArray, - lhs: AfArray, - rhs: AfArray, + out: *mut af_array, + lhs: af_array, + rhs: af_array, optlhs: c_uint, optrhs: c_uint, ) -> c_int; - fn af_dot(out: MutAfArray, lhs: AfArray, rhs: AfArray, optlhs: c_uint, optrhs: c_uint) - -> c_int; + fn af_dot( + out: *mut af_array, + lhs: af_array, + rhs: af_array, + optlhs: c_uint, + optrhs: c_uint, + ) -> c_int; - fn af_transpose(out: MutAfArray, arr: AfArray, conjugate: c_int) -> c_int; - fn af_transpose_inplace(arr: AfArray, conjugate: c_int) -> c_int; + fn af_transpose(out: *mut af_array, arr: af_array, conjugate: bool) -> c_int; + fn af_transpose_inplace(arr: af_array, conjugate: bool) -> c_int; fn afcu_cublasSetMathMode(mode: c_int) -> c_int; } @@ -90,7 +91,7 @@ extern "C" { /// [matmul](./fn.matmul.html) for more terse code. /// /// ```rust -/// use arrayfire::{Array, Dim4, print, randu, gemm}; +/// use arrayfire::{Array, Dim4, af_array, print, randu, gemm}; /// /// let dims = Dim4::new(&[5, 5, 1, 1]); /// @@ -100,7 +101,7 @@ extern "C" { /// let lhs = randu::(dims); /// let rhs = randu::(dims); /// -/// let mut result: Array:: = (0 as i64).into(); +/// let mut result: Array:: = (std::ptr::null_mut() as af_array).into(); /// /// gemm(&mut result, arrayfire::MatProp::NONE, arrayfire::MatProp::NONE, /// alpha, &lhs, &rhs, beta); @@ -129,20 +130,20 @@ pub fn gemm( ) where T: HasAfEnum + FloatingPoint, { - let mut out = output.get(); unsafe { + let mut out = output.get(); let err_val = af_gemm( - &mut out as MutAfArray, - to_u32(optlhs) as c_uint, - to_u32(optrhs) as c_uint, + &mut out as *mut af_array, + optlhs as c_uint, + optrhs as c_uint, alpha.as_ptr() as *const c_void, - lhs.get() as AfArray, - rhs.get() as AfArray, + lhs.get(), + rhs.get(), beta.as_ptr() as *const c_void, ); HANDLE_ERROR(AfError::from(err_val)); + output.set(out); } - output.set(out); } /// Matrix multiple of two Arrays @@ -157,23 +158,22 @@ pub fn gemm( /// # Return Values /// /// The result Array of matrix multiplication -#[allow(unused_mut)] pub fn matmul(lhs: &Array, rhs: &Array, optlhs: MatProp, optrhs: MatProp) -> Array where T: HasAfEnum + FloatingPoint, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_matmul( - &mut temp as MutAfArray, - lhs.get() as AfArray, - rhs.get() as AfArray, - to_u32(optlhs) as c_uint, - to_u32(optrhs) as c_uint, + &mut temp as *mut af_array, + lhs.get(), + rhs.get(), + optlhs as c_uint, + optrhs as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Calculate the dot product of vectors. @@ -190,23 +190,22 @@ where /// # Return Values /// /// The result of dot product. -#[allow(unused_mut)] pub fn dot(lhs: &Array, rhs: &Array, optlhs: MatProp, optrhs: MatProp) -> Array where T: HasAfEnum + FloatingPoint, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_dot( - &mut temp as MutAfArray, - lhs.get() as AfArray, - rhs.get() as AfArray, - to_u32(optlhs) as c_uint, - to_u32(optrhs) as c_uint, + &mut temp as *mut af_array, + lhs.get(), + rhs.get(), + optlhs as c_uint, + optrhs as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Transpose of a matrix. @@ -220,18 +219,13 @@ where /// # Return Values /// /// Transposed Array. -#[allow(unused_mut)] pub fn transpose(arr: &Array, conjugate: bool) -> Array { - let mut temp: i64 = 0; unsafe { - let err_val = af_transpose( - &mut temp as MutAfArray, - arr.get() as AfArray, - conjugate as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_transpose(&mut temp as *mut af_array, arr.get(), conjugate); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Inplace transpose of a matrix. @@ -241,10 +235,9 @@ pub fn transpose(arr: &Array, conjugate: bool) -> Array { /// - `arr` is the input Array that has to be transposed /// - `conjugate` is a boolean that indicates if the transpose operation needs to be a conjugate /// transpose -#[allow(unused_mut)] pub fn transpose_inplace(arr: &mut Array, conjugate: bool) { unsafe { - let err_val = af_transpose_inplace(arr.get() as AfArray, conjugate as c_int); + let err_val = af_transpose_inplace(arr.get(), conjugate); HANDLE_ERROR(AfError::from(err_val)); } } diff --git a/src/arith/mod.rs b/src/core/arith.rs similarity index 72% rename from src/arith/mod.rs rename to src/core/arith.rs index 0dfe9149e..4d6e76539 100644 --- a/src/arith/mod.rs +++ b/src/core/arith.rs @@ -1,98 +1,101 @@ -extern crate libc; -extern crate num; - -use self::libc::c_int; -use self::num::Complex; -use crate::array::Array; -use crate::data::{constant, tile, ConstGenerator}; -use crate::defines::AfError; -use crate::dim4::Dim4; -use crate::error::HANDLE_ERROR; -use crate::num::Zero; -use crate::util::{AfArray, HasAfEnum, ImplicitPromote, MutAfArray}; +use super::array::Array; +use super::data::{constant, tile, ConstGenerator}; +use super::defines::AfError; +use super::dim4::Dim4; +use super::error::HANDLE_ERROR; +use super::util::{af_array, HasAfEnum, ImplicitPromote}; +use num::Zero; + +use libc::c_int; +use num::Complex; use std::ops::Neg; use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Rem, Shl, Shr, Sub}; -#[allow(dead_code)] extern "C" { - fn af_add(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_sub(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_mul(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_div(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - - fn af_lt(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_gt(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_le(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_ge(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_eq(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_or(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - - fn af_neq(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_and(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_rem(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_mod(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - - fn af_bitand(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_bitor(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_bitxor(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_bitshiftl(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - 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; - fn af_arg(out: MutAfArray, arr: AfArray) -> c_int; - fn af_sign(out: MutAfArray, arr: AfArray) -> c_int; - fn af_ceil(out: MutAfArray, arr: AfArray) -> c_int; - fn af_round(out: MutAfArray, arr: AfArray) -> c_int; - fn af_trunc(out: MutAfArray, arr: AfArray) -> c_int; - fn af_floor(out: MutAfArray, arr: AfArray) -> c_int; - - fn af_hypot(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - - fn af_sin(out: MutAfArray, arr: AfArray) -> c_int; - fn af_cos(out: MutAfArray, arr: AfArray) -> c_int; - fn af_tan(out: MutAfArray, arr: AfArray) -> c_int; - fn af_asin(out: MutAfArray, arr: AfArray) -> c_int; - fn af_acos(out: MutAfArray, arr: AfArray) -> c_int; - fn af_atan(out: MutAfArray, arr: AfArray) -> c_int; - - fn af_atan2(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_cplx2(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_root(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - fn af_pow(out: MutAfArray, lhs: AfArray, rhs: AfArray, batch: c_int) -> c_int; - - fn af_cplx(out: MutAfArray, arr: AfArray) -> c_int; - fn af_real(out: MutAfArray, arr: AfArray) -> c_int; - fn af_imag(out: MutAfArray, arr: AfArray) -> c_int; - fn af_conjg(out: MutAfArray, arr: AfArray) -> c_int; - fn af_sinh(out: MutAfArray, arr: AfArray) -> c_int; - fn af_cosh(out: MutAfArray, arr: AfArray) -> c_int; - fn af_tanh(out: MutAfArray, arr: AfArray) -> c_int; - fn af_asinh(out: MutAfArray, arr: AfArray) -> c_int; - fn af_acosh(out: MutAfArray, arr: AfArray) -> c_int; - fn af_atanh(out: MutAfArray, arr: AfArray) -> c_int; - fn af_pow2(out: MutAfArray, arr: AfArray) -> c_int; - fn af_exp(out: MutAfArray, arr: AfArray) -> c_int; - fn af_sigmoid(out: MutAfArray, arr: AfArray) -> c_int; - fn af_expm1(out: MutAfArray, arr: AfArray) -> c_int; - fn af_erf(out: MutAfArray, arr: AfArray) -> c_int; - fn af_erfc(out: MutAfArray, arr: AfArray) -> c_int; - fn af_log(out: MutAfArray, arr: AfArray) -> c_int; - fn af_log1p(out: MutAfArray, arr: AfArray) -> c_int; - fn af_log10(out: MutAfArray, arr: AfArray) -> c_int; - fn af_log2(out: MutAfArray, arr: AfArray) -> c_int; - fn af_sqrt(out: MutAfArray, arr: AfArray) -> c_int; - fn af_rsqrt(out: MutAfArray, arr: AfArray) -> c_int; - fn af_cbrt(out: MutAfArray, arr: AfArray) -> c_int; - fn af_factorial(out: MutAfArray, arr: AfArray) -> c_int; - fn af_tgamma(out: MutAfArray, arr: AfArray) -> c_int; - fn af_lgamma(out: MutAfArray, arr: AfArray) -> c_int; - fn af_iszero(out: MutAfArray, arr: AfArray) -> c_int; - fn af_isinf(out: MutAfArray, arr: AfArray) -> c_int; - fn af_isnan(out: MutAfArray, arr: AfArray) -> c_int; + fn af_add(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_sub(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_mul(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_div(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + + fn af_lt(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_gt(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_le(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_ge(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_eq(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_or(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + + fn af_neq(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_and(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_rem(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_mod(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + + fn af_bitand(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_bitor(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_bitxor(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_bitshiftl(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_bitshiftr(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_minof(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_maxof(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_clamp( + out: *mut af_array, + inp: af_array, + lo: af_array, + hi: af_array, + batch: bool, + ) -> c_int; + + fn af_not(out: *mut af_array, arr: af_array) -> c_int; + fn af_abs(out: *mut af_array, arr: af_array) -> c_int; + fn af_arg(out: *mut af_array, arr: af_array) -> c_int; + fn af_sign(out: *mut af_array, arr: af_array) -> c_int; + fn af_ceil(out: *mut af_array, arr: af_array) -> c_int; + fn af_round(out: *mut af_array, arr: af_array) -> c_int; + fn af_trunc(out: *mut af_array, arr: af_array) -> c_int; + fn af_floor(out: *mut af_array, arr: af_array) -> c_int; + + fn af_hypot(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + + fn af_sin(out: *mut af_array, arr: af_array) -> c_int; + fn af_cos(out: *mut af_array, arr: af_array) -> c_int; + fn af_tan(out: *mut af_array, arr: af_array) -> c_int; + fn af_asin(out: *mut af_array, arr: af_array) -> c_int; + fn af_acos(out: *mut af_array, arr: af_array) -> c_int; + fn af_atan(out: *mut af_array, arr: af_array) -> c_int; + + fn af_atan2(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_cplx2(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_root(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + fn af_pow(out: *mut af_array, lhs: af_array, rhs: af_array, batch: bool) -> c_int; + + fn af_cplx(out: *mut af_array, arr: af_array) -> c_int; + fn af_real(out: *mut af_array, arr: af_array) -> c_int; + fn af_imag(out: *mut af_array, arr: af_array) -> c_int; + fn af_conjg(out: *mut af_array, arr: af_array) -> c_int; + fn af_sinh(out: *mut af_array, arr: af_array) -> c_int; + fn af_cosh(out: *mut af_array, arr: af_array) -> c_int; + fn af_tanh(out: *mut af_array, arr: af_array) -> c_int; + fn af_asinh(out: *mut af_array, arr: af_array) -> c_int; + fn af_acosh(out: *mut af_array, arr: af_array) -> c_int; + fn af_atanh(out: *mut af_array, arr: af_array) -> c_int; + fn af_pow2(out: *mut af_array, arr: af_array) -> c_int; + fn af_exp(out: *mut af_array, arr: af_array) -> c_int; + fn af_sigmoid(out: *mut af_array, arr: af_array) -> c_int; + fn af_expm1(out: *mut af_array, arr: af_array) -> c_int; + fn af_erf(out: *mut af_array, arr: af_array) -> c_int; + fn af_erfc(out: *mut af_array, arr: af_array) -> c_int; + fn af_log(out: *mut af_array, arr: af_array) -> c_int; + fn af_log1p(out: *mut af_array, arr: af_array) -> c_int; + fn af_log10(out: *mut af_array, arr: af_array) -> c_int; + fn af_log2(out: *mut af_array, arr: af_array) -> c_int; + fn af_sqrt(out: *mut af_array, arr: af_array) -> c_int; + fn af_rsqrt(out: *mut af_array, arr: af_array) -> c_int; + fn af_cbrt(out: *mut af_array, arr: af_array) -> c_int; + fn af_factorial(out: *mut af_array, arr: af_array) -> c_int; + fn af_tgamma(out: *mut af_array, arr: af_array) -> c_int; + fn af_lgamma(out: *mut af_array, arr: af_array) -> c_int; + fn af_iszero(out: *mut af_array, arr: af_array) -> c_int; + fn af_isinf(out: *mut af_array, arr: af_array) -> c_int; + fn af_isnan(out: *mut af_array, arr: af_array) -> c_int; } /// Enables use of `!` on objects of type [Array](./struct.Array.html) @@ -103,12 +106,12 @@ where type Output = Array; fn not(self) -> Self::Output { - let mut temp: i64 = 0; unsafe { - let err_val = af_not(&mut temp as MutAfArray, self.get() as AfArray); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_not(&mut temp as *mut af_array, self.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } } @@ -117,15 +120,14 @@ macro_rules! unary_func { #[doc=$doc_str] /// /// This is an element wise unary operation. - #[allow(unused_mut)] pub fn $fn_name(input: &Array) -> Array< T::$out_type > where T::$out_type: HasAfEnum { - let mut temp: i64 = 0; unsafe { - let err_val = $ffi_fn(&mut temp as MutAfArray, input.get() as AfArray); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = $ffi_fn(&mut temp as *mut af_array, input.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } ) } @@ -251,14 +253,13 @@ macro_rules! unary_boolean_func { #[doc=$doc_str] /// /// This is an element wise unary operation. - #[allow(unused_mut)] pub fn $fn_name(input: &Array) -> Array { - let mut temp: i64 = 0; unsafe { - let err_val = $ffi_fn(&mut temp as MutAfArray, input.get() as AfArray); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = $ffi_fn(&mut temp as *mut af_array, input.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } ) } @@ -272,24 +273,31 @@ macro_rules! binary_func { #[doc=$doc_str] /// /// This is an element wise binary operation. - #[allow(unused_mut)] + /// + /// # Important Notes + /// + /// - If shape/dimensions of `lhs` and `rhs` are same, the value of `batch` parameter + /// has no effect. + /// + /// - If shape/dimensions of `lhs` and `rhs` are different, the value of `batch` has + /// to be set to `true`. In this case, the shapes of `lhs` and `rhs` have to satisfy the + /// following criteria: + /// - Same number of elements in `lhs` and `rhs` along a given dimension/axis + /// - Only one element in `lhs` or `rhs` along a given dimension/axis pub fn $fn_name(lhs: &Array, rhs: &Array, batch: bool) -> Array where A: HasAfEnum + ImplicitPromote, B: HasAfEnum + ImplicitPromote, >::Output: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = $ffi_fn( - &mut temp as MutAfArray, - lhs.get() as AfArray, - rhs.get() as AfArray, - batch as c_int, + &mut temp as *mut af_array, lhs.get(), rhs.get(), batch, ); HANDLE_ERROR(AfError::from(err_val)); + Into::>::into(temp) } - Into::>::into(temp) } }; } @@ -410,17 +418,14 @@ macro_rules! overloaded_binary_func { B: HasAfEnum + ImplicitPromote, >::Output: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = $ffi_name( - &mut temp as MutAfArray, - lhs.get() as AfArray, - rhs.get() as AfArray, - batch as c_int, + &mut temp as *mut af_array, lhs.get(), rhs.get(), batch, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } #[doc=$doc_str] @@ -440,9 +445,18 @@ macro_rules! overloaded_binary_func { /// /// An Array with results of the binary operation. /// - ///# Note + ///# Important Notes + /// + /// - If shape/dimensions of `arg1` and `arg2` are same, the value of `batch` parameter + /// has no effect. /// - /// The trait `Convertable` essentially translates to a scalar native type on rust or Array. + /// - If shape/dimensions of `arg1` and `arg2` are different, the value of `batch` has + /// to be set to `true`. In this case, the shapes of `arg1` and `arg2` have to satisfy the + /// following criteria: + /// - Same number of elements in `arg1` and `arg2` along a given dimension/axis + /// - Only one element in `arg1` or `arg2` along a given dimension/axis + /// + /// - The trait `Convertable` essentially translates to a scalar native type on rust or Array. pub fn $fn_name( arg1: &T, arg2: &U, @@ -510,17 +524,14 @@ macro_rules! overloaded_compare_func { A: HasAfEnum + ImplicitPromote, B: HasAfEnum + ImplicitPromote, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = $ffi_name( - &mut temp as MutAfArray, - lhs.get() as AfArray, - rhs.get() as AfArray, - batch as c_int, + &mut temp as *mut af_array, lhs.get(), rhs.get(), batch, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } #[doc=$doc_str] @@ -539,9 +550,19 @@ macro_rules! overloaded_compare_func { ///# Return Values /// /// An Array with results of the comparison operation a.k.a an Array of boolean values. - ///# Note /// - /// The trait `Convertable` essentially translates to a scalar native type on rust or Array. + ///# Important Notes + /// + /// - If shape/dimensions of `arg1` and `arg2` are same, the value of `batch` parameter + /// has no effect. + /// + /// - If shape/dimensions of `arg1` and `arg2` are different, the value of `batch` has + /// to be set to `true`. In this case, the shapes of `arg1` and `arg2` have to satisfy the + /// following criteria: + /// - Same number of elements in `arg1` and `arg2` along a given dimension/axis + /// - Only one element in `arg1` or `arg2` along a given dimension/axis + /// + /// - The trait `Convertable` essentially translates to a scalar native type on rust or Array. pub fn $fn_name( arg1: &T, arg2: &U, @@ -612,18 +633,18 @@ where Y: HasAfEnum + ImplicitPromote, >::Output: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_clamp( - &mut temp as MutAfArray, - inp.get() as AfArray, - lo.get() as AfArray, - hi.get() as AfArray, - batch as c_int, + &mut temp as *mut af_array, + inp.get(), + lo.get(), + hi.get(), + batch, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Clamp the values of Array @@ -641,9 +662,18 @@ where /// /// An Array with results of the binary operation. /// -/// # Note +/// # Important Notes +/// +/// - If shape/dimensions of `arg1` and `arg2` are same, the value of `batch` parameter +/// has no effect. +/// +/// - If shape/dimensions of `arg1` and `arg2` are different, the value of `batch` has +/// to be set to `true`. In this case, the shapes of `arg1` and `arg2` have to satisfy the +/// following criteria: +/// - Same number of elements in `arg1` and `arg2` along a given dimension/axis +/// - Only one element in `arg1` or `arg2` along a given dimension/axis /// -/// The trait `Convertable` essentially translates to a scalar native type on rust or Array. +/// - The trait `Convertable` essentially translates to a scalar native type on rust or Array. pub fn clamp( input: &Array, arg1: &C, @@ -828,9 +858,7 @@ arith_func!(BitXor, bitxor, bitxor); mod op_assign { use super::*; - use crate::array::Array; - use crate::index::{assign_gen, Indexer}; - use crate::seq::Seq; + use crate::core::{assign_gen, Array, Indexer, Seq}; use std::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign}; use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign}; diff --git a/src/array.rs b/src/core/array.rs similarity index 63% rename from src/array.rs rename to src/core/array.rs index 5a1043a6c..3ccdda570 100644 --- a/src/array.rs +++ b/src/core/array.rs @@ -1,10 +1,9 @@ -extern crate libc; +use super::defines::{AfError, Backend, DType}; +use super::dim4::Dim4; +use super::error::HANDLE_ERROR; +use super::util::{af_array, dim_t, void_ptr, HasAfEnum}; -use self::libc::{c_char, c_int, c_longlong, c_uint, c_void}; -use crate::defines::{AfError, Backend, DType}; -use crate::dim4::Dim4; -use crate::error::HANDLE_ERROR; -use crate::util::{AfArray, DimT, HasAfEnum, MutAfArray, MutVoidPtr}; +use libc::{c_char, c_int, c_longlong, c_uint, c_void}; use std::ffi::CString; use std::marker::PhantomData; @@ -13,119 +12,132 @@ use std::marker::PhantomData; // af_write_array // af_get_data_ref_count -#[allow(dead_code)] extern "C" { fn af_create_array( - out: MutAfArray, + out: *mut af_array, data: *const c_void, ndims: c_uint, - dims: *const DimT, + dims: *const dim_t, aftype: c_uint, ) -> c_int; - fn af_create_handle(out: MutAfArray, ndims: c_uint, dims: *const DimT, aftype: c_uint) - -> c_int; + fn af_create_handle( + out: *mut af_array, + ndims: c_uint, + dims: *const dim_t, + aftype: c_uint, + ) -> c_int; - fn af_get_elements(out: MutAfArray, arr: AfArray) -> c_int; + fn af_device_array( + out: *mut af_array, + data: *mut c_void, + ndims: c_uint, + dims: *const dim_t, + aftype: c_uint, + ) -> c_int; + + fn af_get_elements(out: *mut dim_t, arr: af_array) -> c_int; - fn af_get_type(out: *mut c_uint, arr: AfArray) -> c_int; + fn af_get_type(out: *mut c_uint, arr: af_array) -> c_int; fn af_get_dims( dim0: *mut c_longlong, dim1: *mut c_longlong, dim2: *mut c_longlong, dim3: *mut c_longlong, - arr: AfArray, + arr: af_array, ) -> c_int; - fn af_get_numdims(result: *mut c_uint, arr: AfArray) -> c_int; + fn af_get_numdims(result: *mut c_uint, arr: af_array) -> c_int; + + fn af_is_empty(result: *mut bool, arr: af_array) -> c_int; + + fn af_is_scalar(result: *mut bool, arr: af_array) -> c_int; - fn af_is_empty(result: *mut c_int, arr: AfArray) -> c_int; + fn af_is_row(result: *mut bool, arr: af_array) -> c_int; - fn af_is_scalar(result: *mut c_int, arr: AfArray) -> c_int; + fn af_is_column(result: *mut bool, arr: af_array) -> c_int; - fn af_is_row(result: *mut c_int, arr: AfArray) -> c_int; + fn af_is_vector(result: *mut bool, arr: af_array) -> c_int; - fn af_is_column(result: *mut c_int, arr: AfArray) -> c_int; + fn af_is_complex(result: *mut bool, arr: af_array) -> c_int; - fn af_is_vector(result: *mut c_int, arr: AfArray) -> c_int; + fn af_is_real(result: *mut bool, arr: af_array) -> c_int; - fn af_is_complex(result: *mut c_int, arr: AfArray) -> c_int; + fn af_is_double(result: *mut bool, arr: af_array) -> c_int; - fn af_is_real(result: *mut c_int, arr: AfArray) -> c_int; + fn af_is_single(result: *mut bool, arr: af_array) -> c_int; - fn af_is_double(result: *mut c_int, arr: AfArray) -> c_int; + fn af_is_half(result: *mut bool, arr: af_array) -> c_int; - fn af_is_single(result: *mut c_int, arr: AfArray) -> c_int; + fn af_is_integer(result: *mut bool, arr: af_array) -> c_int; - fn af_is_realfloating(result: *mut c_int, arr: AfArray) -> c_int; + fn af_is_bool(result: *mut bool, arr: af_array) -> c_int; - fn af_is_floating(result: *mut c_int, arr: AfArray) -> c_int; + fn af_is_realfloating(result: *mut bool, arr: af_array) -> c_int; - fn af_is_integer(result: *mut c_int, arr: AfArray) -> c_int; + fn af_is_floating(result: *mut bool, arr: af_array) -> c_int; - fn af_is_bool(result: *mut c_int, arr: AfArray) -> c_int; + fn af_is_linear(result: *mut bool, arr: af_array) -> c_int; - fn af_get_data_ptr(data: *mut c_void, arr: AfArray) -> c_int; + fn af_is_owner(result: *mut bool, arr: af_array) -> c_int; - fn af_eval(arr: AfArray) -> c_int; + fn af_is_sparse(result: *mut bool, arr: af_array) -> c_int; - fn af_eval_multiple(num: c_int, arrays: *const AfArray) -> c_int; + fn af_get_data_ptr(data: *mut c_void, arr: af_array) -> c_int; + + fn af_eval(arr: af_array) -> c_int; + + fn af_eval_multiple(num: c_int, arrays: *const af_array) -> 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_retain_array(out: *mut af_array, arr: af_array) -> c_int; - fn af_copy_array(out: MutAfArray, arr: AfArray) -> c_int; + fn af_copy_array(out: *mut af_array, arr: af_array) -> c_int; - fn af_release_array(arr: AfArray) -> c_int; + fn af_release_array(arr: af_array) -> c_int; - fn af_print_array(arr: AfArray) -> c_int; + //fn af_print_array(arr: af_array) -> c_int; - fn af_print_array_gen(exp: *const c_char, arr: AfArray, precision: c_int) -> c_int; + fn af_print_array_gen(exp: *const c_char, arr: af_array, precision: c_int) -> c_int; - fn af_cast(out: MutAfArray, arr: AfArray, aftype: c_uint) -> c_int; + fn af_cast(out: *mut af_array, arr: af_array, aftype: c_uint) -> c_int; - fn af_get_backend_id(backend: *mut c_uint, input: AfArray) -> c_int; + fn af_get_backend_id(backend: *mut c_uint, input: af_array) -> c_int; - fn af_get_device_id(device: *mut c_int, input: AfArray) -> c_int; + fn af_get_device_id(device: *mut c_int, input: af_array) -> c_int; fn af_create_strided_array( - arr: MutAfArray, + arr: *mut af_array, data: *const c_void, - offset: DimT, + offset: dim_t, ndims: c_uint, - dims: *const DimT, - strides: *const DimT, + dims: *const dim_t, + strides: *const dim_t, aftype: c_uint, stype: c_uint, ) -> c_int; fn af_get_strides( - s0: *mut DimT, - s1: *mut DimT, - s2: *mut DimT, - s3: *mut DimT, - arr: AfArray, + s0: *mut dim_t, + s1: *mut dim_t, + s2: *mut dim_t, + s3: *mut dim_t, + arr: af_array, ) -> 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; + fn af_get_offset(offset: *mut dim_t, arr: af_array) -> c_int; - fn af_is_sparse(result: *mut c_int, arr: AfArray) -> c_int; + fn af_lock_array(arr: af_array) -> c_int; - fn af_lock_array(arr: AfArray) -> c_int; + fn af_unlock_array(arr: af_array) -> c_int; - fn af_unlock_array(arr: AfArray) -> c_int; + fn af_get_device_ptr(ptr: *mut void_ptr, arr: af_array) -> c_int; - fn af_get_device_ptr(ptr: MutVoidPtr, arr: AfArray) -> c_int; - - fn af_get_allocated_bytes(result: *mut usize, arr: AfArray) -> c_int; + fn af_get_allocated_bytes(result: *mut usize, arr: af_array) -> c_int; } /// A multidimensional data container @@ -138,7 +150,7 @@ extern "C" { /// carry out element wise operations. For example, `*` does multiplication of /// elements at corresponding locations in two different Arrays. pub struct Array { - handle: i64, + handle: af_array, /// The phantom marker denotes the /// allocation of data on compute device _marker: PhantomData, @@ -149,10 +161,10 @@ macro_rules! is_func { #[doc=$doc_str] pub fn $fn_name(&self) -> bool { unsafe { - let mut ret_val: i32 = 0; - let err_val = $ffi_fn(&mut ret_val as *mut c_int, self.handle as AfArray); + let mut ret_val: bool = false; + let err_val = $ffi_fn(&mut ret_val as *mut bool, self.handle); HANDLE_ERROR(AfError::from(err_val)); - ret_val>0 + ret_val } } ) @@ -189,35 +201,33 @@ where /// print(&hvals); /// ``` /// - #[allow(unused_mut)] pub fn new(slice: &[T], dims: Dim4) -> Self { let aftype = T::get_af_dtype(); - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_create_array( - &mut temp as MutAfArray, + &mut temp as *mut af_array, slice.as_ptr() as *const c_void, dims.ndims() as c_uint, dims.get().as_ptr() as *const c_longlong, aftype as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Constructs a new Array object from strided data /// /// 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) -> Self { let aftype = T::get_af_dtype(); - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_create_strided_array( - &mut temp as MutAfArray, + &mut temp as *mut af_array, slice.as_ptr() as *const c_void, - offset as DimT, + offset as dim_t, dims.ndims() as c_uint, dims.get().as_ptr() as *const c_longlong, strides.get().as_ptr() as *const c_longlong, @@ -225,8 +235,8 @@ where 1 as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Constructs a new Array object of specified dimensions and type @@ -237,13 +247,12 @@ where /// use arrayfire::{Array, Dim4}; /// let garbage_vals = Array::::new_empty(Dim4::new(&[3, 1, 1, 1])); /// ``` - #[allow(unused_mut)] pub fn new_empty(dims: Dim4) -> Self { let aftype = T::get_af_dtype(); unsafe { - let mut temp: i64 = 0; + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_create_handle( - &mut temp as MutAfArray, + &mut temp as *mut af_array, dims.ndims() as c_uint, dims.get().as_ptr() as *const c_longlong, aftype as c_uint, @@ -253,6 +262,93 @@ where } } + /// Constructs a new Array object from device pointer + /// + /// The example show cases the usage using CUDA API, but usage of this function will + /// be similar in CPU and OpenCL backends also. In the case of OpenCL backend, the pointer + /// would be cl_mem. A short example of how to create an Array from device pointer is + /// shown below but for detailed set of examples, please check out the tutorial book + /// pages: + /// - [Interoperability with CUDA][1] + /// - [Interoperability with OpenCL][2] + /// + /// [1]: http://arrayfire.org/arrayfire-rust/book/cuda-interop.html + /// [2]: http://arrayfire.org/arrayfire-rust/book/opencl-interop.html + /// + /// # Examples + /// + /// An example of creating an Array device pointer using + /// [rustacuda](https://github.com/bheisler/RustaCUDA) crate. The + /// example has to be copied to a `bin` crate with following contents in Cargo.toml + /// to run successfully. Note that, all required setup for rustacuda and arrayfire crate + /// have to completed first. + /// ```text + /// [package] + /// .... + /// [dependencies] + /// rustacuda = "0.1" + /// rustacuda_derive = "0.1" + /// rustacuda_core = "0.1" + /// arrayfire = "3.7.*" + /// ``` + /// + /// ```rust,ignore + ///use arrayfire::*; + ///use rustacuda::*; + ///use rustacuda::prelude::*; + /// + ///fn main() { + /// let v: Vec<_> = (0u8 .. 100).map(f32::from).collect(); + /// + /// rustacuda::init(CudaFlags::empty()); + /// let device = Device::get_device(0).unwrap(); + /// let context = Context::create_and_push(ContextFlags::MAP_HOST | ContextFlags::SCHED_AUTO, + /// device).unwrap(); + /// // Approach 1 + /// { + /// let mut buffer = memory::DeviceBuffer::from_slice(&v).unwrap(); + /// + /// let array_dptr = Array::new_from_device_ptr( + /// buffer.as_device_ptr().as_raw_mut(), dim4!(10, 10)); + /// + /// af_print!("array_dptr", &array_dptr); + /// + /// array_dptr.lock(); // Needed to avoid free as arrayfire takes ownership + /// } + /// + /// // Approach 2 + /// { + /// let mut dptr: *mut f32 = std::ptr::null_mut(); + /// unsafe { + /// dptr = memory::cuda_malloc::(10*10).unwrap().as_raw_mut(); + /// } + /// let array_dptr = Array::new_from_device_ptr(dptr, dim4!(10, 10)); + /// // note that values might be garbage in the memory pointed out by dptr + /// // in this example as it is allocated but not initialized prior to passing + /// // along to arrayfire::Array::new* + /// + /// // After ArrayFire takes over ownership of the pointer, you can use other + /// // arrayfire functions as usual. + /// af_print!("array_dptr", &array_dptr); + /// } + ///} + /// ``` + pub fn new_from_device_ptr(dev_ptr: *mut T, dims: Dim4) -> Self { + let aftype = T::get_af_dtype(); + unsafe { + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_device_array( + &mut temp as *mut af_array, + dev_ptr as *mut c_void, + dims.ndims() as c_uint, + dims.get().as_ptr() as *const dim_t, + aftype as c_uint, + ); + HANDLE_ERROR(AfError::from(err_val)); + temp.into() + } + } + /// Returns the backend of the Array /// /// # Return Values @@ -262,7 +358,7 @@ where pub fn get_backend(&self) -> Backend { unsafe { let mut ret_val: u32 = 0; - let err_val = af_get_backend_id(&mut ret_val as *mut c_uint, self.handle as AfArray); + let err_val = af_get_backend_id(&mut ret_val as *mut c_uint, self.handle); HANDLE_ERROR(AfError::from(err_val)); match (err_val, ret_val) { (0, 1) => Backend::CPU, @@ -281,7 +377,7 @@ where pub fn get_device_id(&self) -> i32 { 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); + let err_val = af_get_device_id(&mut ret_val as *mut c_int, self.handle); HANDLE_ERROR(AfError::from(err_val)); ret_val } @@ -290,8 +386,8 @@ where /// Returns the number of elements in the Array pub fn elements(&self) -> usize { unsafe { - let mut ret_val: i64 = 0; - let err_val = af_get_elements(&mut ret_val as MutAfArray, self.handle as AfArray); + let mut ret_val: dim_t = 0; + let err_val = af_get_elements(&mut ret_val as *mut dim_t, self.handle); HANDLE_ERROR(AfError::from(err_val)); ret_val as usize } @@ -301,7 +397,7 @@ where pub fn get_type(&self) -> DType { unsafe { let mut ret_val: u32 = 0; - let err_val = af_get_type(&mut ret_val as *mut c_uint, self.handle as AfArray); + let err_val = af_get_type(&mut ret_val as *mut c_uint, self.handle); HANDLE_ERROR(AfError::from(err_val)); DType::from(ret_val) } @@ -315,11 +411,11 @@ where let mut ret2: i64 = 0; let mut ret3: i64 = 0; 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, + &mut ret0 as *mut dim_t, + &mut ret1 as *mut dim_t, + &mut ret2 as *mut dim_t, + &mut ret3 as *mut dim_t, + self.handle, ); HANDLE_ERROR(AfError::from(err_val)); Dim4::new(&[ret0 as u64, ret1 as u64, ret2 as u64, ret3 as u64]) @@ -334,11 +430,11 @@ where 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, + &mut ret0 as *mut dim_t, + &mut ret1 as *mut dim_t, + &mut ret2 as *mut dim_t, + &mut ret3 as *mut dim_t, + self.handle, ); HANDLE_ERROR(AfError::from(err_val)); Dim4::new(&[ret0 as u64, ret1 as u64, ret2 as u64, ret3 as u64]) @@ -349,7 +445,7 @@ where pub fn numdims(&self) -> u32 { unsafe { let mut ret_val: u32 = 0; - let err_val = af_get_numdims(&mut ret_val as *mut c_uint, self.handle as AfArray); + let err_val = af_get_numdims(&mut ret_val as *mut c_uint, self.handle); HANDLE_ERROR(AfError::from(err_val)); ret_val } @@ -359,19 +455,19 @@ where pub fn offset(&self) -> i64 { unsafe { let mut ret_val: i64 = 0; - let err_val = af_get_offset(&mut ret_val as *mut DimT, self.handle as AfArray); + let err_val = af_get_offset(&mut ret_val as *mut dim_t, self.handle); HANDLE_ERROR(AfError::from(err_val)); ret_val } } /// Returns the native FFI handle for Rust object `Array` - pub fn get(&self) -> i64 { + pub unsafe fn get(&self) -> af_array { self.handle } /// Returns the native FFI handle for Rust object `Array` - pub fn set(&mut self, handle: i64) { + pub fn set(&mut self, handle: af_array) { self.handle = handle; } @@ -406,7 +502,7 @@ where HANDLE_ERROR(AfError::ERR_SIZE); } unsafe { - let err_val = af_get_data_ptr(data.as_mut_ptr() as *mut c_void, self.handle as AfArray); + let err_val = af_get_data_ptr(data.as_mut_ptr() as *mut c_void, self.handle); HANDLE_ERROR(AfError::from(err_val)); } } @@ -414,7 +510,7 @@ where /// Evaluates any pending lazy expressions that represent the data in the Array object pub fn eval(&self) { unsafe { - let err_val = af_eval(self.handle as AfArray); + let err_val = af_eval(self.handle); HANDLE_ERROR(AfError::from(err_val)); } } @@ -424,8 +520,8 @@ where /// This does a deep copy of the data into a new Array pub fn copy(&self) -> Self { unsafe { - let mut temp: i64 = 0; - let err_val = af_copy_array(&mut temp as MutAfArray, self.handle as AfArray); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_copy_array(&mut temp as *mut af_array, self.handle); HANDLE_ERROR(AfError::from(err_val)); temp.into() } @@ -436,11 +532,18 @@ where 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 real (not complex) type", + is_real, + af_is_real + ); 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, @@ -451,11 +554,10 @@ where 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 + "Check if Array's numerical type is of half precision", + is_half, + af_is_half ); is_func!( "Check if Array is of integral type", @@ -463,11 +565,24 @@ where af_is_integer ); is_func!("Check if Array is of boolean type", is_bool, af_is_bool); + + is_func!( + "Check if Array is floating point real(not complex) data type", + is_realfloating, + af_is_realfloating + ); + is_func!( + "Check if Array is floating point type, either real or complex data", + is_floating, + af_is_floating + ); + is_func!( "Check if Array's memory layout is continuous and one dimensional", is_linear, af_is_linear ); + is_func!("Check if Array is a sparse matrix", is_sparse, af_is_sparse); is_func!( "Check if Array's memory is owned by it and not a view of another Array", is_owner, @@ -477,25 +592,11 @@ where /// Cast the Array data type to `target_type` pub fn cast(&self) -> Array { let trgt_type = O::get_af_dtype(); - let mut temp: i64 = 0; unsafe { - let err_val = af_cast( - &mut temp as MutAfArray, - self.handle as AfArray, - trgt_type as c_uint, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_cast(&mut temp as *mut af_array, self.handle, trgt_type as c_uint); HANDLE_ERROR(AfError::from(err_val)); - } - temp.into() - } - - /// 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 + temp.into() } } @@ -504,7 +605,7 @@ where /// 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); + let err_val = af_lock_array(self.handle); HANDLE_ERROR(AfError::from(err_val)); } } @@ -515,7 +616,7 @@ where /// memory manager. pub fn unlock(&self) { unsafe { - let err_val = af_unlock_array(self.handle as AfArray); + let err_val = af_unlock_array(self.handle); HANDLE_ERROR(AfError::from(err_val)); } } @@ -523,13 +624,11 @@ where /// 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 - } + pub unsafe fn device_ptr(&self) -> void_ptr { + let mut temp: void_ptr = std::ptr::null_mut(); + let err_val = af_get_device_ptr(&mut temp as *mut void_ptr, self.handle); + HANDLE_ERROR(AfError::from(err_val)); + temp } /// Get the size of physical allocated bytes. @@ -539,7 +638,7 @@ where pub fn get_allocated_bytes(&self) -> usize { unsafe { let mut temp: usize = 0; - let err_val = af_get_allocated_bytes(&mut temp as *mut usize, self.handle as AfArray); + let err_val = af_get_allocated_bytes(&mut temp as *mut usize, self.handle); HANDLE_ERROR(AfError::from(err_val)); temp } @@ -548,7 +647,7 @@ where /// Used for creating Array object from native /// resource id, an 64 bit integer -impl Into> for i64 { +impl Into> for af_array { fn into(self) -> Array { Array { handle: self, @@ -564,15 +663,15 @@ impl Into> for i64 { /// object. /// /// To create a deep copy use -/// [copy()](http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html#method.copy) +/// [copy()](./struct.Array.html#method.copy) impl Clone for Array where T: HasAfEnum, { fn clone(&self) -> Self { unsafe { - let mut temp: i64 = 0; - let ret_val = af_retain_array(&mut temp as MutAfArray, self.handle as AfArray); + let mut temp: af_array = std::ptr::null_mut(); + let ret_val = af_retain_array(&mut temp as *mut af_array, self.handle); match ret_val { 0 => temp.into(), _ => panic!("Weak copy of Array failed with error code: {}", ret_val), @@ -628,7 +727,7 @@ pub fn print(input: &Array) { unsafe { let err_val = af_print_array_gen( emptystring.to_bytes_with_nul().as_ptr() as *const c_char, - input.get() as AfArray, + input.get(), 4, ); HANDLE_ERROR(AfError::from(err_val)); @@ -672,7 +771,7 @@ pub fn print_gen(msg: String, input: &Array, precision: Option< unsafe { let err_val = af_print_array_gen( emptystring.to_bytes_with_nul().as_ptr() as *const c_char, - input.get() as AfArray, + input.get(), match precision { Some(p) => p, None => 4, @@ -696,7 +795,7 @@ pub fn eval_multiple(inputs: Vec<&Array>) { v.push(i.get()); } - let err_val = af_eval_multiple(v.len() as c_int, v.as_ptr() as *const AfArray); + let err_val = af_eval_multiple(v.len() as c_int, v.as_ptr() as *const af_array); HANDLE_ERROR(AfError::from(err_val)); } } diff --git a/src/backend.rs b/src/core/backend.rs similarity index 90% rename from src/backend.rs rename to src/core/backend.rs index ead475881..d6355d493 100644 --- a/src/backend.rs +++ b/src/core/backend.rs @@ -1,8 +1,7 @@ -extern crate libc; +use super::defines::{AfError, Backend}; +use super::error::HANDLE_ERROR; -use self::libc::{c_int, c_uint}; -use crate::defines::{AfError, Backend}; -use crate::error::HANDLE_ERROR; +use libc::{c_int, c_uint}; extern "C" { fn af_set_backend(bknd: u8) -> c_int; @@ -24,7 +23,6 @@ pub fn set_backend(backend: Backend) { } /// Get the available backend count -#[allow(unused_mut)] pub fn get_backend_count() -> u32 { unsafe { let mut temp: u32 = 0; @@ -35,7 +33,6 @@ pub fn get_backend_count() -> u32 { } /// Get the available backends -#[allow(unused_mut)] pub fn get_available_backends() -> Vec { unsafe { let mut temp: i32 = 0; @@ -58,7 +55,6 @@ pub fn get_available_backends() -> Vec { } /// Get current active backend -#[allow(unused_mut)] pub fn get_active_backend() -> Backend { unsafe { let mut temp: i32 = 0; diff --git a/src/data/mod.rs b/src/core/data.rs similarity index 71% rename from src/data/mod.rs rename to src/core/data.rs index 3ba58360f..9f8c3cd5d 100644 --- a/src/data/mod.rs +++ b/src/core/data.rs @@ -1,87 +1,109 @@ -extern crate libc; -extern crate num; - -use self::libc::{c_double, c_int, c_uint}; -use self::num::Complex; -use crate::array::Array; -use crate::defines::{AfError, BorderType}; -use crate::dim4::Dim4; -use crate::error::HANDLE_ERROR; -use crate::util::{AfArray, DimT, HasAfEnum, Intl, MutAfArray, Uintl}; +use super::array::Array; +use super::defines::{AfError, BorderType}; +use super::dim4::Dim4; +use super::error::HANDLE_ERROR; +use super::util::{af_array, c32, c64, dim_t, u64_t, HasAfEnum}; + +use libc::{c_double, c_int, c_uint}; use std::option::Option; use std::vec::Vec; -#[allow(dead_code)] extern "C" { fn af_constant( - out: MutAfArray, + out: *mut af_array, val: c_double, ndims: c_uint, - dims: *const DimT, - afdtype: c_int, + dims: *const dim_t, + afdtype: c_uint, ) -> c_int; fn af_constant_complex( - out: MutAfArray, + out: *mut af_array, real: c_double, imag: c_double, ndims: c_uint, - dims: *const DimT, - afdtype: c_int, + dims: *const dim_t, + afdtype: c_uint, ) -> c_int; - fn af_constant_long(out: MutAfArray, val: Intl, ndims: c_uint, dims: *const DimT) -> c_int; + fn af_constant_long(out: *mut af_array, val: dim_t, ndims: c_uint, dims: *const dim_t) + -> c_int; - fn af_constant_ulong(out: MutAfArray, val: Uintl, ndims: c_uint, dims: *const DimT) -> c_int; + fn af_constant_ulong( + out: *mut af_array, + val: u64_t, + ndims: c_uint, + dims: *const dim_t, + ) -> c_int; fn af_range( - out: MutAfArray, + out: *mut af_array, ndims: c_uint, - dims: *const DimT, - seq_dims: c_int, + dims: *const dim_t, + seq_dim: c_int, afdtype: c_uint, ) -> c_int; fn af_iota( - out: MutAfArray, + out: *mut af_array, ndims: c_uint, - dims: *const DimT, + dims: *const dim_t, t_ndims: c_uint, - tdims: *const DimT, + tdims: *const dim_t, afdtype: c_uint, ) -> c_int; - fn af_identity(out: MutAfArray, ndims: c_uint, dims: *const DimT, afdtype: c_uint) -> 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; - fn af_join(out: MutAfArray, dim: c_int, first: AfArray, second: AfArray) -> c_int; - fn af_join_many(out: MutAfArray, dim: c_int, n_arrays: c_uint, inpts: *const AfArray) -> c_int; + fn af_identity(out: *mut af_array, ndims: c_uint, dims: *const dim_t, afdtype: c_uint) + -> c_int; + fn af_diag_create(out: *mut af_array, arr: af_array, num: c_int) -> c_int; + fn af_diag_extract(out: *mut af_array, arr: af_array, num: c_int) -> c_int; + fn af_join(out: *mut af_array, dim: c_int, first: af_array, second: af_array) -> c_int; + fn af_join_many( + out: *mut af_array, + dim: c_int, + n_arrays: c_uint, + inpts: *const af_array, + ) -> c_int; - 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_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_tile( + out: *mut af_array, + arr: af_array, + x: c_uint, + y: c_uint, + z: c_uint, + w: c_uint, + ) -> c_int; + fn af_reorder( + o: *mut af_array, + a: af_array, + x: c_uint, + y: c_uint, + z: c_uint, + w: c_uint, + ) -> c_int; + fn af_shift(o: *mut af_array, a: af_array, x: c_int, y: c_int, z: c_int, w: c_int) -> c_int; + fn af_moddims(out: *mut af_array, arr: af_array, ndims: c_uint, dims: *const dim_t) -> c_int; - fn af_flat(out: MutAfArray, arr: AfArray) -> c_int; - fn af_flip(out: MutAfArray, arr: AfArray, dim: c_uint) -> c_int; - fn af_lower(out: MutAfArray, arr: AfArray, is_unit_diag: c_int) -> c_int; - fn af_upper(out: MutAfArray, arr: AfArray, is_unit_diag: c_int) -> c_int; + fn af_flat(out: *mut af_array, arr: af_array) -> c_int; + fn af_flip(out: *mut af_array, arr: af_array, dim: c_uint) -> c_int; + fn af_lower(out: *mut af_array, arr: af_array, is_unit_diag: bool) -> c_int; + fn af_upper(out: *mut af_array, arr: af_array, is_unit_diag: bool) -> c_int; - fn af_select(out: MutAfArray, cond: AfArray, a: AfArray, b: AfArray) -> c_int; - fn af_select_scalar_l(out: MutAfArray, cond: AfArray, a: c_double, b: AfArray) -> c_int; - fn af_select_scalar_r(out: MutAfArray, cond: AfArray, a: AfArray, b: c_double) -> c_int; + fn af_select(out: *mut af_array, cond: af_array, a: af_array, b: af_array) -> c_int; + fn af_select_scalar_l(out: *mut af_array, cond: af_array, a: c_double, b: af_array) -> c_int; + fn af_select_scalar_r(out: *mut af_array, cond: af_array, a: af_array, b: c_double) -> c_int; - fn af_replace(a: MutAfArray, cond: AfArray, b: AfArray) -> c_int; - fn af_replace_scalar(a: MutAfArray, cond: AfArray, b: c_double) -> c_int; + fn af_replace(a: *mut af_array, cond: af_array, b: af_array) -> c_int; + fn af_replace_scalar(a: *mut af_array, cond: af_array, b: c_double) -> c_int; fn af_pad( - out: MutAfArray, - input: AfArray, + out: *mut af_array, + input: af_array, begin_ndims: c_uint, - begin_dims: *const DimT, + begin_dims: *const dim_t, end_ndims: c_uint, - end_dims: *const DimT, - pad_fill_type: c_int, + end_dims: *const dim_t, + pad_fill_type: c_uint, ) -> c_int; } @@ -116,125 +138,119 @@ pub trait ConstGenerator { Self::OutType: HasAfEnum; } -#[allow(unused_mut)] impl ConstGenerator for i64 { type OutType = i64; fn generate(&self, dims: Dim4) -> Array { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_constant_long( - &mut temp as MutAfArray, - *self as Intl, + &mut temp as *mut af_array, + *self, dims.ndims() as c_uint, - dims.get().as_ptr() as *const DimT, + dims.get().as_ptr() as *const dim_t, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } } -#[allow(unused_mut)] impl ConstGenerator for u64 { type OutType = u64; fn generate(&self, dims: Dim4) -> Array { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_constant_ulong( - &mut temp as MutAfArray, - *self as Uintl, + &mut temp as *mut af_array, + *self, dims.ndims() as c_uint, - dims.get().as_ptr() as *const DimT, + dims.get().as_ptr() as *const dim_t, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } } -#[allow(unused_mut)] -impl ConstGenerator for Complex { - type OutType = Complex; +impl ConstGenerator for c32 { + type OutType = c32; fn generate(&self, dims: Dim4) -> Array { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_constant_complex( - &mut temp as MutAfArray, + &mut temp as *mut af_array, (*self).re as c_double, (*self).im as c_double, dims.ndims() as c_uint, - dims.get().as_ptr() as *const DimT, + dims.get().as_ptr() as *const dim_t, 1, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } } -#[allow(unused_mut)] -impl ConstGenerator for Complex { - type OutType = Complex; +impl ConstGenerator for c64 { + type OutType = c64; fn generate(&self, dims: Dim4) -> Array { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_constant_complex( - &mut temp as MutAfArray, + &mut temp as *mut af_array, (*self).re as c_double, (*self).im as c_double, dims.ndims() as c_uint, - dims.get().as_ptr() as *const DimT, + dims.get().as_ptr() as *const dim_t, 3, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } } -#[allow(unused_mut)] impl ConstGenerator for bool { type OutType = bool; fn generate(&self, dims: Dim4) -> Array { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_constant( - &mut temp as MutAfArray, + &mut temp as *mut af_array, *self as c_int as c_double, dims.ndims() as c_uint, - dims.get().as_ptr() as *const DimT, + dims.get().as_ptr() as *const dim_t, 4, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } } macro_rules! cnst { ($rust_type:ty, $ffi_type:expr) => { - #[allow(unused_mut)] impl ConstGenerator for $rust_type { type OutType = $rust_type; fn generate(&self, dims: Dim4) -> Array { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_constant( - &mut temp as MutAfArray, + &mut temp as *mut af_array, *self as c_double, dims.ndims() as c_uint, - dims.get().as_ptr() as *const DimT, + dims.get().as_ptr() as *const dim_t, $ffi_type, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } } }; @@ -254,8 +270,8 @@ cnst!(u16, 11); /// /// - i64 /// - u64 -/// - num::Complex\ -/// - num::Complex\ +/// - num::Complex\ a.k.a c32 +/// - num::Complex\ a.k.a c64 /// - f32 /// - f64 /// - i32 @@ -291,21 +307,20 @@ where /// /// # Return Values /// Array -#[allow(unused_mut)] pub fn range(dims: Dim4, seq_dim: i32) -> Array { let aftype = T::get_af_dtype(); - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_range( - &mut temp as MutAfArray, + &mut temp as *mut af_array, dims.ndims() as c_uint, - dims.get().as_ptr() as *const DimT, + dims.get().as_ptr() as *const dim_t, seq_dim as c_int, aftype as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Create a range of values @@ -320,22 +335,21 @@ pub fn range(dims: Dim4, seq_dim: i32) -> Array { /// # Return Values /// /// Array -#[allow(unused_mut)] pub fn iota(dims: Dim4, tdims: Dim4) -> Array { let aftype = T::get_af_dtype(); - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_iota( - &mut temp as MutAfArray, + &mut temp as *mut af_array, dims.ndims() as c_uint, - dims.get().as_ptr() as *const DimT, + dims.get().as_ptr() as *const dim_t, tdims.ndims() as c_uint, - tdims.get().as_ptr() as *const DimT, + tdims.get().as_ptr() as *const dim_t, aftype as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Create an identity array with 1's in diagonal @@ -347,20 +361,19 @@ pub fn iota(dims: Dim4, tdims: Dim4) -> Array { /// # Return Values /// /// Identity matrix -#[allow(unused_mut)] pub fn identity(dims: Dim4) -> Array { let aftype = T::get_af_dtype(); - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_identity( - &mut temp as MutAfArray, + &mut temp as *mut af_array, dims.ndims() as c_uint, - dims.get().as_ptr() as *const DimT, + dims.get().as_ptr() as *const dim_t, aftype as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Create a diagonal matrix @@ -374,21 +387,16 @@ pub fn identity(dims: Dim4) -> Array { /// # Return Values /// /// An Array with values as a diagonal Matrix -#[allow(unused_mut)] pub fn diag_create(input: &Array, dim: i32) -> Array where T: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_diag_create( - &mut temp as MutAfArray, - input.get() as AfArray, - dim as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_diag_create(&mut temp as *mut af_array, input.get(), dim); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Extract diagonal from a given Matrix @@ -401,21 +409,16 @@ where /// # Return Values /// /// An Array with values of the diagonal from input Array -#[allow(unused_mut)] pub fn diag_extract(input: &Array, dim: i32) -> Array where T: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_diag_extract( - &mut temp as MutAfArray, - input.get() as AfArray, - dim as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_diag_extract(&mut temp as *mut af_array, input.get(), dim); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Join two arrays @@ -429,22 +432,16 @@ where /// # Return Values /// /// Concatenated Array -#[allow(unused_mut)] pub fn join(dim: i32, first: &Array, second: &Array) -> Array where T: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_join( - &mut temp as MutAfArray, - dim as c_int, - first.get() as AfArray, - second.get() as AfArray, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_join(&mut temp as *mut af_array, dim, first.get(), second.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Join multiple arrays @@ -457,26 +454,25 @@ where /// # Return Values /// /// Concatenated Array -#[allow(unused_mut)] pub fn join_many(dim: i32, inputs: Vec<&Array>) -> Array where T: HasAfEnum, { - let mut v = Vec::new(); - for i in inputs { - v.push(i.get()); - } - let mut temp: i64 = 0; unsafe { + let mut v = Vec::new(); + for i in inputs { + v.push(i.get()); + } + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_join_many( - &mut temp as MutAfArray, - dim as c_int, - v.len() as c_uint, - v.as_ptr() as *const AfArray, + &mut temp as *mut af_array, + dim, + v.len() as u32, + v.as_ptr() as *const af_array, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Tile the input array along specified dimension @@ -493,24 +489,23 @@ where ///# Return Values /// /// Tiled input array as per the tiling dimensions provided -#[allow(unused_mut)] pub fn tile(input: &Array, dims: Dim4) -> Array where T: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_tile( - &mut temp as MutAfArray, - input.get() as AfArray, + &mut temp as *mut af_array, + input.get() as af_array, dims[0] as c_uint, dims[1] as c_uint, dims[2] as c_uint, dims[3] as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Reorder the array according to the new specified axes @@ -595,19 +590,19 @@ where } }; - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_reorder( - &mut temp as MutAfArray, - input.get() as AfArray, + &mut temp as *mut af_array, + input.get() as af_array, new_axes[0] as c_uint, new_axes[1] as c_uint, new_axes[2] as c_uint, new_axes[3] as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Reorder the array in specified order @@ -654,24 +649,23 @@ where /// print(&_a); /// print(&a_); /// ``` -#[allow(unused_mut)] pub fn shift(input: &Array, offsets: &[i32; 4]) -> Array where T: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); 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, + &mut temp as *mut af_array, + input.get(), + offsets[0], + offsets[1], + offsets[2], + offsets[3], ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Change the shape of the Array @@ -683,36 +677,34 @@ where /// /// # Return Values /// Reshaped Array -#[allow(unused_mut)] pub fn moddims(input: &Array, dims: Dim4) -> Array where T: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_moddims( - &mut temp as MutAfArray, - input.get() as AfArray, + &mut temp as *mut af_array, + input.get(), dims.ndims() as c_uint, - dims.get().as_ptr() as *const DimT, + dims.get().as_ptr() as *const dim_t, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Flatten the multidimensional Array to an 1D Array -#[allow(unused_mut)] pub fn flat(input: &Array) -> Array where T: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_flat(&mut temp as MutAfArray, input.get() as AfArray); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_flat(&mut temp as *mut af_array, input.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Flip the Array @@ -725,21 +717,16 @@ where /// # Return Values /// /// Flipped Array -#[allow(unused_mut)] pub fn flip(input: &Array, dim: u32) -> Array where T: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_flip( - &mut temp as MutAfArray, - input.get() as AfArray, - dim as c_uint, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_flip(&mut temp as *mut af_array, input.get(), dim); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Create lower triangular matrix @@ -751,21 +738,16 @@ where /// /// # Return Values /// Array -#[allow(unused_mut)] pub fn lower(input: &Array, is_unit_diag: bool) -> Array where T: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_lower( - &mut temp as MutAfArray, - input.get() as AfArray, - is_unit_diag as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_lower(&mut temp as *mut af_array, input.get(), is_unit_diag); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Create upper triangular matrix @@ -777,21 +759,16 @@ where /// /// # Return Values /// Array -#[allow(unused_mut)] pub fn upper(input: &Array, is_unit_diag: bool) -> Array where T: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_upper( - &mut temp as MutAfArray, - input.get() as AfArray, - is_unit_diag as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_upper(&mut temp as *mut af_array, input.get(), is_unit_diag); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Element wise conditional operator for Arrays @@ -814,22 +791,16 @@ where /// # Return Values /// /// An Array -#[allow(unused_mut)] pub fn select(a: &Array, cond: &Array, b: &Array) -> Array where T: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_select( - &mut temp as MutAfArray, - cond.get() as AfArray, - a.get() as AfArray, - b.get() as AfArray, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_select(&mut temp as *mut af_array, cond.get(), a.get(), b.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Element wise conditional operator for Arrays @@ -852,22 +823,16 @@ where /// # Return Values /// /// An Array -#[allow(unused_mut)] pub fn selectl(a: f64, cond: &Array, b: &Array) -> Array where T: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_select_scalar_l( - &mut temp as MutAfArray, - cond.get() as AfArray, - a as c_double, - b.get() as AfArray, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_select_scalar_l(&mut temp as *mut af_array, cond.get(), a, b.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Element wise conditional operator for Arrays @@ -890,22 +855,16 @@ where /// # Return Values /// /// An Array -#[allow(unused_mut)] pub fn selectr(a: &Array, cond: &Array, b: f64) -> Array where T: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_select_scalar_r( - &mut temp as MutAfArray, - cond.get() as AfArray, - a.get() as AfArray, - b as c_double, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_select_scalar_r(&mut temp as *mut af_array, cond.get(), a.get(), b); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Inplace replace in Array based on a condition @@ -927,17 +886,12 @@ where /// # Return Values /// /// None -#[allow(unused_mut)] pub fn replace(a: &mut Array, cond: &Array, b: &Array) where T: HasAfEnum, { unsafe { - let err_val = af_replace( - a.get() as MutAfArray, - cond.get() as AfArray, - b.get() as AfArray, - ); + let err_val = af_replace(a.get() as *mut af_array, cond.get(), b.get()); HANDLE_ERROR(AfError::from(err_val)); } } @@ -961,14 +915,12 @@ where /// # Return Values /// /// None -#[allow(unused_mut)] pub fn replace_scalar(a: &mut Array, cond: &Array, b: f64) where T: HasAfEnum, { unsafe { - let err_val = - af_replace_scalar(a.get() as MutAfArray, cond.get() as AfArray, b as c_double); + let err_val = af_replace_scalar(a.get() as *mut af_array, cond.get(), b); HANDLE_ERROR(AfError::from(err_val)); } } @@ -991,18 +943,18 @@ pub fn pad( end: Dim4, fill_type: BorderType, ) -> Array { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_pad( - &mut temp as MutAfArray, - input.get() as AfArray, + &mut temp as *mut af_array, + input.get(), begin.ndims() as c_uint, - begin.get().as_ptr() as *const DimT, + begin.get().as_ptr() as *const dim_t, end.ndims() as c_uint, - end.get().as_ptr() as *const DimT, - fill_type as c_int, + end.get().as_ptr() as *const dim_t, + fill_type as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } diff --git a/src/defines.rs b/src/core/defines.rs similarity index 98% rename from src/defines.rs rename to src/core/defines.rs index ec6de2813..6c95f1385 100644 --- a/src/defines.rs +++ b/src/core/defines.rs @@ -1,11 +1,9 @@ -extern crate num; - -use self::num::Complex; +use num::Complex; use std::fmt::Error as FmtError; use std::fmt::{Display, Formatter}; /// Error codes -#[repr(i32)] +#[repr(u32)] #[derive(Clone, Copy, Debug, PartialEq)] pub enum AfError { /// The function returned successfully @@ -249,27 +247,29 @@ pub enum ColorSpace { #[derive(Clone, Copy, Debug, PartialEq)] pub enum MatProp { /// Default (no-op) - NONE, + NONE = 0, /// Data needs to be transposed - TRANS, + TRANS = 1, /// Data needs to be conjugate transposed - CTRANS, + CTRANS = 2, /// Matrix is upper triangular - UPPER, + CONJ = 4, + /// Matrix needs to be conjugate + UPPER = 32, /// Matrix is lower triangular - LOWER, + LOWER = 64, /// Matrix diagonal has unitary values - DIAGUNIT, + DIAGUNIT = 128, /// Matrix is symmetric - SYM, + SYM = 512, /// Matrix is positive definite - POSDEF, + POSDEF = 1024, /// Matrix is orthogonal - ORTHOG, + ORTHOG = 2048, /// Matrix is tri-diagonal - TRIDIAG, + TRIDIAG = 4096, /// Matrix is block-diagonal - BLOCKDIAG, + BLOCKDIAG = 8192, } /// Norm type diff --git a/src/device/mod.rs b/src/core/device.rs similarity index 98% rename from src/device/mod.rs rename to src/core/device.rs index c62482cc7..cf2a81b42 100644 --- a/src/device/mod.rs +++ b/src/core/device.rs @@ -1,9 +1,8 @@ -extern crate libc; +use super::defines::AfError; +use super::error::HANDLE_ERROR; +use super::util::free_host; -use self::libc::{c_char, c_int, size_t}; -use crate::defines::AfError; -use crate::error::HANDLE_ERROR; -use crate::util::free_host; +use libc::{c_char, c_int, size_t}; use std::borrow::Cow; use std::ffi::{CStr, CString}; diff --git a/src/dim4.rs b/src/core/dim4.rs similarity index 100% rename from src/dim4.rs rename to src/core/dim4.rs diff --git a/src/error.rs b/src/core/error.rs similarity index 88% rename from src/error.rs rename to src/core/error.rs index e33b2c60c..d5b8b35bc 100644 --- a/src/error.rs +++ b/src/core/error.rs @@ -1,15 +1,13 @@ -extern crate libc; +use super::defines::AfError; +use super::util::{dim_t, free_host}; -use self::libc::c_char; -use crate::defines::AfError; -use crate::util::{free_host, DimT, MutDimT}; +use libc::c_char; use std::ffi::CStr; use std::ops::{Deref, DerefMut}; use std::sync::RwLock; -#[allow(dead_code)] extern "C" { - fn af_get_last_error(str: *mut *mut c_char, len: *mut DimT); + fn af_get_last_error(str: *mut *mut c_char, len: *mut dim_t); } /// Signature of error handling callback function @@ -75,7 +73,6 @@ lazy_static! { /// info(); /// } /// ``` -#[allow(unused_must_use)] #[allow(clippy::match_wild_err_arm)] pub fn register_error_handler(cb_value: Callback) { let mut gaurd = match ERROR_HANDLER_LOCK.write() { @@ -86,6 +83,7 @@ pub fn register_error_handler(cb_value: Callback) { *gaurd.deref_mut() = cb_value; } +/// Default error handler for error code returned by ArrayFire FFI calls #[allow(non_snake_case)] #[allow(clippy::match_wild_err_arm)] pub fn HANDLE_ERROR(error_code: AfError) { @@ -97,12 +95,13 @@ pub fn HANDLE_ERROR(error_code: AfError) { (*gaurd.deref()).call(error_code); } +/// Fetch last error description as String pub fn get_last_error() -> String { let mut result: String = String::from("No Last Error"); let mut tmp: *mut c_char = ::std::ptr::null_mut(); - let mut len: DimT = 0; + let mut len: dim_t = 0; unsafe { - af_get_last_error(&mut tmp, &mut len as MutDimT); + af_get_last_error(&mut tmp, &mut len as *mut dim_t); if len > 0 { result = CStr::from_ptr(tmp).to_string_lossy().into_owned(); free_host(tmp); diff --git a/src/event.rs b/src/core/event.rs similarity index 67% rename from src/event.rs rename to src/core/event.rs index e609d9b64..f60c1ddd0 100644 --- a/src/event.rs +++ b/src/core/event.rs @@ -1,31 +1,28 @@ -extern crate libc; - -use self::libc::c_int; -use crate::defines::AfError; -use crate::error::HANDLE_ERROR; -use crate::util::{AfEvent, MutAfEvent}; +use super::defines::AfError; +use super::error::HANDLE_ERROR; +use super::util::af_event; +use libc::c_int; use std::default::Default; -#[allow(dead_code)] extern "C" { - fn af_create_event(out: MutAfEvent) -> c_int; - fn af_delete_event(out: AfEvent) -> c_int; - fn af_mark_event(out: AfEvent) -> c_int; - fn af_enqueue_wait_event(out: AfEvent) -> c_int; - fn af_block_event(out: AfEvent) -> c_int; + fn af_create_event(out: *mut af_event) -> c_int; + fn af_delete_event(out: af_event) -> c_int; + fn af_mark_event(out: af_event) -> c_int; + fn af_enqueue_wait_event(out: af_event) -> c_int; + fn af_block_event(out: af_event) -> c_int; } /// RAII construct to manage ArrayFire events pub struct Event { - event_handle: i64, + event_handle: af_event, } impl Default for Event { fn default() -> Self { - let mut temp: i64 = 0; + let mut temp: af_event = std::ptr::null_mut(); unsafe { - let err_val = af_create_event(&mut temp as MutAfEvent); + let err_val = af_create_event(&mut temp as *mut af_event); HANDLE_ERROR(AfError::from(err_val)); } Self { event_handle: temp } @@ -40,7 +37,7 @@ impl Event { /// enqueued after the call to enqueue pub fn mark(&self) { unsafe { - let err_val = af_mark_event(self.event_handle as AfEvent); + let err_val = af_mark_event(self.event_handle as af_event); HANDLE_ERROR(AfError::from(err_val)); } } @@ -51,7 +48,7 @@ impl Event { /// until operations on the queue when mark was called are complete pub fn enqueue_wait(&self) { unsafe { - let err_val = af_enqueue_wait_event(self.event_handle as AfEvent); + let err_val = af_enqueue_wait_event(self.event_handle as af_event); HANDLE_ERROR(AfError::from(err_val)); } } @@ -60,7 +57,7 @@ impl Event { /// stream before mark was called are complete pub fn block(&self) { unsafe { - let err_val = af_block_event(self.event_handle as AfEvent); + let err_val = af_block_event(self.event_handle as af_event); HANDLE_ERROR(AfError::from(err_val)); } } @@ -69,7 +66,7 @@ impl Event { impl Drop for Event { fn drop(&mut self) { unsafe { - let ret_val = af_delete_event(self.event_handle as AfEvent); + let ret_val = af_delete_event(self.event_handle as af_event); match ret_val { 0 => (), _ => panic!("Failed to delete event resources: {}", ret_val), diff --git a/src/index.rs b/src/core/index.rs similarity index 82% rename from src/index.rs rename to src/core/index.rs index f5eb00dbb..f919136b5 100644 --- a/src/index.rs +++ b/src/core/index.rs @@ -1,45 +1,51 @@ -extern crate libc; - -use self::libc::{c_double, c_int, c_uint}; -use crate::array::Array; -use crate::defines::AfError; -use crate::error::HANDLE_ERROR; -use crate::seq::Seq; -use crate::util::{AfArray, AfIndex, DimT, HasAfEnum, MutAfArray, MutAfIndex}; +use super::array::Array; +use super::defines::AfError; +use super::error::HANDLE_ERROR; +use super::seq::Seq; +use super::util::{af_array, af_index_t, dim_t, HasAfEnum}; +use libc::{c_double, c_int, c_uint}; use std::default::Default; use std::marker::PhantomData; use std::mem; -#[allow(dead_code)] extern "C" { - fn af_create_indexers(indexers: MutAfIndex) -> c_int; - fn af_set_array_indexer(indexer: AfIndex, idx: AfArray, dim: DimT) -> c_int; + fn af_create_indexers(indexers: *mut af_index_t) -> c_int; + fn af_set_array_indexer(indexer: af_index_t, idx: af_array, dim: dim_t) -> c_int; fn af_set_seq_indexer( - indexer: AfIndex, + indexer: af_index_t, idx: *const SeqInternal, - dim: DimT, - is_batch: c_int, + dim: dim_t, + is_batch: bool, ) -> c_int; - fn af_release_indexers(indexers: AfIndex) -> c_int; + fn af_release_indexers(indexers: af_index_t) -> c_int; - fn af_index(out: MutAfArray, input: AfArray, ndims: c_uint, index: *const SeqInternal) - -> c_int; - fn af_lookup(out: MutAfArray, arr: AfArray, indices: AfArray, dim: c_uint) -> c_int; + fn af_index( + out: *mut af_array, + input: af_array, + ndims: c_uint, + index: *const SeqInternal, + ) -> c_int; + fn af_lookup(out: *mut af_array, arr: af_array, indices: af_array, dim: c_uint) -> c_int; fn af_assign_seq( - out: MutAfArray, - lhs: AfArray, + out: *mut af_array, + lhs: af_array, ndims: c_uint, indices: *const SeqInternal, - rhs: AfArray, + rhs: af_array, + ) -> c_int; + fn af_index_gen( + out: *mut af_array, + input: af_array, + ndims: dim_t, + indices: af_index_t, ) -> c_int; - fn af_index_gen(out: MutAfArray, input: AfArray, ndims: DimT, indices: AfIndex) -> c_int; fn af_assign_gen( - out: MutAfArray, - lhs: AfArray, - ndims: DimT, - indices: AfIndex, - rhs: AfArray, + out: *mut af_array, + lhs: af_array, + ndims: dim_t, + indices: af_index_t, + rhs: af_array, ) -> c_int; } @@ -97,7 +103,7 @@ extern "C" { /// = note: consider using a `let` binding to increase its lifetime /// ``` pub struct Indexer<'object> { - handle: i64, + handle: af_index_t, count: usize, marker: PhantomData<&'object ()>, } @@ -130,11 +136,9 @@ pub trait Indexable { /// This is used in functions [index_gen](./fn.index_gen.html) and /// [assign_gen](./fn.assign_gen.html) impl Indexable for Array { - #[allow(unused_variables)] - fn set(&self, idxr: &mut Indexer, dim: u32, is_batch: Option) { + fn set(&self, idxr: &mut Indexer, dim: u32, _is_batch: Option) { unsafe { - let err_val = - af_set_array_indexer(idxr.get() as AfIndex, self.get() as AfArray, dim as DimT); + let err_val = af_set_array_indexer(idxr.get(), self.get(), dim as dim_t); HANDLE_ERROR(AfError::from(err_val)); } } @@ -151,12 +155,12 @@ where fn set(&self, idxr: &mut Indexer, dim: u32, is_batch: Option) { unsafe { let err_val = af_set_seq_indexer( - idxr.get() as AfIndex, + idxr.get(), &SeqInternal::from_seq(self) as *const SeqInternal, - dim as DimT, + dim as dim_t, match is_batch { - Some(value) => value as c_int, - None => false as c_int, + Some(value) => value, + None => false, }, ); HANDLE_ERROR(AfError::from(err_val)); @@ -166,15 +170,15 @@ where impl<'object> Default for Indexer<'object> { fn default() -> Self { - let mut temp: i64 = 0; unsafe { - let err_val = af_create_indexers(&mut temp as MutAfIndex); + let mut temp: af_index_t = std::ptr::null_mut(); + let err_val = af_create_indexers(&mut temp as *mut af_index_t); HANDLE_ERROR(AfError::from(err_val)); - } - Self { - handle: temp, - count: 0, - marker: PhantomData, + Self { + handle: temp, + count: 0, + marker: PhantomData, + } } } } @@ -183,15 +187,15 @@ impl<'object> Indexer<'object> { /// Create a new Indexer object and set the dimension specific index objects later #[deprecated(since = "3.7.0", note = "Use Indexer::default() instead")] pub fn new() -> Self { - let mut temp: i64 = 0; unsafe { - let err_val = af_create_indexers(&mut temp as MutAfIndex); + let mut temp: af_index_t = std::ptr::null_mut(); + let err_val = af_create_indexers(&mut temp as *mut af_index_t); HANDLE_ERROR(AfError::from(err_val)); - } - Self { - handle: temp, - count: 0, - marker: PhantomData, + Self { + handle: temp, + count: 0, + marker: PhantomData, + } } } @@ -215,7 +219,7 @@ impl<'object> Indexer<'object> { } /// Get native(ArrayFire) resource handle - pub fn get(&self) -> i64 { + pub unsafe fn get(&self) -> af_index_t { self.handle } } @@ -223,7 +227,7 @@ impl<'object> Indexer<'object> { impl<'object> Drop for Indexer<'object> { fn drop(&mut self) { unsafe { - let ret_val = af_release_indexers(self.handle as AfIndex); + let ret_val = af_release_indexers(self.handle as af_index_t); match ret_val { 0 => (), _ => panic!("Failed to release indexers resource: {}", ret_val), @@ -250,19 +254,18 @@ where c_double: From, IO: HasAfEnum, { - let mut temp: i64 = 0; + let seqs: Vec = seqs.iter().map(|s| SeqInternal::from_seq(s)).collect(); unsafe { - // TODO: allocating a whole new array on the heap just for this is BAD - let seqs: Vec = seqs.iter().map(|s| SeqInternal::from_seq(s)).collect(); + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_index( - &mut temp as MutAfArray, - input.get() as AfArray, + &mut temp as *mut af_array, + input.get(), seqs.len() as u32, seqs.as_ptr() as *const SeqInternal, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Extract `row_num` row from `input` Array @@ -448,17 +451,17 @@ where T: HasAfEnum, I: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_lookup( - &mut temp as MutAfArray, - input.get() as AfArray, - indices.get() as AfArray, + &mut temp as *mut af_array, + input.get() as af_array, + indices.get() as af_array, seq_dim as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Assign(copy) content of an Array to another Array indexed by Sequences @@ -493,21 +496,21 @@ where c_double: From, I: HasAfEnum, { - let mut temp: i64 = 0; - // TODO: allocating a whole new array on the heap just for this is BAD let seqs: Vec = seqs.iter().map(|s| SeqInternal::from_seq(s)).collect(); unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_assign_seq( - &mut temp as MutAfArray, - lhs.get() as AfArray, + &mut temp as *mut af_array, + lhs.get() as af_array, seqs.len() as c_uint, seqs.as_ptr() as *const SeqInternal, - rhs.get() as AfArray, + rhs.get() as af_array, ); HANDLE_ERROR(AfError::from(err_val)); + + let modified = temp.into(); + let _old_arr = mem::replace(lhs, modified); } - let modified = temp.into(); - let _old_arr = mem::replace(lhs, modified); } /// Index an Array using any combination of Array's and Sequence's @@ -543,17 +546,17 @@ pub fn index_gen(input: &Array, indices: Indexer) -> Array where T: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_index_gen( - &mut temp as MutAfArray, - input.get() as AfArray, - indices.len() as DimT, - indices.get() as AfIndex, + &mut temp as *mut af_array, + input.get() as af_array, + indices.len() as dim_t, + indices.get() as af_index_t, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Assign an Array to another after indexing it using any combination of Array's and Sequence's @@ -592,19 +595,20 @@ pub fn assign_gen(lhs: &mut Array, indices: &Indexer, rhs: &Array) where T: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_assign_gen( - &mut temp as MutAfArray, - lhs.get() as AfArray, - indices.len() as DimT, - indices.get() as AfIndex, - rhs.get() as AfArray, + &mut temp as *mut af_array, + lhs.get() as af_array, + indices.len() as dim_t, + indices.get() as af_index_t, + rhs.get() as af_array, ); HANDLE_ERROR(AfError::from(err_val)); + + let modified = temp.into(); + let _old_arr = mem::replace(lhs, modified); } - let modified = temp.into(); - let _old_arr = mem::replace(lhs, modified); } #[repr(C)] diff --git a/src/macros.rs b/src/core/macros.rs similarity index 100% rename from src/macros.rs rename to src/core/macros.rs diff --git a/src/core/mod.rs b/src/core/mod.rs new file mode 100644 index 000000000..173764f05 --- /dev/null +++ b/src/core/mod.rs @@ -0,0 +1,51 @@ +#[cfg(feature = "arithmetic")] +pub use arith::*; +#[cfg(feature = "arithmetic")] +mod arith; + +pub use array::*; +mod array; + +pub use backend::*; +mod backend; + +#[cfg(feature = "data")] +pub use data::*; +#[cfg(feature = "data")] +mod data; + +pub use defines::*; +mod defines; + +pub use dim4::Dim4; +mod dim4; + +pub use device::*; +mod device; + +pub use error::*; +mod error; + +pub use event::*; +mod event; + +#[cfg(feature = "indexing")] +pub use index::*; +#[cfg(feature = "indexing")] +mod index; + +#[cfg(feature = "macros")] +mod macros; + +#[cfg(feature = "random")] +pub use random::*; +#[cfg(feature = "random")] +mod random; + +#[cfg(feature = "indexing")] +pub use seq::Seq; +#[cfg(feature = "indexing")] +mod seq; + +pub use util::*; +mod util; diff --git a/src/num.rs b/src/core/num.rs similarity index 100% rename from src/num.rs rename to src/core/num.rs diff --git a/src/random/mod.rs b/src/core/random.rs similarity index 62% rename from src/random/mod.rs rename to src/core/random.rs index a70b285e1..cdae248a7 100644 --- a/src/random/mod.rs +++ b/src/core/random.rs @@ -1,62 +1,61 @@ -extern crate libc; +use super::array::Array; +use super::defines::{AfError, RandomEngineType}; +use super::dim4::Dim4; +use super::error::HANDLE_ERROR; +use super::util::{af_array, af_random_engine, dim_t, u64_t, FloatingPoint, HasAfEnum}; -use self::libc::{c_int, c_uint}; -use crate::array::Array; -use crate::defines::{AfError, RandomEngineType}; -use crate::dim4::Dim4; -use crate::error::HANDLE_ERROR; -use crate::util::{DimT, MutAfArray, MutRandEngine, RandEngine, Uintl}; -use crate::util::{FloatingPoint, HasAfEnum}; +use libc::{c_int, c_uint}; -#[allow(dead_code)] extern "C" { - fn af_set_seed(seed: Uintl) -> c_int; - fn af_get_seed(seed: *mut Uintl) -> c_int; + fn af_set_seed(seed: u64_t) -> c_int; + fn af_get_seed(seed: *mut u64_t) -> c_int; - fn af_randu(out: MutAfArray, ndims: c_uint, dims: *const DimT, afdtype: c_uint) -> c_int; - fn af_randn(out: MutAfArray, ndims: c_uint, dims: *const DimT, afdtype: c_uint) -> c_int; + fn af_randu(out: *mut af_array, ndims: c_uint, dims: *const dim_t, afdtype: c_uint) -> c_int; + fn af_randn(out: *mut af_array, ndims: c_uint, dims: *const dim_t, afdtype: c_uint) -> c_int; - fn af_create_random_engine(engine: MutRandEngine, rtype: c_uint, seed: Uintl) -> c_int; - fn af_retain_random_engine(engine: MutRandEngine, inputEngine: RandEngine) -> c_int; - fn af_random_engine_set_type(engine: MutRandEngine, rtpye: c_uint) -> c_int; - fn af_random_engine_get_type(rtype: *mut c_uint, 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_create_random_engine(engine: *mut af_random_engine, rtype: c_uint, seed: u64_t) -> c_int; + fn af_retain_random_engine( + engine: *mut af_random_engine, + inputEngine: af_random_engine, + ) -> c_int; + fn af_random_engine_set_type(engine: *mut af_random_engine, rtpye: c_uint) -> c_int; + fn af_random_engine_get_type(rtype: *mut c_uint, engine: af_random_engine) -> c_int; + fn af_random_engine_set_seed(engine: *mut af_random_engine, seed: u64_t) -> c_int; + fn af_random_engine_get_seed(seed: *mut u64_t, engine: af_random_engine) -> c_int; + fn af_release_random_engine(engine: af_random_engine) -> c_int; - fn af_get_default_random_engine(engine: MutRandEngine) -> c_int; + fn af_get_default_random_engine(engine: *mut af_random_engine) -> c_int; fn af_set_default_random_engine_type(rtype: c_uint) -> c_int; fn af_random_uniform( - out: MutAfArray, + out: *mut af_array, ndims: c_uint, - dims: *const DimT, + dims: *const dim_t, aftype: c_uint, - engine: RandEngine, + engine: af_random_engine, ) -> c_int; fn af_random_normal( - out: MutAfArray, + out: *mut af_array, ndims: c_uint, - dims: *const DimT, + dims: *const dim_t, aftype: c_uint, - engine: RandEngine, + engine: af_random_engine, ) -> c_int; } /// Set seed for random number generation pub fn set_seed(seed: u64) { unsafe { - let err_val = af_set_seed(seed as Uintl); + let err_val = af_set_seed(seed as u64_t); HANDLE_ERROR(AfError::from(err_val)); } } /// Get the seed of random number generator -#[allow(unused_mut)] pub fn get_seed() -> u64 { let mut ret_val: u64 = 0; unsafe { - let err_val = af_get_seed(&mut ret_val as *mut Uintl); + let err_val = af_get_seed(&mut ret_val as *mut u64_t); HANDLE_ERROR(AfError::from(err_val)); } ret_val @@ -73,18 +72,17 @@ macro_rules! data_gen_def { ///# Return Values /// /// An Array with random values. - #[allow(unused_mut)] pub fn $fn_name(dims: Dim4) -> Array where $( T: $type_trait, )* { let aftype = T::get_af_dtype(); - let mut temp: i64 = 0; unsafe { - let err_val = $ffi_name(&mut temp as MutAfArray, - dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, + let mut temp: af_array = std::ptr::null_mut(); + let err_val = $ffi_name(&mut temp as *mut af_array, + dims.ndims() as c_uint, dims.get().as_ptr() as *const dim_t, aftype as c_uint); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } ) } @@ -107,12 +105,12 @@ data_gen_def!( /// /// This is a wrapper for ArrayFire's native random number generator engine. pub struct RandomEngine { - handle: i64, + handle: af_random_engine, } /// Used for creating RandomEngine object from native resource id -impl From for RandomEngine { - fn from(t: i64) -> Self { +impl From for RandomEngine { + fn from(t: af_random_engine) -> Self { Self { handle: t } } } @@ -129,27 +127,26 @@ impl RandomEngine { /// /// A object of type RandomEngine pub fn new(rengine: RandomEngineType, seed: Option) -> Self { - let mut temp: i64 = 0; unsafe { + let mut temp: af_random_engine = std::ptr::null_mut(); let err_val = af_create_random_engine( - &mut temp as MutRandEngine, + &mut temp as *mut af_random_engine, rengine as c_uint, match seed { Some(s) => s, None => 0, - } as Uintl, + } as u64_t, ); HANDLE_ERROR(AfError::from(err_val)); + RandomEngine { handle: temp } } - RandomEngine::from(temp) } /// Get random engine type pub fn get_type(&self) -> RandomEngineType { let mut temp: u32 = 0; unsafe { - let err_val = - af_random_engine_get_type(&mut temp as *mut c_uint, self.handle as RandEngine); + let err_val = af_random_engine_get_type(&mut temp as *mut c_uint, self.handle); HANDLE_ERROR(AfError::from(err_val)); } RandomEngineType::from(temp) @@ -158,8 +155,10 @@ impl RandomEngine { /// 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 c_uint); + let err_val = af_random_engine_set_type( + &mut self.handle as *mut af_random_engine, + engine_type as c_uint, + ); HANDLE_ERROR(AfError::from(err_val)); } } @@ -168,7 +167,7 @@ impl RandomEngine { 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); + af_random_engine_set_seed(&mut self.handle as *mut af_random_engine, seed as u64_t); HANDLE_ERROR(AfError::from(err_val)); } } @@ -177,15 +176,14 @@ impl RandomEngine { pub fn get_seed(&self) -> u64 { let mut seed: u64 = 0; unsafe { - let err_val = - af_random_engine_get_seed(&mut seed as *mut Uintl, self.handle as RandEngine); + let err_val = af_random_engine_get_seed(&mut seed as *mut u64_t, self.handle); HANDLE_ERROR(AfError::from(err_val)); } seed } /// Returns the native FFI handle for Rust object `RandomEngine` - pub fn get(&self) -> i64 { + pub unsafe fn get(&self) -> af_random_engine { self.handle } } @@ -194,9 +192,8 @@ impl RandomEngine { impl Clone for RandomEngine { fn clone(&self) -> Self { unsafe { - let mut temp: i64 = 0; - let err_val = - af_retain_random_engine(&mut temp as MutRandEngine, self.handle as RandEngine); + let mut temp: af_random_engine = std::ptr::null_mut(); + let err_val = af_retain_random_engine(&mut temp as *mut af_random_engine, self.handle); HANDLE_ERROR(AfError::from(err_val)); RandomEngine::from(temp) } @@ -207,7 +204,7 @@ impl Clone for RandomEngine { impl Drop for RandomEngine { fn drop(&mut self) { unsafe { - let err_val = af_release_random_engine(self.handle as RandEngine); + let err_val = af_release_random_engine(self.handle); HANDLE_ERROR(AfError::from(err_val)); } } @@ -215,15 +212,15 @@ impl Drop for RandomEngine { /// Get default random engine pub fn get_default_random_engine() -> RandomEngine { - let mut handle: i64 = 0; unsafe { - let mut temp: i64 = 0; - let mut err_val = af_get_default_random_engine(&mut temp as MutRandEngine); + let mut temp: af_random_engine = std::ptr::null_mut(); + let mut err_val = af_get_default_random_engine(&mut temp as *mut af_random_engine); HANDLE_ERROR(AfError::from(err_val)); - err_val = af_retain_random_engine(&mut handle as MutRandEngine, temp as RandEngine); + let mut handle: af_random_engine = std::ptr::null_mut(); + err_val = af_retain_random_engine(&mut handle as *mut af_random_engine, temp); HANDLE_ERROR(AfError::from(err_val)); + RandomEngine { handle: handle } } - RandomEngine::from(handle) } /// Set the random engine type for default random number generator @@ -253,18 +250,18 @@ where T: HasAfEnum, { let aftype = T::get_af_dtype(); - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_random_uniform( - &mut temp as MutAfArray, + &mut temp as *mut af_array, dims.ndims() as c_uint, - dims.get().as_ptr() as *const DimT, + dims.get().as_ptr() as *const dim_t, aftype as c_uint, - engine.get() as RandEngine, + engine.get(), ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Generate array of normal numbers using a random engine @@ -282,16 +279,16 @@ where T: HasAfEnum + FloatingPoint, { let aftype = T::get_af_dtype(); - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_random_normal( - &mut temp as MutAfArray, + &mut temp as *mut af_array, dims.ndims() as c_uint, - dims.get().as_ptr() as *const DimT, + dims.get().as_ptr() as *const dim_t, aftype as c_uint, - engine.get() as RandEngine, + engine.get(), ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } diff --git a/src/seq.rs b/src/core/seq.rs similarity index 96% rename from src/seq.rs rename to src/core/seq.rs index e3761bd4e..cba9f8516 100644 --- a/src/seq.rs +++ b/src/core/seq.rs @@ -1,6 +1,5 @@ -extern crate libc; +use num::{One, Zero}; -use crate::num::{One, Zero}; use std::default::Default; use std::fmt; diff --git a/src/util.rs b/src/core/util.rs similarity index 83% rename from src/util.rs rename to src/core/util.rs index 5576f4701..a5bbe7e93 100644 --- a/src/util.rs +++ b/src/core/util.rs @@ -1,45 +1,43 @@ -extern crate half; -extern crate libc; -extern crate num; - -use self::libc::{c_int, c_uint, c_void, size_t}; -use self::num::Complex; -use crate::defines::{ - AfError, ColorMap, ConvDomain, ConvMode, DType, InterpType, MatProp, MatchType, +use super::defines::{ + AfError, BinaryOp, ColorMap, ConvDomain, ConvMode, DType, InterpType, MatProp, MatchType, + RandomEngineType, SparseFormat, }; -use crate::defines::{BinaryOp, RandomEngineType, SparseFormat}; -use crate::error::HANDLE_ERROR; -use crate::num::Zero; +use super::error::HANDLE_ERROR; + +use half::f16; +use libc::{c_int, c_uint, c_void, size_t}; +use num::Complex; +use std::convert::From; use std::mem; +use std::ops::BitOr; + +/// Short type alias for Complex single precision type +pub type c32 = Complex; +/// Short type alias for Complex double precision type +pub type c64 = Complex; +/// ArrayFire FFI Type alias for libc's signed long long +pub type dim_t = libc::c_longlong; +/// ArrayFire FFI Type alias for libc's unsigned long long +pub type u64_t = libc::c_ulonglong; +/// ArrayFire FFI Type alias for libc's void* +pub type void_ptr = *mut libc::c_void; + +/// ArrayFire FFI Type alias for af_array +pub type af_array = *mut libc::c_void; +/// ArrayFire FFI Type alias for af_event +pub type af_event = *mut libc::c_void; +/// ArrayFire FFI Type alias for af_indexers_t +pub type af_index_t = *mut libc::c_void; +/// ArrayFire FFI Type alias for af_features +pub type af_features = *const libc::c_void; +/// ArrayFire FFI Type alias for af_random_engine +pub type af_random_engine = *mut libc::c_void; +/// ArrayFire FFI Type alias for af_window +pub type af_window = *mut libc::c_void; -pub type AfArray = self::libc::c_longlong; -pub type AfEvent = self::libc::c_longlong; -pub type AfIndex = self::libc::c_longlong; -pub type CellPtr = *const self::libc::c_void; -pub type Complex32 = Complex; -pub type Complex64 = Complex; -pub type DimT = self::libc::c_longlong; -pub type Feat = *const self::libc::c_void; -pub type Intl = self::libc::c_longlong; -pub type MutAfArray = *mut self::libc::c_longlong; -pub type MutAfEvent = *mut self::libc::c_longlong; -pub type MutAfIndex = *mut self::libc::c_longlong; -pub type MutDimT = *mut self::libc::c_longlong; -pub type MutDouble = *mut self::libc::c_double; -pub type MutFeat = *mut *mut self::libc::c_void; -pub type MutRandEngine = *mut self::libc::c_longlong; -pub type MutUint = *mut self::libc::c_uint; -pub type MutVoidPtr = *mut self::libc::c_ulonglong; -pub type MutWndHandle = *mut self::libc::c_ulonglong; -pub type RandEngine = self::libc::c_longlong; -pub type Uintl = self::libc::c_ulonglong; -pub type WndHandle = self::libc::c_ulonglong; - -#[allow(dead_code)] extern "C" { fn af_get_size_of(size: *mut size_t, aftype: c_uint) -> c_int; - - fn af_alloc_host(ptr: *mut *const c_void, bytes: DimT) -> c_int; + fn af_alloc_host(ptr: *mut *const c_void, bytes: dim_t) -> c_int; fn af_free_host(ptr: *mut c_void) -> c_int; } @@ -54,10 +52,9 @@ pub fn get_size(value: DType) -> usize { } /// Allocates space using Arrayfire allocator in host memory -#[allow(dead_code)] pub fn alloc_host(elements: usize, _type: DType) -> *const T { let ptr: *const T = ::std::ptr::null(); - let bytes = (elements * get_size(_type)) as DimT; + let bytes = (elements * get_size(_type)) as dim_t; unsafe { let err_val = af_alloc_host(&mut (ptr as *const c_void), bytes); HANDLE_ERROR(AfError::from(err_val)); @@ -115,22 +112,6 @@ impl From for MatchType { } } -pub fn to_u32(t: MatProp) -> u32 { - match t { - MatProp::NONE => 0, - MatProp::TRANS => 1, - MatProp::CTRANS => 2, - MatProp::UPPER => 32, - MatProp::LOWER => 64, - MatProp::DIAGUNIT => 128, - MatProp::SYM => 512, - MatProp::POSDEF => 1024, - MatProp::ORTHOG => 2048, - MatProp::TRIDIAG => 4096, - MatProp::BLOCKDIAG => 8192, - } -} - impl From for ColorMap { fn from(t: u32) -> Self { assert!(ColorMap::DEFAULT as u32 <= t && t <= ColorMap::BLUE as u32); @@ -335,13 +316,13 @@ impl HasAfEnum for u16 { DType::U16 } } -impl HasAfEnum for half::f16 { +impl HasAfEnum for f16 { type InType = Self; type BaseType = Self; type AbsOutType = Self; type ArgOutType = Self; type UnaryOutType = Self; - type ComplexOutType = Complex; + type ComplexOutType = Complex; type MeanOutType = Self; type AggregateOutType = f32; type ProductOutType = f32; @@ -462,36 +443,36 @@ macro_rules! implicit { // //LHS is Complex double -implicit!(Complex64, Complex64 => Complex64); -implicit!(Complex64, Complex32 => Complex64); -implicit!(Complex64, f64 => Complex64); -implicit!(Complex64, f32 => Complex64); -implicit!(Complex64, i64 => Complex64); -implicit!(Complex64, u64 => Complex64); -implicit!(Complex64, i32 => Complex64); -implicit!(Complex64, u32 => Complex64); -implicit!(Complex64, i16 => Complex64); -implicit!(Complex64, u16 => Complex64); -implicit!(Complex64, bool => Complex64); -implicit!(Complex64, u8 => Complex64); +implicit!(c64, c64 => c64); +implicit!(c64, c32 => c64); +implicit!(c64, f64 => c64); +implicit!(c64, f32 => c64); +implicit!(c64, i64 => c64); +implicit!(c64, u64 => c64); +implicit!(c64, i32 => c64); +implicit!(c64, u32 => c64); +implicit!(c64, i16 => c64); +implicit!(c64, u16 => c64); +implicit!(c64, bool => c64); +implicit!(c64, u8 => c64); //LHS is Complex float -implicit!(Complex32, Complex64 => Complex64); -implicit!(Complex32, Complex32 => Complex32); -implicit!(Complex32, f64 => Complex64); -implicit!(Complex32, f32 => Complex32); -implicit!(Complex32, i64 => Complex32); -implicit!(Complex32, u64 => Complex32); -implicit!(Complex32, i32 => Complex32); -implicit!(Complex32, u32 => Complex32); -implicit!(Complex32, i16 => Complex32); -implicit!(Complex32, u16 => Complex32); -implicit!(Complex32, bool => Complex32); -implicit!(Complex32, u8 => Complex32); +implicit!(c32, c64 => c64); +implicit!(c32, c32 => c32); +implicit!(c32, f64 => c64); +implicit!(c32, f32 => c32); +implicit!(c32, i64 => c32); +implicit!(c32, u64 => c32); +implicit!(c32, i32 => c32); +implicit!(c32, u32 => c32); +implicit!(c32, i16 => c32); +implicit!(c32, u16 => c32); +implicit!(c32, bool => c32); +implicit!(c32, u8 => c32); //LHS is 64-bit floating point -implicit!(f64, Complex64 => Complex64); -implicit!(f64, Complex32 => Complex64); +implicit!(f64, c64 => c64); +implicit!(f64, c32 => c64); implicit!(f64, f64 => f64); implicit!(f64, f32 => f64); implicit!(f64, i64 => f64); @@ -504,8 +485,8 @@ implicit!(f64, bool => f64); implicit!(f64, u8 => f64); //LHS is 32-bit floating point -implicit!(f32, Complex64 => Complex64); -implicit!(f32, Complex32 => Complex32); +implicit!(f32, c64 => c64); +implicit!(f32, c32 => c32); implicit!(f32, f64 => f64); implicit!(f32, f32 => f32); implicit!(f32, i64 => f32); @@ -518,8 +499,8 @@ implicit!(f32, bool => f32); implicit!(f32, u8 => f32); //LHS is 64-bit signed integer -implicit!(i64, Complex64 => Complex64); -implicit!(i64, Complex32 => Complex32); +implicit!(i64, c64 => c64); +implicit!(i64, c32 => c32); implicit!(i64, f64 => f64); implicit!(i64, f32 => f32); implicit!(i64, i64 => i64); @@ -532,8 +513,8 @@ implicit!(i64, bool => i64); implicit!(i64, u8 => i64); //LHS is 64-bit unsigned integer -implicit!(u64, Complex64 => Complex64); -implicit!(u64, Complex32 => Complex32); +implicit!(u64, c64 => c64); +implicit!(u64, c32 => c32); implicit!(u64, f64 => f64); implicit!(u64, f32 => f32); implicit!(u64, i64 => u64); @@ -546,8 +527,8 @@ implicit!(u64, bool => u64); implicit!(u64, u8 => u64); //LHS is 32-bit signed integer -implicit!(i32, Complex64 => Complex64); -implicit!(i32, Complex32 => Complex32); +implicit!(i32, c64 => c64); +implicit!(i32, c32 => c32); implicit!(i32, f64 => f64); implicit!(i32, f32 => f32); implicit!(i32, i64 => i64); @@ -560,8 +541,8 @@ implicit!(i32, bool => i32); implicit!(i32, u8 => i32); //LHS is 32-bit unsigned integer -implicit!(u32, Complex64 => Complex64); -implicit!(u32, Complex32 => Complex32); +implicit!(u32, c64 => c64); +implicit!(u32, c32 => c32); implicit!(u32, f64 => f64); implicit!(u32, f32 => f32); implicit!(u32, i64 => i64); @@ -574,8 +555,8 @@ implicit!(u32, bool => u32); implicit!(u32, u8 => u32); //LHS is 16-bit signed integer -implicit!(i16, Complex64 => Complex64); -implicit!(i16, Complex32 => Complex32); +implicit!(i16, c64 => c64); +implicit!(i16, c32 => c32); implicit!(i16, f64 => f64); implicit!(i16, f32 => f32); implicit!(i16, i64 => i64); @@ -588,8 +569,8 @@ implicit!(i16, bool => u16); implicit!(i16, u8 => u16); //LHS is 16-bit unsigned integer -implicit!(u16, Complex64 => Complex64); -implicit!(u16, Complex32 => Complex32); +implicit!(u16, c64 => c64); +implicit!(u16, c32 => c32); implicit!(u16, f64 => f64); implicit!(u16, f32 => f32); implicit!(u16, i64 => i64); @@ -602,8 +583,8 @@ implicit!(u16, bool => u16); implicit!(u16, u8 => u16); //LHS is 8-bit unsigned integer -implicit!(u8, Complex64 => Complex64); -implicit!(u8, Complex32 => Complex32); +implicit!(u8, c64 => c64); +implicit!(u8, c32 => c32); implicit!(u8, f64 => f64); implicit!(u8, f32 => f32); implicit!(u8, i64 => i64); @@ -616,8 +597,8 @@ implicit!(u8, bool => u8); implicit!(u8, u8 => u8); //LHS is bool(af::s8) -implicit!(bool, Complex64 => Complex64); -implicit!(bool, Complex32 => Complex32); +implicit!(bool, c64 => c64); +implicit!(bool, c32 => c32); implicit!(bool, f64 => f64); implicit!(bool, f32 => f32); implicit!(bool, i64 => i64); @@ -629,18 +610,6 @@ implicit!(bool, u16 => u16); implicit!(bool, bool => bool); implicit!(bool, u8 => u8); -impl Zero for Complex64 { - fn zero() -> Self { - Self { re: 0.0, im: 0.0 } - } -} - -impl Zero for Complex32 { - fn zero() -> Self { - Self { re: 0.0, im: 0.0 } - } -} - ///Trait qualifier to accept either real or complex typed data pub trait FloatingPoint { /// Use to check if trait implementor is real number @@ -683,8 +652,8 @@ impl RealFloating for f32 {} ///Trait qualifier to accept complex data(numbers) pub trait ComplexFloating {} -impl ComplexFloating for Complex64 {} -impl ComplexFloating for Complex32 {} +impl ComplexFloating for c64 {} +impl ComplexFloating for c32 {} ///Trait qualifier indicating it can hold real numbers only pub trait RealNumber {} @@ -813,3 +782,17 @@ pub trait ReduceByKeyInput: HasAfEnum {} impl ReduceByKeyInput for i32 {} impl ReduceByKeyInput for u32 {} + +impl From for MatProp { + fn from(t: u32) -> Self { + unsafe { mem::transmute(t) } + } +} + +impl BitOr for MatProp { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self { + Self::from(self as u32 | rhs as u32) + } +} diff --git a/src/graphics.rs b/src/graphics/mod.rs similarity index 73% rename from src/graphics.rs rename to src/graphics/mod.rs index ea1d38975..df164a760 100644 --- a/src/graphics.rs +++ b/src/graphics/mod.rs @@ -1,146 +1,152 @@ -extern crate libc; - -use self::libc::{c_char, c_double, c_float, c_int, c_uint}; -use crate::array::Array; -use crate::defines::AfError; -use crate::defines::{ColorMap, MarkerType}; -use crate::error::HANDLE_ERROR; -use crate::util::{AfArray, CellPtr, HasAfEnum, MutWndHandle, WndHandle}; +use super::core::{ + af_array, af_window, AfError, Array, ColorMap, HasAfEnum, MarkerType, HANDLE_ERROR, +}; + +use libc::{c_char, c_double, c_float, c_int, c_uint}; use std::ffi::CString; use std::ptr; -#[allow(dead_code)] +/// Represents a sub-view of Window +/// +/// This struct is used in conjunction with [Window](./struct.Window.html) in multiview +/// mode to render multiple targets to sub-regions of a given window. +/// +#[repr(C)] +struct af_cell { + pub row: c_int, + pub col: c_int, + pub title: *const c_char, + pub cmap: c_uint, +} + extern "C" { - fn af_create_window(out: MutWndHandle, w: c_int, h: c_int, title: *const c_char) -> c_int; + fn af_create_window(out: *mut af_window, 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_position(wnd: af_window, x: c_uint, y: c_uint) -> c_int; + fn af_set_title(wnd: af_window, title: *const c_char) -> c_int; + fn af_set_size(wnd: af_window, w: c_uint, h: c_uint) -> c_int; + fn af_set_visibility(wnd: af_window, is_visible: bool) -> c_int; fn af_set_axes_titles( - wnd: WndHandle, + wnd: af_window, xtitle: *const c_char, ytitle: *const c_char, ztitle: *const c_char, - props: CellPtr, + props: *const af_cell, ) -> c_int; fn af_set_axes_label_format( - wnd: WndHandle, + wnd: af_window, xformat: *const c_char, yformat: *const c_char, zformat: *const c_char, - props: CellPtr, + props: *const af_cell, ) -> c_int; fn af_set_axes_limits_compute( - wnd: WndHandle, - x: AfArray, - y: AfArray, - z: AfArray, - exact: c_int, - props: CellPtr, + wnd: af_window, + x: af_array, + y: af_array, + z: af_array, + exact: bool, + props: *const af_cell, ) -> c_int; fn af_set_axes_limits_2d( - wnd: WndHandle, + wnd: af_window, xmin: c_float, xmax: c_float, ymin: c_float, ymax: c_float, - exact: c_int, - props: CellPtr, + exact: bool, + props: *const af_cell, ) -> c_int; fn af_set_axes_limits_3d( - wnd: WndHandle, + wnd: af_window, xmin: c_float, xmax: c_float, ymin: c_float, ymax: c_float, zmin: c_float, zmax: c_float, - exact: c_int, - props: CellPtr, + exact: bool, + props: *const af_cell, ) -> c_int; - fn af_draw_image(wnd: WndHandle, arr: AfArray, props: CellPtr) -> c_int; + fn af_draw_image(wnd: af_window, arr: af_array, props: *const af_cell) -> c_int; fn af_draw_hist( - wnd: WndHandle, - x: AfArray, + wnd: af_window, + x: af_array, minval: c_double, maxval: c_double, - props: CellPtr, + props: *const af_cell, ) -> c_int; fn af_draw_surface( - wnd: WndHandle, - xvals: AfArray, - yvals: AfArray, - S: AfArray, - props: CellPtr, + wnd: af_window, + xvals: af_array, + yvals: af_array, + S: af_array, + props: *const af_cell, ) -> 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_plot_2d(wnd: af_window, x: af_array, y: af_array, props: *const af_cell) -> c_int; + fn af_draw_plot_3d( + wnd: af_window, + x: af_array, + y: af_array, + z: af_array, + props: *const af_cell, + ) -> c_int; + fn af_draw_plot_nd(wnd: af_window, P: af_array, props: *const af_cell) -> c_int; fn af_draw_scatter_2d( - wnd: WndHandle, - x: AfArray, - y: AfArray, - marker: c_int, - props: CellPtr, + wnd: af_window, + x: af_array, + y: af_array, + marker: c_uint, + props: *const af_cell, ) -> c_int; fn af_draw_scatter_3d( - wnd: WndHandle, - x: AfArray, - y: AfArray, - z: AfArray, - marker: c_int, - props: CellPtr, + wnd: af_window, + x: af_array, + y: af_array, + z: af_array, + marker: c_uint, + props: *const af_cell, + ) -> c_int; + fn af_draw_scatter_nd( + wnd: af_window, + P: af_array, + marker: c_uint, + props: *const af_cell, ) -> 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, + wnd: af_window, + xpnts: af_array, + ypnts: af_array, + xdirs: af_array, + ydirs: af_array, + props: *const af_cell, ) -> c_int; fn af_draw_vector_field_3d( - wnd: WndHandle, - xpnts: AfArray, - ypnts: AfArray, - xdirs: AfArray, - ydirs: AfArray, - zdirs: AfArray, - zdirs: AfArray, - props: CellPtr, + wnd: af_window, + xpnts: af_array, + ypnts: af_array, + xdirs: af_array, + ydirs: af_array, + zdirs: af_array, + zdirs: af_array, + props: *const af_cell, ) -> c_int; fn af_draw_vector_field_nd( - wnd: WndHandle, - pnts: AfArray, - dirs: AfArray, - props: CellPtr, + wnd: af_window, + pnts: af_array, + dirs: af_array, + props: *const af_cell, ) -> 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; - fn af_destroy_window(wnd: WndHandle) -> c_int; -} - -/// Represents a sub-view of Window -/// -/// This struct is used in conjunction with [Window](./struct.Window.html) in multiview -/// mode to render multiple targets to sub-regions of a given window. -/// -#[repr(C)] -pub struct Cell { - pub row: i32, - pub col: i32, - pub title: *const c_char, - pub cmap: ColorMap, + fn af_grid(wnd: af_window, rows: c_int, cols: c_int) -> c_int; + fn af_show(wnd: af_window) -> c_int; + fn af_is_window_closed(out: *mut bool, wnd: af_window) -> c_int; + fn af_destroy_window(wnd: af_window) -> c_int; } /// Used to render [Array](./struct.Array.html) objects @@ -173,24 +179,12 @@ pub struct Cell { /// ``` #[derive(Clone)] pub struct Window { - handle: u64, + handle: af_window, row: i32, col: i32, cmap: ColorMap, } -/// Used to create Window object from native(ArrayFire) resource handle -impl From for Window { - fn from(t: u64) -> Self { - Self { - handle: t, - row: -1, - col: -1, - cmap: ColorMap::DEFAULT, - } - } -} - impl Drop for Window { fn drop(&mut self) { unsafe { @@ -218,22 +212,22 @@ impl Window { /// # Return Values /// /// Window Object - #[allow(unused_mut)] #[allow(clippy::match_wild_err_arm)] pub fn new(width: i32, height: i32, title: String) -> Self { unsafe { - let mut temp: u64 = 0; let cstr_ret = CString::new(title); match cstr_ret { Ok(cstr) => { - let err_val = af_create_window( - &mut temp as MutWndHandle, - width as c_int, - height as c_int, - cstr.as_ptr(), - ); + let mut temp: af_window = std::ptr::null_mut(); + let err_val = + af_create_window(&mut temp as *mut af_window, width, height, cstr.as_ptr()); HANDLE_ERROR(AfError::from(err_val)); - Self::from(temp) + Window { + handle: temp, + row: -1, + col: -1, + cmap: ColorMap::DEFAULT, + } } Err(_) => { panic!("String creation failed while prepping params for window creation.") @@ -250,7 +244,7 @@ impl Window { /// - `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); + let err_val = af_set_position(self.handle, x, y); HANDLE_ERROR(AfError::from(err_val)); } } @@ -265,7 +259,7 @@ impl Window { let cstr_ret = CString::new(title); match cstr_ret { Ok(cstr) => { - let err_val = af_set_title(self.handle as WndHandle, cstr.as_ptr()); + let err_val = af_set_title(self.handle, cstr.as_ptr()); HANDLE_ERROR(AfError::from(err_val)); } Err(_) => HANDLE_ERROR(AfError::ERR_INTERNAL), @@ -284,7 +278,7 @@ impl Window { /// None pub fn set_visibility(&self, is_visible: bool) { unsafe { - let err_val = af_set_visibility(self.handle as WndHandle, is_visible as c_int); + let err_val = af_set_visibility(self.handle, is_visible); HANDLE_ERROR(AfError::from(err_val)); } } @@ -297,7 +291,7 @@ impl Window { /// - `h` is the target height of window pub fn set_size(&self, w: u32, h: u32) { unsafe { - let err_val = af_set_size(self.handle as WndHandle, w as c_uint, h as c_uint); + let err_val = af_set_size(self.handle, w, h); HANDLE_ERROR(AfError::from(err_val)); } } @@ -311,10 +305,10 @@ impl Window { /// Returns true if the window close is triggered by the user pub fn is_closed(&self) -> bool { unsafe { - let mut temp: i32 = 1; - let err_val = af_is_window_closed(&mut temp as *mut c_int, self.handle as WndHandle); + let mut temp: bool = true; + let err_val = af_is_window_closed(&mut temp as *mut bool, self.handle); HANDLE_ERROR(AfError::from(err_val)); - temp > 0 + temp } } @@ -326,7 +320,7 @@ impl Window { /// - `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); + let err_val = af_grid(self.handle, rows, cols); HANDLE_ERROR(AfError::from(err_val)); } } @@ -335,7 +329,7 @@ impl Window { /// frame pub fn show(&mut self) { unsafe { - let err_val = af_show(self.handle as WndHandle); + let err_val = af_show(self.handle); HANDLE_ERROR(AfError::from(err_val)); self.row = -1; self.col = -1; @@ -363,22 +357,56 @@ impl Window { /// - `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 { + let cprops = af_cell { row: self.row, col: self.col, title: ptr::null(), - cmap: self.cmap, + cmap: self.cmap as u32, }; let xstr = CString::new(xlabel).unwrap(); let ystr = CString::new(ylabel).unwrap(); let zstr = CString::new(zlabel).unwrap(); unsafe { let err_val = af_set_axes_titles( - self.handle as WndHandle, + self.handle, + xstr.as_ptr(), + ystr.as_ptr(), + zstr.as_ptr(), + &cprops as *const af_cell, + ); + HANDLE_ERROR(AfError::from(err_val)); + } + } + + /// Set chart axes labels format + /// + /// # Parameters + /// + /// - `xlabel_format` is x axis label format. format specific is identical to C's printf format + /// - `ylabel_format` is y axis label format. format specific is identical to C's printf format + /// - `zlabel_format` is z axis label format. format specific is identical to C's printf format + pub fn set_axes_label_format( + &mut self, + xlabel_format: String, + ylabel_format: String, + zlabel_format: String, + ) { + let cprops = af_cell { + row: self.row, + col: self.col, + title: ptr::null(), + cmap: self.cmap as u32, + }; + let xstr = CString::new(xlabel_format).unwrap(); + let ystr = CString::new(ylabel_format).unwrap(); + let zstr = CString::new(zlabel_format).unwrap(); + unsafe { + let err_val = af_set_axes_label_format( + self.handle, xstr.as_ptr(), ystr.as_ptr(), zstr.as_ptr(), - cprops as *const Cell as CellPtr, + &cprops as *const af_cell, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -396,22 +424,22 @@ impl Window { /// - `ylabel` is printf style format specifier for y axis /// - `zlabel` is printf style format specifier for z axis pub fn set_axes_label_formats(&mut self, xformat: String, yformat: String, zformat: String) { - let cprops = &Cell { + let cprops = af_cell { row: self.row, col: self.col, title: ptr::null(), - cmap: self.cmap, + cmap: self.cmap as u32, }; let xstr = CString::new(xformat).unwrap(); let ystr = CString::new(yformat).unwrap(); let zstr = CString::new(zformat).unwrap(); unsafe { let err_val = af_set_axes_titles( - self.handle as WndHandle, + self.handle, xstr.as_ptr(), ystr.as_ptr(), zstr.as_ptr(), - cprops as *const Cell as CellPtr, + &cprops as *const af_cell, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -440,23 +468,23 @@ impl Window { ) where T: HasAfEnum, { - let cprops = &Cell { + let cprops = af_cell { row: self.row, col: self.col, title: ptr::null(), - cmap: self.cmap, + cmap: self.cmap as u32, }; unsafe { let err_val = af_set_axes_limits_compute( - self.handle as WndHandle, - xrange.get() as AfArray, - yrange.get() as AfArray, + self.handle, + xrange.get(), + yrange.get(), match zrange { - Some(z) => z.get() as AfArray, - None => 0, + Some(z) => z.get(), + None => std::ptr::null_mut(), }, - exact as c_int, - cprops as *const Cell as CellPtr, + exact, + &cprops as *const af_cell, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -477,21 +505,21 @@ impl Window { /// 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 { + let cprops = af_cell { row: self.row, col: self.col, title: ptr::null(), - cmap: self.cmap, + cmap: self.cmap as u32, }; 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, + self.handle, + xmin, + xmax, + ymin, + ymax, + exact, + &cprops as *const af_cell, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -524,23 +552,23 @@ impl Window { zmax: f32, exact: bool, ) { - let cprops = &Cell { + let cprops = af_cell { row: self.row, col: self.col, title: ptr::null(), - cmap: self.cmap, + cmap: self.cmap as u32, }; 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, + self.handle, + xmin, + xmax, + ymin, + ymax, + zmin, + zmax, + exact, + &cprops as *const af_cell, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -562,18 +590,14 @@ impl Window { None => format!("Cell({},{}))", self.col, self.row), }; let tstr = CString::new(tstr).unwrap(); - let cprops = &Cell { + let cprops = af_cell { row: self.row, col: self.col, title: tstr.as_ptr(), - cmap: self.cmap, + cmap: self.cmap as u32, }; unsafe { - let err_val = af_draw_image( - self.handle as WndHandle, - input.get() as AfArray, - cprops as *const Cell as CellPtr, - ); + let err_val = af_draw_image(self.handle, input.get(), &cprops as *const af_cell); HANDLE_ERROR(AfError::from(err_val)); } } @@ -595,19 +619,14 @@ impl Window { None => format!("Cell({},{}))", self.col, self.row), }; let tstr = CString::new(tstr).unwrap(); - let cprops = &Cell { + let cprops = af_cell { row: self.row, col: self.col, title: tstr.as_ptr(), - cmap: self.cmap, + cmap: self.cmap as u32, }; unsafe { - 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, - ); + let err_val = af_draw_plot_2d(self.handle, x.get(), y.get(), &cprops as *const af_cell); HANDLE_ERROR(AfError::from(err_val)); } } @@ -630,19 +649,19 @@ impl Window { None => format!("Cell({},{}))", self.col, self.row), }; let tstr = CString::new(tstr).unwrap(); - let cprops = &Cell { + let cprops = af_cell { row: self.row, col: self.col, title: tstr.as_ptr(), - cmap: self.cmap, + cmap: self.cmap as u32, }; 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, + self.handle, + x.get(), + y.get(), + z.get(), + &cprops as *const af_cell, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -664,18 +683,14 @@ impl Window { None => format!("Cell({},{}))", self.col, self.row), }; let tstr = CString::new(tstr).unwrap(); - let cprops = &Cell { + let cprops = af_cell { row: self.row, col: self.col, title: tstr.as_ptr(), - cmap: self.cmap, + cmap: self.cmap as u32, }; unsafe { - let err_val = af_draw_plot_nd( - self.handle as WndHandle, - points.get() as AfArray, - cprops as *const Cell as CellPtr, - ); + let err_val = af_draw_plot_nd(self.handle, points.get(), &cprops as *const af_cell); HANDLE_ERROR(AfError::from(err_val)); } } @@ -698,19 +713,19 @@ impl Window { None => format!("Cell({},{}))", self.col, self.row), }; let tstr = CString::new(tstr).unwrap(); - let cprops = &Cell { + let cprops = af_cell { row: self.row, col: self.col, title: tstr.as_ptr(), - cmap: self.cmap, + cmap: self.cmap as u32, }; unsafe { let err_val = af_draw_hist( - self.handle as WndHandle, - hst.get() as AfArray, - minval as c_double, - maxval as c_double, - cprops as *const Cell as CellPtr, + self.handle, + hst.get(), + minval, + maxval, + &cprops as *const af_cell, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -739,19 +754,19 @@ impl Window { None => format!("Cell({},{}))", self.col, self.row), }; let tstr = CString::new(tstr).unwrap(); - let cprops = &Cell { + let cprops = af_cell { row: self.row, col: self.col, title: tstr.as_ptr(), - cmap: self.cmap, + cmap: self.cmap as u32, }; unsafe { let err_val = af_draw_surface( - self.handle as WndHandle, - xvals.get() as AfArray, - yvals.get() as AfArray, - zvals.get() as AfArray, - cprops as *const Cell as CellPtr, + self.handle, + xvals.get(), + yvals.get(), + zvals.get(), + &cprops as *const af_cell, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -780,19 +795,19 @@ impl Window { None => format!("Cell({},{}))", self.col, self.row), }; let tstr = CString::new(tstr).unwrap(); - let cprops = &Cell { + let cprops = af_cell { row: self.row, col: self.col, title: tstr.as_ptr(), - cmap: self.cmap, + cmap: self.cmap as u32, }; unsafe { 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, + self.handle, + xvals.get(), + yvals.get(), + marker as c_uint, + &cprops as *const af_cell, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -823,20 +838,20 @@ impl Window { None => format!("Cell({},{}))", self.col, self.row), }; let tstr = CString::new(tstr).unwrap(); - let cprops = &Cell { + let cprops = af_cell { row: self.row, col: self.col, title: tstr.as_ptr(), - cmap: self.cmap, + cmap: self.cmap as u32, }; 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, + self.handle, + xvals.get(), + yvals.get(), + zvals.get(), + marker as c_uint, + &cprops as *const af_cell, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -859,18 +874,18 @@ impl Window { None => format!("Cell({},{}))", self.col, self.row), }; let tstr = CString::new(tstr).unwrap(); - let cprops = &Cell { + let cprops = af_cell { row: self.row, col: self.col, title: tstr.as_ptr(), - cmap: self.cmap, + cmap: self.cmap as u32, }; 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, + self.handle, + vals.get(), + marker as c_uint, + &cprops as *const af_cell, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -901,20 +916,20 @@ impl Window { None => format!("Cell({},{}))", self.col, self.row), }; let tstr = CString::new(tstr).unwrap(); - let cprops = &Cell { + let cprops = af_cell { row: self.row, col: self.col, title: tstr.as_ptr(), - cmap: self.cmap, + cmap: self.cmap as u32, }; unsafe { 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, + self.handle, + xpnts.get(), + ypnts.get(), + xdirs.get(), + ydirs.get(), + &cprops as *const af_cell, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -950,22 +965,22 @@ impl Window { None => format!("Cell({},{}))", self.col, self.row), }; let tstr = CString::new(tstr).unwrap(); - let cprops = &Cell { + let cprops = af_cell { row: self.row, col: self.col, title: tstr.as_ptr(), - cmap: self.cmap, + cmap: self.cmap as u32, }; 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, + self.handle, + xpnts.get(), + ypnts.get(), + zpnts.get(), + xdirs.get(), + ydirs.get(), + zdirs.get(), + &cprops as *const af_cell, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -993,18 +1008,18 @@ impl Window { None => format!("Cell({},{}))", self.col, self.row), }; let tstr = CString::new(tstr).unwrap(); - let cprops = &Cell { + let cprops = af_cell { row: self.row, col: self.col, title: tstr.as_ptr(), - cmap: self.cmap, + cmap: self.cmap as u32, }; 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, + self.handle, + points.get(), + directions.get(), + &cprops as *const af_cell, ); HANDLE_ERROR(AfError::from(err_val)); } diff --git a/src/image/mod.rs b/src/image/mod.rs index b15afd89b..68aee1992 100644 --- a/src/image/mod.rs +++ b/src/image/mod.rs @@ -1,222 +1,259 @@ -extern crate libc; - -use self::libc::{c_char, c_double, c_float, c_int, c_uint}; -use crate::array::Array; -use crate::defines::{AfError, BorderType, CannyThresholdType, ColorSpace, Connectivity}; -use crate::defines::{DiffusionEq, FluxFn, InterpType, MomentType, YCCStd}; -use crate::defines::{InverseDeconvAlgo, IterativeDeconvAlgo}; -use crate::error::HANDLE_ERROR; -use crate::util::{AfArray, DimT, MutAfArray}; -use crate::util::{ConfidenceCCInput, DeconvInput}; -use crate::util::{EdgeComputable, GrayRGBConvertible, MomentsComputable, RealFloating}; -use crate::util::{FloatingPoint, HasAfEnum, ImageFilterType, ImageNativeType, RealNumber}; +use super::core::{ + af_array, dim_t, AfError, Array, BorderType, CannyThresholdType, ColorSpace, ConfidenceCCInput, + Connectivity, DeconvInput, DiffusionEq, EdgeComputable, FloatingPoint, FluxFn, + GrayRGBConvertible, HasAfEnum, ImageFilterType, ImageNativeType, InterpType, InverseDeconvAlgo, + IterativeDeconvAlgo, MomentType, MomentsComputable, RealFloating, RealNumber, YCCStd, + HANDLE_ERROR, +}; + +use libc::{c_char, c_double, c_float, c_int, c_uint}; use std::ffi::CString; // unused functions from image.h header +// TODO add later when requested // af_load_image_memory // af_save_image_memory // af_delete_image_memory -#[allow(dead_code)] extern "C" { - fn af_cast(out: MutAfArray, arr: AfArray, aftype: c_uint) -> c_int; - fn af_gradient(dx: MutAfArray, dy: MutAfArray, arr: 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_cast(out: *mut af_array, arr: af_array, aftype: c_uint) -> c_int; + fn af_gradient(dx: *mut af_array, dy: *mut af_array, arr: af_array) -> c_int; + fn af_load_image(out: *mut af_array, filename: *const c_char, iscolor: bool) -> c_int; + fn af_save_image(filename: *const c_char, input: af_array) -> c_int; + fn af_load_image_native(out: *mut af_array, filename: *const c_char) -> c_int; + fn af_save_image_native(filename: *const c_char, input: af_array) -> c_int; fn af_resize( - out: MutAfArray, - input: AfArray, - odim0: DimT, - odim1: DimT, + out: *mut af_array, + input: af_array, + odim0: dim_t, + odim1: dim_t, method: c_uint, ) -> c_int; fn af_transform( - out: MutAfArray, - input: AfArray, - trans: AfArray, - odim0: DimT, - odim1: DimT, + out: *mut af_array, + input: af_array, + trans: af_array, + odim0: dim_t, + odim1: dim_t, method: c_uint, - is_inverse: c_int, + is_inverse: bool, ) -> c_int; fn af_rotate( - out: MutAfArray, - input: AfArray, + out: *mut af_array, + input: af_array, theta: c_float, - crop: c_int, + crop: bool, method: c_uint, ) -> c_int; fn af_translate( - out: MutAfArray, - input: AfArray, + out: *mut af_array, + input: af_array, trans0: c_float, trans1: c_float, - odim0: DimT, - odim1: DimT, + odim0: dim_t, + odim1: dim_t, method: c_uint, ) -> c_int; fn af_scale( - out: MutAfArray, - input: AfArray, + out: *mut af_array, + input: af_array, scale0: c_float, scale1: c_float, - odim0: DimT, - odim1: DimT, + odim0: dim_t, + odim1: dim_t, method: c_uint, ) -> c_int; fn af_skew( - out: MutAfArray, - input: AfArray, + out: *mut af_array, + input: af_array, skew0: c_float, skew1: c_float, - odim0: DimT, - odim1: DimT, + odim0: dim_t, + odim1: dim_t, method: c_uint, - is_inverse: c_int, + is_inverse: bool, ) -> c_int; fn af_histogram( - out: MutAfArray, - input: AfArray, + out: *mut af_array, + input: af_array, nbins: c_uint, minval: c_double, maxval: c_double, ) -> c_int; - fn af_dilate(out: MutAfArray, input: AfArray, mask: AfArray) -> c_int; - fn af_dilate3(out: MutAfArray, input: AfArray, mask: AfArray) -> c_int; - fn af_erode(out: MutAfArray, input: AfArray, mask: AfArray) -> c_int; - fn af_erode3(out: MutAfArray, input: AfArray, mask: AfArray) -> c_int; - fn af_regions(out: MutAfArray, input: AfArray, conn: c_uint, aftype: c_uint) -> c_int; - fn af_sobel_operator(dx: MutAfArray, dy: MutAfArray, i: AfArray, ksize: c_uint) -> c_int; - fn af_rgb2gray(out: MutAfArray, input: AfArray, r: c_float, g: c_float, b: c_float) -> c_int; - fn af_gray2rgb(out: MutAfArray, input: AfArray, r: c_float, g: c_float, b: c_float) -> c_int; - fn af_hist_equal(out: MutAfArray, input: AfArray, hist: AfArray) -> c_int; - fn af_hsv2rgb(out: MutAfArray, input: AfArray) -> c_int; - fn af_rgb2hsv(out: MutAfArray, input: AfArray) -> c_int; + fn af_dilate(out: *mut af_array, input: af_array, mask: af_array) -> c_int; + fn af_dilate3(out: *mut af_array, input: af_array, mask: af_array) -> c_int; + fn af_erode(out: *mut af_array, input: af_array, mask: af_array) -> c_int; + fn af_erode3(out: *mut af_array, input: af_array, mask: af_array) -> c_int; + fn af_regions(out: *mut af_array, input: af_array, conn: c_uint, aftype: c_uint) -> c_int; + fn af_sobel_operator(dx: *mut af_array, dy: *mut af_array, i: af_array, ksize: c_uint) + -> c_int; + fn af_rgb2gray( + out: *mut af_array, + input: af_array, + r: c_float, + g: c_float, + b: c_float, + ) -> c_int; + fn af_gray2rgb( + out: *mut af_array, + input: af_array, + r: c_float, + g: c_float, + b: c_float, + ) -> c_int; + fn af_hist_equal(out: *mut af_array, input: af_array, hist: af_array) -> c_int; + fn af_hsv2rgb(out: *mut af_array, input: af_array) -> c_int; + fn af_rgb2hsv(out: *mut af_array, input: af_array) -> c_int; fn af_bilateral( - out: MutAfArray, - input: AfArray, + out: *mut af_array, + input: af_array, sp_sig: c_float, ch_sig: c_float, - iscolor: c_int, + iscolor: bool, ) -> c_int; fn af_mean_shift( - out: MutAfArray, - input: AfArray, + out: *mut af_array, + input: af_array, sp_sig: c_float, ch_sig: c_float, iter: c_uint, - iscolor: c_int, + iscolor: bool, ) -> c_int; - fn af_medfilt(out: MutAfArray, input: AfArray, wlen: DimT, wwid: DimT, etype: c_uint) -> c_int; + fn af_medfilt( + out: *mut af_array, + input: af_array, + wlen: dim_t, + wwid: dim_t, + etype: c_uint, + ) -> c_int; - fn af_medfilt1(out: MutAfArray, input: AfArray, wlen: DimT, etype: c_uint) -> c_int; + fn af_medfilt1(out: *mut af_array, input: af_array, wlen: dim_t, etype: c_uint) -> c_int; - fn af_minfilt(out: MutAfArray, input: AfArray, wlen: DimT, wwid: DimT, etype: c_uint) -> c_int; + fn af_minfilt( + out: *mut af_array, + input: af_array, + wlen: dim_t, + wwid: dim_t, + etype: c_uint, + ) -> c_int; - fn af_maxfilt(out: MutAfArray, input: AfArray, wlen: DimT, wwid: DimT, etype: c_uint) -> c_int; + fn af_maxfilt( + out: *mut af_array, + input: af_array, + wlen: dim_t, + wwid: dim_t, + etype: c_uint, + ) -> c_int; fn af_gaussian_kernel( - out: MutAfArray, + out: *mut af_array, rows: c_int, cols: c_int, sigma_r: c_double, sigma_c: c_double, ) -> c_int; - fn af_color_space(out: MutAfArray, input: AfArray, tospace: c_uint, fromspace: c_uint) - -> c_int; + fn af_color_space( + out: *mut af_array, + input: af_array, + tospace: c_uint, + fromspace: c_uint, + ) -> c_int; fn af_unwrap( - out: MutAfArray, - input: AfArray, - wx: DimT, - wy: DimT, - sx: DimT, - sy: DimT, - px: DimT, - py: DimT, - is_column: c_int, + out: *mut af_array, + input: af_array, + wx: dim_t, + wy: dim_t, + sx: dim_t, + sy: dim_t, + px: dim_t, + py: dim_t, + is_column: bool, ) -> c_int; fn af_wrap( - out: MutAfArray, - input: AfArray, - ox: DimT, - oy: DimT, - wx: DimT, - wy: DimT, - sx: DimT, - sy: DimT, - px: DimT, - py: DimT, - is_column: c_int, + out: *mut af_array, + input: af_array, + ox: dim_t, + oy: dim_t, + wx: dim_t, + wy: dim_t, + sx: dim_t, + sy: dim_t, + px: dim_t, + py: dim_t, + is_column: bool, ) -> c_int; - fn af_sat(out: MutAfArray, input: AfArray) -> c_int; + fn af_sat(out: *mut af_array, input: af_array) -> c_int; - 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; + fn af_ycbcr2rgb(out: *mut af_array, input: af_array, stnd: c_uint) -> c_int; + fn af_rgb2ycbcr(out: *mut af_array, input: af_array, stnd: c_uint) -> c_int; + fn af_is_image_io_available(out: *mut bool) -> c_int; + fn af_transform_coordinates( + out: *mut af_array, + tf: af_array, + 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; + fn af_moments(out: *mut af_array, input: af_array, moment: c_uint) -> c_int; + fn af_moments_all(out: *mut c_double, input: af_array, moment: c_uint) -> c_int; fn af_canny( - out: MutAfArray, - input: AfArray, + out: *mut af_array, + input: af_array, thres_type: c_int, low: c_float, high: c_float, swindow: c_uint, - is_fast: c_int, + is_fast: bool, ) -> c_int; fn af_anisotropic_diffusion( - out: MutAfArray, - input: AfArray, + out: *mut af_array, + input: af_array, dt: c_float, K: c_float, iters: c_uint, - fftype: c_int, - diff_kind: c_int, + fftype: c_uint, + diff_kind: c_uint, ) -> c_int; fn af_confidence_cc( - out: MutAfArray, - input: AfArray, - seedx: AfArray, - seedy: AfArray, + out: *mut af_array, + input: af_array, + seedx: af_array, + seedy: af_array, radius: c_uint, multiplier: c_uint, iterations: c_int, seg_val: c_double, ) -> c_int; fn af_iterative_deconv( - out: MutAfArray, - input: AfArray, - ker: AfArray, + out: *mut af_array, + input: af_array, + ker: af_array, iterations: c_uint, rfactor: c_float, - algo: c_int, + algo: c_uint, ) -> c_int; fn af_inverse_deconv( - out: MutAfArray, - input: AfArray, - ker: AfArray, + out: *mut af_array, + input: af_array, + ker: af_array, gamma: c_float, - algo: c_int, + algo: c_uint, ) -> c_int; } @@ -235,22 +272,21 @@ extern "C" { /// The first Array is `dx` which is the gradient along the 1st dimension. /// /// The second Array is `dy` which is the gradient along the 2nd dimension. -#[allow(unused_mut)] pub fn gradient(input: &Array) -> (Array, Array) where T: HasAfEnum + FloatingPoint, { - let mut dx: i64 = 0; - let mut dy: i64 = 0; unsafe { + let mut dx: af_array = std::ptr::null_mut(); + let mut dy: af_array = std::ptr::null_mut(); let err_val = af_gradient( - &mut dx as MutAfArray, - &mut dy as MutAfArray, - input.get() as AfArray, + &mut dx as *mut af_array, + &mut dy as *mut af_array, + input.get(), ); HANDLE_ERROR(AfError::from(err_val)); + (dx.into(), dy.into()) } - (dx.into(), dy.into()) } /// Load Image into Array @@ -265,7 +301,6 @@ where /// # Return Arrays /// /// An Array with pixel values loaded from the image -#[allow(unused_mut)] #[allow(clippy::match_wild_err_arm)] pub fn load_image(filename: String, is_color: bool) -> Array where @@ -276,19 +311,17 @@ where Err(_) => panic!("CString creation from input filename failed"), }; let trgt_type = T::get_af_dtype(); - let mut img: i64 = 0; unsafe { - let mut temp: i64 = 0; - let err1 = af_load_image( - &mut temp as MutAfArray, - cstr_param.as_ptr(), - is_color as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err1 = af_load_image(&mut temp as *mut af_array, cstr_param.as_ptr(), is_color); HANDLE_ERROR(AfError::from(err1)); - let err2 = af_cast(&mut img as MutAfArray, temp as AfArray, trgt_type as c_uint); + + let mut img: af_array = std::ptr::null_mut(); + let err2 = af_cast(&mut img as *mut af_array, temp, trgt_type as c_uint); HANDLE_ERROR(AfError::from(err2)); + + img.into() } - img.into() } /// Load Image into Array in it's native type @@ -309,7 +342,6 @@ where /// # Return Arrays /// /// An Array with pixel values loaded from the image -#[allow(unused_mut)] #[allow(clippy::match_wild_err_arm)] pub fn load_image_native(filename: String) -> Array where @@ -320,15 +352,17 @@ where Err(_) => panic!("CString creation from input filename failed"), }; let trgt_type = T::get_af_dtype(); - let mut img: i64 = 0; unsafe { - let mut temp: i64 = 0; - let err1 = af_load_image_native(&mut temp as MutAfArray, cstr_param.as_ptr()); + let mut temp: af_array = std::ptr::null_mut(); + let err1 = af_load_image_native(&mut temp as *mut af_array, cstr_param.as_ptr()); HANDLE_ERROR(AfError::from(err1)); - let err2 = af_cast(&mut img as MutAfArray, temp as AfArray, trgt_type as c_uint); + + let mut img: af_array = std::ptr::null_mut(); + let err2 = af_cast(&mut img as *mut af_array, temp, trgt_type as c_uint); HANDLE_ERROR(AfError::from(err2)); + + img.into() } - img.into() } /// Save an Array to an image file @@ -337,7 +371,6 @@ where /// /// - `filename` is the abolute path(includes filename) at which input Array is going to be saved /// - `input` is the Array to be stored into the image file -#[allow(unused_mut)] #[allow(clippy::match_wild_err_arm)] pub fn save_image(filename: String, input: &Array) where @@ -348,7 +381,7 @@ where Err(_) => panic!("CString creation from input filename failed"), }; unsafe { - let err_val = af_save_image(cstr_param.as_ptr(), input.get() as AfArray); + let err_val = af_save_image(cstr_param.as_ptr(), input.get()); HANDLE_ERROR(AfError::from(err_val)); } } @@ -369,7 +402,6 @@ where /// /// - `filename` is name of file to be saved /// - `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)] #[allow(clippy::match_wild_err_arm)] pub fn save_image_native(filename: String, input: &Array) where @@ -380,7 +412,7 @@ where Err(_) => panic!("CString creation from input filename failed"), }; unsafe { - let err_val = af_save_image_native(cstr_param.as_ptr(), input.get() as AfArray); + let err_val = af_save_image_native(cstr_param.as_ptr(), input.get()); HANDLE_ERROR(AfError::from(err_val)); } } @@ -405,25 +437,24 @@ where /// # Return Values /// /// Resized Array -#[allow(unused_mut)] pub fn resize( input: &Array, odim0: i64, odim1: i64, method: InterpType, ) -> Array { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_resize( - &mut temp as MutAfArray, - input.get() as AfArray, - odim0 as DimT, - odim1 as DimT, + &mut temp as *mut af_array, + input.get(), + odim0 as dim_t, + odim1 as dim_t, method as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Transform(Affine) an Image @@ -455,7 +486,6 @@ pub fn resize( /// # Return Values /// /// Transformed Array -#[allow(unused_mut)] pub fn transform( input: &Array, trans: &Array, @@ -464,20 +494,20 @@ pub fn transform( method: InterpType, is_inverse: bool, ) -> Array { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_transform( - &mut temp as MutAfArray, - input.get() as AfArray, - trans.get() as AfArray, - odim0 as DimT, - odim1 as DimT, + &mut temp as *mut af_array, + input.get(), + trans.get(), + odim0 as dim_t, + odim1 as dim_t, method as c_uint, - is_inverse as c_int, + is_inverse, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Rotate an Image @@ -509,25 +539,24 @@ pub fn transform( /// # Return Values /// /// Rotated Array -#[allow(unused_mut)] pub fn rotate( input: &Array, theta: f64, crop: bool, method: InterpType, ) -> Array { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_rotate( - &mut temp as MutAfArray, - input.get() as AfArray, + &mut temp as *mut af_array, + input.get(), theta as c_float, - crop as c_int, + crop, method as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Translate an Image @@ -557,7 +586,6 @@ pub fn rotate( /// # Return Values /// /// Translated Image(Array). -#[allow(unused_mut)] pub fn translate( input: &Array, trans0: f32, @@ -566,20 +594,20 @@ pub fn translate( odim1: i64, method: InterpType, ) -> Array { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_translate( - &mut temp as MutAfArray, - input.get() as AfArray, - trans0 as c_float, - trans1 as c_float, - odim0 as DimT, - odim1 as DimT, + &mut temp as *mut af_array, + input.get(), + trans0, + trans1, + odim0 as dim_t, + odim1 as dim_t, method as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Scale an Image @@ -600,7 +628,6 @@ pub fn translate( /// # Return Values /// /// Translated Image(Array). -#[allow(unused_mut)] pub fn scale( input: &Array, scale0: f32, @@ -609,20 +636,20 @@ pub fn scale( odim1: i64, method: InterpType, ) -> Array { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_scale( - &mut temp as MutAfArray, - input.get() as AfArray, - scale0 as c_float, - scale1 as c_float, - odim0 as DimT, - odim1 as DimT, + &mut temp as *mut af_array, + input.get(), + scale0, + scale1, + odim0 as dim_t, + odim1 as dim_t, method as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Skew an image @@ -649,7 +676,6 @@ pub fn scale( /// # Return Values /// /// Skewed Image -#[allow(unused_mut)] pub fn skew( input: &Array, skew0: f32, @@ -659,21 +685,21 @@ pub fn skew( method: InterpType, is_inverse: bool, ) -> Array { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_skew( - &mut temp as MutAfArray, - input.get() as AfArray, - skew0 as c_float, - skew1 as c_float, - odim0 as DimT, - odim1 as DimT, + &mut temp as *mut af_array, + input.get(), + skew0, + skew1, + odim0 as dim_t, + odim1 as dim_t, method as c_uint, - is_inverse as c_int, + is_inverse, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Compute Histogram of an Array @@ -699,23 +725,22 @@ pub fn skew( /// # Return Values /// /// Histogram of input Array -#[allow(unused_mut)] pub fn histogram(input: &Array, nbins: u32, minval: f64, maxval: f64) -> Array where T: HasAfEnum + RealNumber, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_histogram( - &mut temp as MutAfArray, - input.get() as AfArray, - nbins as c_uint, - minval as c_double, - maxval as c_double, + &mut temp as *mut af_array, + input.get(), + nbins, + minval, + maxval, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Dilate an Image @@ -737,21 +762,16 @@ where /// # Return Values /// /// Dilated Image(Array) -#[allow(unused_mut)] pub fn dilate(input: &Array, mask: &Array) -> Array where T: HasAfEnum + ImageFilterType, { - let mut temp: i64 = 0; unsafe { - let err_val = af_dilate( - &mut temp as MutAfArray, - input.get() as AfArray, - mask.get() as AfArray, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_dilate(&mut temp as *mut af_array, input.get(), mask.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Erode an Image @@ -774,21 +794,16 @@ where /// # Return Values /// /// Eroded Image(Array) -#[allow(unused_mut)] pub fn erode(input: &Array, mask: &Array) -> Array where T: HasAfEnum + ImageFilterType, { - let mut temp: i64 = 0; unsafe { - let err_val = af_erode( - &mut temp as MutAfArray, - input.get() as AfArray, - mask.get() as AfArray, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_erode(&mut temp as *mut af_array, input.get(), mask.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Dilate a Volume @@ -804,21 +819,16 @@ where /// # Return Values /// /// Dilated Volume(Array) -#[allow(unused_mut)] pub fn dilate3(input: &Array, mask: &Array) -> Array where T: HasAfEnum + ImageFilterType, { - let mut temp: i64 = 0; unsafe { - let err_val = af_dilate3( - &mut temp as MutAfArray, - input.get() as AfArray, - mask.get() as AfArray, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_dilate3(&mut temp as *mut af_array, input.get(), mask.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Erode a Volume @@ -834,21 +844,16 @@ where /// # Return Values /// /// Eroded Volume(Array) -#[allow(unused_mut)] pub fn erode3(input: &Array, mask: &Array) -> Array where T: HasAfEnum + ImageFilterType, { - let mut temp: i64 = 0; unsafe { - let err_val = af_erode3( - &mut temp as MutAfArray, - input.get() as AfArray, - mask.get() as AfArray, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_erode3(&mut temp as *mut af_array, input.get(), mask.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Bilateral Filter. @@ -870,7 +875,6 @@ where /// # Return Values /// /// Filtered Image - Array -#[allow(unused_mut)] pub fn bilateral( input: &Array, spatial_sigma: f32, @@ -881,18 +885,18 @@ where T: HasAfEnum + ImageFilterType, T::AbsOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_bilateral( - &mut temp as MutAfArray, - input.get() as AfArray, - spatial_sigma as c_float, - chromatic_sigma as c_float, - iscolor as c_int, + &mut temp as *mut af_array, + input.get(), + spatial_sigma, + chromatic_sigma, + iscolor, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Meanshift Filter. @@ -915,7 +919,6 @@ where /// # Return Values /// /// Filtered Image - Array -#[allow(unused_mut)] pub fn mean_shift( input: &Array, spatial_sigma: f32, @@ -926,19 +929,19 @@ pub fn mean_shift( where T: HasAfEnum + RealNumber, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_mean_shift( - &mut temp as MutAfArray, - input.get() as AfArray, - spatial_sigma as c_float, - chromatic_sigma as c_float, - iter as c_uint, - iscolor as c_int, + &mut temp as *mut af_array, + input.get(), + spatial_sigma, + chromatic_sigma, + iter, + iscolor, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } macro_rules! filt_func_def { @@ -955,23 +958,22 @@ macro_rules! filt_func_def { ///# Return Values /// /// An Array with filtered image data. - #[allow(unused_mut)] pub fn $fn_name(input: &Array, wlen: u64, wwid: u64, etype: BorderType) -> Array where T: HasAfEnum + ImageFilterType, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = $ffi_name( - &mut temp as MutAfArray, - input.get() as AfArray, - wlen as DimT, - wwid as DimT, + &mut temp as *mut af_array, + input.get(), + wlen as dim_t, + wwid as dim_t, etype as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } }; } @@ -1009,20 +1011,13 @@ filt_func_def!( /// # Return Values /// /// An Array with gaussian kernel values -#[allow(unused_mut)] pub fn gaussian_kernel(rows: i32, cols: i32, sigma_r: f64, sigma_c: f64) -> Array { - let mut temp: i64 = 0; unsafe { - let err_val = af_gaussian_kernel( - &mut temp as MutAfArray, - rows as c_int, - cols as c_int, - sigma_r as c_double, - sigma_c as c_double, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_gaussian_kernel(&mut temp as *mut af_array, rows, cols, sigma_r, sigma_c); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Color space conversion @@ -1059,22 +1054,21 @@ pub fn gaussian_kernel(rows: i32, cols: i32, sigma_r: f64, sigma_c: f64) -> Arra /// # Return Values /// /// An Array with input image values in target color space -#[allow(unused_mut)] pub fn color_space(input: &Array, tospace: ColorSpace, fromspace: ColorSpace) -> Array where T: HasAfEnum + RealNumber, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_color_space( - &mut temp as MutAfArray, - input.get() as AfArray, + &mut temp as *mut af_array, + input.get(), tospace as c_uint, fromspace as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Find blobs in given image. @@ -1094,23 +1088,22 @@ where /// # Return Values /// /// Array with labels indicating different regions -#[allow(unused_mut)] pub fn regions(input: &Array, conn: Connectivity) -> Array where OutType: HasAfEnum + RealNumber, { let otype = OutType::get_af_dtype(); - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_regions( - &mut temp as MutAfArray, - input.get() as AfArray, + &mut temp as *mut af_array, + input.get(), conn as c_uint, otype as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Sobel Operator @@ -1130,24 +1123,23 @@ where /// The first Array has derivatives along horizontal direction /// /// The second Array has derivatives along vertical direction -#[allow(unused_mut)] pub fn sobel(input: &Array, ker_size: u32) -> (Array, Array) where T: HasAfEnum + ImageFilterType, T::SobelOutType: HasAfEnum, { - let mut dx: i64 = 0; - let mut dy: i64 = 0; unsafe { + let mut dx: af_array = std::ptr::null_mut(); + let mut dy: af_array = std::ptr::null_mut(); let err_val = af_sobel_operator( - &mut dx as MutAfArray, - &mut dy as MutAfArray, - input.get() as AfArray, - ker_size as c_uint, + &mut dx as *mut af_array, + &mut dy as *mut af_array, + input.get(), + ker_size, ); HANDLE_ERROR(AfError::from(err_val)); + (dx.into(), dy.into()) } - (dx.into(), dy.into()) } /// Histogram Equalization @@ -1159,21 +1151,16 @@ where /// /// # Return Values /// Equalized Array -#[allow(unused_mut)] pub fn hist_equal(input: &Array, hist: &Array) -> Array where T: HasAfEnum + RealNumber, { - let mut temp: i64 = 0; unsafe { - let err_val = af_hist_equal( - &mut temp as MutAfArray, - input.get() as AfArray, - hist.get() as AfArray, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_hist_equal(&mut temp as *mut af_array, input.get(), hist.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } macro_rules! grayrgb_func_def { @@ -1189,23 +1176,16 @@ macro_rules! grayrgb_func_def { ///#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 where T: HasAfEnum + GrayRGBConvertible, { - let mut temp: i64 = 0; unsafe { - let err_val = $ffi_name( - &mut temp as MutAfArray, - input.get() as AfArray, - r as c_float, - g as c_float, - b as c_float, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = $ffi_name(&mut temp as *mut af_array, input.get(), r, g, b); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } }; } @@ -1216,17 +1196,16 @@ grayrgb_func_def!("Grayscale to Color(RGB) conversion", gray2rgb, af_gray2rgb); macro_rules! hsvrgb_func_def { ($doc_str: expr, $fn_name: ident, $ffi_name: ident) => { #[doc=$doc_str] - #[allow(unused_mut)] pub fn $fn_name(input: &Array) -> Array where T: HasAfEnum + RealFloating, { - let mut temp: i64 = 0; unsafe { - let err_val = $ffi_name(&mut temp as MutAfArray, input.get() as AfArray); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = $ffi_name(&mut temp as *mut af_array, input.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } }; } @@ -1258,8 +1237,8 @@ hsvrgb_func_def!("RGB to HSV color space conversion", rgb2hsv, af_rgb2hsv); /// # Parameters /// /// - `input` is the input image -/// - `wx` is the block window size along 0th-dimension between [1, input.dims[0] + px] -/// - `wy` is the block window size along 1st-dimension between [1, input.dims[1] + py] +/// - `wx` is the block window size along 0th-dimension between \[1, input.dims\[0\] + px\] +/// - `wy` is the block window size along 1st-dimension between \[1, input.dims\[1\] + py\] /// - `sx` is the stride along 0th-dimension /// - `sy` is the stride along 1st-dimension /// - `px` is the padding along 0th-dimension between [0, wx). Padding is applied both before and after. @@ -1315,22 +1294,22 @@ pub fn unwrap( py: i64, is_column: bool, ) -> Array { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_unwrap( - &mut temp as MutAfArray, - input.get() as AfArray, + &mut temp as *mut af_array, + input.get(), wx, wy, sx, sy, px, py, - is_column as c_int, + is_column, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Converts unwrapped image to an image @@ -1369,11 +1348,11 @@ pub fn wrap( py: i64, is_column: bool, ) -> Array { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_wrap( - &mut temp as MutAfArray, - input.get() as AfArray, + &mut temp as *mut af_array, + input.get(), ox, oy, wx, @@ -1382,11 +1361,11 @@ pub fn wrap( sy, px, py, - is_column as c_int, + is_column, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Summed area table of an Image @@ -1403,12 +1382,12 @@ where T: HasAfEnum + RealNumber, T::AggregateOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_sat(&mut temp as MutAfArray, input.get() as AfArray); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_sat(&mut temp as *mut af_array, input.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// RGB to YCbCr colorspace converter. @@ -1435,16 +1414,12 @@ pub fn rgb2ycbcr(input: &Array, standard: YCCStd) -> Array where T: HasAfEnum + RealFloating, { - let mut temp: i64 = 0; unsafe { - let err_val = af_rgb2ycbcr( - &mut temp as MutAfArray, - input.get() as AfArray, - standard as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_rgb2ycbcr(&mut temp as *mut af_array, input.get(), standard as c_uint); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// YCbCr to RGB colorspace converter. @@ -1477,16 +1452,12 @@ pub fn ycbcr2rgb(input: &Array, standard: YCCStd) -> Array where T: HasAfEnum + RealFloating, { - let mut temp: i64 = 0; unsafe { - let err_val = af_ycbcr2rgb( - &mut temp as MutAfArray, - input.get() as AfArray, - standard as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_ycbcr2rgb(&mut temp as *mut af_array, input.get(), standard as c_uint); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Function to check if Image I/O is available @@ -1499,11 +1470,11 @@ where /// /// Return a boolean indicating if ArrayFire was compiled with Image I/O support pub fn is_imageio_available() -> bool { - let mut temp: i32 = 0; + let mut temp: bool = false; unsafe { - af_is_image_io_available(&mut temp as *mut c_int); + af_is_image_io_available(&mut temp as *mut bool); } - temp > 0 // Return boolean flag + temp } /// Transform input coordinates @@ -1527,17 +1498,12 @@ pub fn transform_coords(tf: &Array, d0: f32, d1: f32) -> Array where T: HasAfEnum + RealFloating, { - let mut temp: i64 = 0; unsafe { - let err_val = af_transform_coordinates( - &mut temp as MutAfArray, - tf.get() as AfArray, - d0 as c_float, - d1 as c_float, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_transform_coordinates(&mut temp as *mut af_array, tf.get(), d0, d1); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Find Image moments @@ -1555,16 +1521,12 @@ pub fn moments(input: &Array, moment: MomentType) -> Array where T: HasAfEnum + MomentsComputable, { - let mut temp: i64 = 0; unsafe { - let err_val = af_moments( - &mut temp as MutAfArray, - input.get() as AfArray, - moment as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_moments(&mut temp as *mut af_array, input.get(), moment as c_uint); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Find Image moment for whole image @@ -1584,11 +1546,7 @@ where { let mut temp: f64 = 0.0; unsafe { - let err_val = af_moments_all( - &mut temp as *mut c_double, - input.get() as AfArray, - moment as c_int, - ); + let err_val = af_moments_all(&mut temp as *mut c_double, input.get(), moment as c_uint); HANDLE_ERROR(AfError::from(err_val)); } temp @@ -1609,17 +1567,17 @@ pub fn medfilt1(input: &Array, wlen: u64, etype: BorderType) -> Array where T: HasAfEnum + ImageFilterType, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_medfilt1( - &mut temp as MutAfArray, - input.get() as AfArray, - wlen as DimT, + &mut temp as *mut af_array, + input.get(), + wlen as dim_t, etype as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Canny edge detection operator @@ -1631,7 +1589,7 @@ where /// - `input` is the input image /// - `threshold_type` helps determine if user set high threshold is to be used or not. It can take values defined by the enum [CannyThresholdType](./enum.CannyThresholdType.html) /// - `low` is the lower threshold % of the maximum or auto-derived high -/// - `hight` is the higher threshold % of maximum value in gradient image used in hysteresis procedure. This value is ignored if [CannyThresholdType::OTSU](./enum.CannyThresholdType.html) is chosen. +/// - `high` is the higher threshold % of maximum value in gradient image used in hysteresis procedure. This value is ignored if [CannyThresholdType::OTSU](./enum.CannyThresholdType.html) is chosen. /// - `sobel_window` is the window size of sobel kernel for computing gradient direction and magnitude. /// - `is_fast` indicates if L1 norm(faster but less accurate) is used to compute image gradient magnitude instead of L2 norm. /// @@ -1643,27 +1601,27 @@ pub fn canny( input: &Array, threshold_type: CannyThresholdType, low: f32, - hight: f32, + high: f32, sobel_window: u32, is_fast: bool, ) -> Array where T: HasAfEnum + EdgeComputable, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_canny( - &mut temp as MutAfArray, - input.get() as AfArray, + &mut temp as *mut af_array, + input.get(), threshold_type as c_int, - low as c_float, - hight as c_float, + low, + high, sobel_window as c_uint, - is_fast as c_int, + is_fast, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Anisotropic smoothing filter @@ -1752,20 +1710,20 @@ where T: HasAfEnum + EdgeComputable, T::AbsOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_anisotropic_diffusion( - &mut temp as MutAfArray, - img.get() as AfArray, - dt as c_float, - k as c_float, - iters as c_uint, - fftype as c_int, - diff_kind as c_int, + &mut temp as *mut af_array, + img.get(), + dt, + k, + iters, + fftype as c_uint, + diff_kind as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Segment image based on similar pixel characteristics @@ -1823,21 +1781,21 @@ pub fn confidence_cc( where InOutType: ConfidenceCCInput, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_confidence_cc( - &mut temp as MutAfArray, - input.get() as AfArray, - seedx.get() as AfArray, - seedy.get() as AfArray, + &mut temp as *mut af_array, + input.get(), + seedx.get(), + seedy.get(), radius, multiplier, iterations as i32, segmented_val, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Iterative Deconvolution @@ -1886,19 +1844,19 @@ where T: DeconvInput, T::AbsOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_iterative_deconv( - &mut temp as MutAfArray, - input.get() as AfArray, - kernel.get() as AfArray, + &mut temp as *mut af_array, + input.get(), + kernel.get(), iterations, relaxation_factor, - algo as c_int, + algo as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Inverse deconvolution @@ -1939,16 +1897,16 @@ where T: DeconvInput, T::AbsOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_inverse_deconv( - &mut temp as MutAfArray, - input.get() as AfArray, - kernel.get() as AfArray, + &mut temp as *mut af_array, + input.get(), + kernel.get(), gamma, - algo as c_int, + algo as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } diff --git a/src/lapack/mod.rs b/src/lapack/mod.rs index b7ba256da..457877812 100644 --- a/src/lapack/mod.rs +++ b/src/lapack/mod.rs @@ -1,30 +1,48 @@ -extern crate libc; +use super::core::{ + af_array, AfError, Array, FloatingPoint, HasAfEnum, MatProp, NormType, HANDLE_ERROR, +}; -use self::libc::{c_double, c_int, c_uint}; -use crate::array::Array; -use crate::defines::{AfError, MatProp, NormType}; -use crate::error::HANDLE_ERROR; -use crate::util::{to_u32, AfArray, MutAfArray, MutDouble}; -use crate::util::{FloatingPoint, HasAfEnum}; +use libc::{c_double, c_int, c_uint}; -#[allow(dead_code)] extern "C" { - fn af_svd(u: MutAfArray, s: MutAfArray, vt: MutAfArray, input: AfArray) -> c_int; - fn af_svd_inplace(u: MutAfArray, s: MutAfArray, vt: MutAfArray, input: AfArray) -> c_int; - fn af_lu(lower: MutAfArray, upper: MutAfArray, pivot: MutAfArray, input: AfArray) -> c_int; - fn af_lu_inplace(pivot: MutAfArray, input: AfArray, is_lapack_piv: c_int) -> c_int; - fn af_qr(q: MutAfArray, r: MutAfArray, tau: MutAfArray, input: AfArray) -> c_int; - fn af_qr_inplace(tau: MutAfArray, input: AfArray) -> c_int; - fn af_cholesky(out: MutAfArray, info: *mut c_int, input: AfArray, is_upper: c_int) -> c_int; - fn af_cholesky_inplace(info: *mut c_int, input: AfArray, is_upper: c_int) -> c_int; - fn af_solve(x: MutAfArray, a: AfArray, b: AfArray, options: c_uint) -> c_int; - fn af_solve_lu(x: MutAfArray, a: AfArray, piv: AfArray, b: AfArray, options: c_uint) -> c_int; - fn af_inverse(out: MutAfArray, input: AfArray, options: c_uint) -> c_int; - 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: c_uint, p: c_double, q: c_double) -> c_int; - fn af_is_lapack_available(out: *mut c_int) -> c_int; - fn af_pinverse(out: MutAfArray, input: AfArray, tol: c_double, options: c_int) -> c_int; + fn af_svd(u: *mut af_array, s: *mut af_array, vt: *mut af_array, input: af_array) -> c_int; + fn af_svd_inplace( + u: *mut af_array, + s: *mut af_array, + vt: *mut af_array, + input: af_array, + ) -> c_int; + fn af_lu( + lower: *mut af_array, + upper: *mut af_array, + pivot: *mut af_array, + input: af_array, + ) -> c_int; + fn af_lu_inplace(pivot: *mut af_array, input: af_array, is_lapack_piv: bool) -> c_int; + fn af_qr(q: *mut af_array, r: *mut af_array, tau: *mut af_array, input: af_array) -> c_int; + fn af_qr_inplace(tau: *mut af_array, input: af_array) -> c_int; + fn af_cholesky(out: *mut af_array, info: *mut c_int, input: af_array, is_upper: bool) -> c_int; + fn af_cholesky_inplace(info: *mut c_int, input: af_array, is_upper: bool) -> c_int; + fn af_solve(x: *mut af_array, a: af_array, b: af_array, options: c_uint) -> c_int; + fn af_solve_lu( + x: *mut af_array, + a: af_array, + piv: af_array, + b: af_array, + options: c_uint, + ) -> c_int; + fn af_inverse(out: *mut af_array, input: af_array, options: c_uint) -> c_int; + fn af_rank(rank: *mut c_uint, input: af_array, tol: c_double) -> c_int; + fn af_det(det_real: *mut c_double, det_imag: *mut c_double, input: af_array) -> c_int; + fn af_norm( + out: *mut c_double, + input: af_array, + ntype: c_uint, + p: c_double, + q: c_double, + ) -> c_int; + fn af_is_lapack_available(out: *mut bool) -> c_int; + fn af_pinverse(out: *mut af_array, input: af_array, tol: c_double, options: c_uint) -> c_int; } /// Perform Singular Value Decomposition @@ -50,25 +68,24 @@ extern "C" { /// The second Array is the output array containing the diagonal values of sigma, (singular values of the input matrix)) /// /// The third Array is the output array containing V ^ H -#[allow(unused_mut)] pub fn svd(input: &Array) -> (Array, Array, Array) where T: HasAfEnum + FloatingPoint, T::BaseType: HasAfEnum, { - let mut u: i64 = 0; - let mut s: i64 = 0; - let mut vt: i64 = 0; unsafe { + let mut u: af_array = std::ptr::null_mut(); + let mut s: af_array = std::ptr::null_mut(); + let mut vt: af_array = std::ptr::null_mut(); let err_val = af_svd( - &mut u as MutAfArray, - &mut s as MutAfArray, - &mut vt as MutAfArray, - input.get() as AfArray, + &mut u as *mut af_array, + &mut s as *mut af_array, + &mut vt as *mut af_array, + input.get(), ); HANDLE_ERROR(AfError::from(err_val)); + (u.into(), s.into(), vt.into()) } - (u.into(), s.into(), vt.into()) } /// Perform Singular Value Decomposition inplace @@ -95,25 +112,24 @@ where /// The second Array is the output array containing the diagonal values of sigma, (singular values of the input matrix)) /// /// The third Array is the output array containing V ^ H -#[allow(unused_mut)] pub fn svd_inplace(input: &mut Array) -> (Array, Array, Array) where T: HasAfEnum + FloatingPoint, T::BaseType: HasAfEnum, { - let mut u: i64 = 0; - let mut s: i64 = 0; - let mut vt: i64 = 0; unsafe { + let mut u: af_array = std::ptr::null_mut(); + let mut s: af_array = std::ptr::null_mut(); + let mut vt: af_array = std::ptr::null_mut(); let err_val = af_svd_inplace( - &mut u as MutAfArray, - &mut s as MutAfArray, - &mut vt as MutAfArray, - input.get() as AfArray, + &mut u as *mut af_array, + &mut s as *mut af_array, + &mut vt as *mut af_array, + input.get(), ); HANDLE_ERROR(AfError::from(err_val)); + (u.into(), s.into(), vt.into()) } - (u.into(), s.into(), vt.into()) } /// Perform LU decomposition @@ -131,24 +147,23 @@ where /// The second Array will contain the lower triangular matrix of the LU decomposition. /// /// The third Array will contain the permutation indices to map the input to the decomposition. -#[allow(unused_mut)] pub fn lu(input: &Array) -> (Array, Array, Array) where T: HasAfEnum + FloatingPoint, { - let mut lower: i64 = 0; - let mut upper: i64 = 0; - let mut pivot: i64 = 0; unsafe { + let mut lower: af_array = std::ptr::null_mut(); + let mut upper: af_array = std::ptr::null_mut(); + let mut pivot: af_array = std::ptr::null_mut(); let err_val = af_lu( - &mut lower as MutAfArray, - &mut upper as MutAfArray, - &mut pivot as MutAfArray, - input.get() as AfArray, + &mut lower as *mut af_array, + &mut upper as *mut af_array, + &mut pivot as *mut af_array, + input.get(), ); HANDLE_ERROR(AfError::from(err_val)); + (lower.into(), upper.into(), pivot.into()) } - (lower.into(), upper.into(), pivot.into()) } /// Perform inplace LU decomposition @@ -162,21 +177,16 @@ where /// /// An Array with permutation indices to map the input to the decomposition. Since, the input /// matrix is modified in place, only pivot values are returned. -#[allow(unused_mut)] pub fn lu_inplace(input: &mut Array, is_lapack_piv: bool) -> Array where T: HasAfEnum + FloatingPoint, { - let mut pivot: i64 = 0; unsafe { - let err_val = af_lu_inplace( - &mut pivot as MutAfArray, - input.get() as AfArray, - is_lapack_piv as c_int, - ); + let mut pivot: af_array = std::ptr::null_mut(); + let err_val = af_lu_inplace(&mut pivot as *mut af_array, input.get(), is_lapack_piv); HANDLE_ERROR(AfError::from(err_val)); + pivot.into() } - pivot.into() } /// Perform QR decomposition @@ -195,24 +205,23 @@ where /// /// The third Array will contain additional information needed for solving a least squares problem /// using q and r -#[allow(unused_mut)] pub fn qr(input: &Array) -> (Array, Array, Array) where T: HasAfEnum + FloatingPoint, { - let mut q: i64 = 0; - let mut r: i64 = 0; - let mut tau: i64 = 0; unsafe { + let mut q: af_array = std::ptr::null_mut(); + let mut r: af_array = std::ptr::null_mut(); + let mut tau: af_array = std::ptr::null_mut(); let err_val = af_qr( - &mut q as MutAfArray, - &mut r as MutAfArray, - &mut tau as MutAfArray, - input.get() as AfArray, + &mut q as *mut af_array, + &mut r as *mut af_array, + &mut tau as *mut af_array, + input.get(), ); HANDLE_ERROR(AfError::from(err_val)); + (q.into(), r.into(), tau.into()) } - (q.into(), r.into(), tau.into()) } /// Perform inplace QR decomposition @@ -224,17 +233,16 @@ where /// # Return Values /// /// An Array with additional information needed for unpacking the data. -#[allow(unused_mut)] pub fn qr_inplace(input: &mut Array) -> Array where T: HasAfEnum + FloatingPoint, { - let mut tau: i64 = 0; unsafe { - let err_val = af_qr_inplace(&mut tau as MutAfArray, input.get() as AfArray); + let mut tau: af_array = std::ptr::null_mut(); + let err_val = af_qr_inplace(&mut tau as *mut af_array, input.get()); HANDLE_ERROR(AfError::from(err_val)); + tau.into() } - tau.into() } /// Perform Cholesky decomposition @@ -252,23 +260,22 @@ where /// /// If the integer is 0, it means the cholesky decomposition passed. Otherwise, it will contain the rank at /// which the decomposition failed. -#[allow(unused_mut)] pub fn cholesky(input: &Array, is_upper: bool) -> (Array, i32) where T: HasAfEnum + FloatingPoint, { - let mut temp: i64 = 0; - let mut info: i32 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); + let mut info: i32 = 0; let err_val = af_cholesky( - &mut temp as MutAfArray, + &mut temp as *mut af_array, &mut info as *mut c_int, - input.get() as AfArray, - is_upper as c_int, + input.get(), + is_upper, ); HANDLE_ERROR(AfError::from(err_val)); + (temp.into(), info) } - (temp.into(), info) } /// Perform inplace Cholesky decomposition @@ -282,18 +289,13 @@ where /// /// A signed 32-bit integer. If the integer is 0, it means the cholesky decomposition passed. Otherwise, /// it will contain the rank at which the decomposition failed. -#[allow(unused_mut)] pub fn cholesky_inplace(input: &mut Array, is_upper: bool) -> i32 where T: HasAfEnum + FloatingPoint, { let mut info: i32 = 0; unsafe { - let err_val = af_cholesky_inplace( - &mut info as *mut c_int, - input.get() as AfArray, - is_upper as c_int, - ); + let err_val = af_cholesky_inplace(&mut info as *mut c_int, input.get(), is_upper); HANDLE_ERROR(AfError::from(err_val)); } info @@ -312,22 +314,21 @@ where /// # Return Values /// /// An Array which is the matrix of unknown variables -#[allow(unused_mut)] pub fn solve(a: &Array, b: &Array, options: MatProp) -> Array where T: HasAfEnum + FloatingPoint, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_solve( - &mut temp as MutAfArray, - a.get() as AfArray, - b.get() as AfArray, - to_u32(options) as c_uint, + &mut temp as *mut af_array, + a.get(), + b.get(), + options as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Solve a system of equations @@ -344,23 +345,22 @@ where /// # Return Values /// /// An Array which is the matrix of unknown variables -#[allow(unused_mut)] pub fn solve_lu(a: &Array, piv: &Array, b: &Array, options: MatProp) -> Array where T: HasAfEnum + FloatingPoint, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_solve_lu( - &mut temp as MutAfArray, - a.get() as AfArray, - piv.get() as AfArray, - b.get() as AfArray, - to_u32(options) as c_uint, + &mut temp as *mut af_array, + a.get(), + piv.get(), + b.get(), + options as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Compute inverse of a matrix @@ -375,21 +375,16 @@ where /// # Return Values /// /// An Array with values of the inverse of input matrix. -#[allow(unused_mut)] pub fn inverse(input: &Array, options: MatProp) -> Array where T: HasAfEnum + FloatingPoint, { - let mut temp: i64 = 0; unsafe { - let err_val = af_inverse( - &mut temp as MutAfArray, - input.get() as AfArray, - to_u32(options) as c_uint, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_inverse(&mut temp as *mut af_array, input.get(), options as c_uint); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Find rank of a matrix @@ -402,18 +397,13 @@ where /// # Return Values /// /// An unsigned 32-bit integer which is the rank of the input matrix. -#[allow(unused_mut)] pub fn rank(input: &Array, tol: f64) -> u32 where T: HasAfEnum + FloatingPoint, { let mut temp: u32 = 0; unsafe { - let err_val = af_rank( - &mut temp as *mut c_uint, - input.get() as AfArray, - tol as c_double, - ); + let err_val = af_rank(&mut temp as *mut c_uint, input.get(), tol); HANDLE_ERROR(AfError::from(err_val)); } temp @@ -430,7 +420,6 @@ where /// A tuple of 32-bit floating point values. /// /// If the input matrix is non-complex type, only first values of tuple contains the result. -#[allow(unused_mut)] pub fn det(input: &Array) -> (f64, f64) where T: HasAfEnum + FloatingPoint, @@ -439,9 +428,9 @@ where let mut imag: f64 = 0.0; unsafe { let err_val = af_det( - &mut real as MutDouble, - &mut imag as MutDouble, - input.get() as AfArray, + &mut real as *mut c_double, + &mut imag as *mut c_double, + input.get(), ); HANDLE_ERROR(AfError::from(err_val)); } @@ -462,7 +451,6 @@ where /// # Return Values /// /// A 64-bit floating point value that contains the norm of input matrix. -#[allow(unused_mut)] pub fn norm(input: &Array, ntype: NormType, p: f64, q: f64) -> f64 where T: HasAfEnum + FloatingPoint, @@ -470,11 +458,11 @@ where let mut out: f64 = 0.0; unsafe { let err_val = af_norm( - &mut out as MutDouble, - input.get() as AfArray, + &mut out as *mut c_double, + input.get(), ntype as c_uint, - p as c_double, - q as c_double, + p, + q, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -491,11 +479,11 @@ where /// /// Return a boolean indicating if ArrayFire was compiled with lapack support pub fn is_lapack_available() -> bool { - let mut temp: i32 = 0; + let mut temp: bool = false; unsafe { - af_is_lapack_available(&mut temp as *mut c_int); + af_is_lapack_available(&mut temp as *mut bool); } - temp > 0 // Return boolean fla + temp } /// Psuedo Inverse of Matrix @@ -519,15 +507,15 @@ pub fn pinverse(input: &Array, tolerance: f64, option: MatProp) -> Array c_int; fn af_convolve2_gradient_nn( - out: MutAfArray, - incoming_gradient: AfArray, - original_signal: AfArray, - original_filter: AfArray, - convolved_output: AfArray, + out: *mut af_array, + incoming_gradient: af_array, + original_signal: af_array, + original_filter: af_array, + convolved_output: af_array, stride_dims: c_uint, - strides: *const DimT, + strides: *const dim_t, padding_dims: c_uint, - paddings: *const DimT, + paddings: *const dim_t, dilation_dims: c_uint, - dilations: *const DimT, - grad_type: c_int, + dilations: *const dim_t, + grad_type: c_uint, ) -> c_int; } @@ -74,22 +70,22 @@ pub fn convolve2_nn( where T: HasAfEnum + RealFloating, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_convolve2_nn( - &mut temp as MutAfArray, - signal.get() as AfArray, - filter.get() as AfArray, + &mut temp as *mut af_array, + signal.get(), + filter.get(), strides.ndims() as c_uint, - strides.get().as_ptr() as *const c_longlong, + strides.get().as_ptr() as *const dim_t, padding.ndims() as c_uint, - padding.get().as_ptr() as *const c_longlong, + padding.get().as_ptr() as *const dim_t, dilation.ndims() as c_uint, - dilation.get().as_ptr() as *const c_longlong, + dilation.get().as_ptr() as *const dim_t, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Backward pass gradient of 2D convolution @@ -122,23 +118,23 @@ pub fn convolve2_gradient_nn( where T: HasAfEnum + RealFloating, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_convolve2_gradient_nn( - &mut temp as MutAfArray, - incoming_grad.get() as AfArray, - original_signal.get() as AfArray, - original_filter.get() as AfArray, - convolved_output.get() as AfArray, + &mut temp as *mut af_array, + incoming_grad.get(), + original_signal.get(), + original_filter.get(), + convolved_output.get(), strides.ndims() as c_uint, - strides.get().as_ptr() as *const c_longlong, + strides.get().as_ptr() as *const dim_t, padding.ndims() as c_uint, - padding.get().as_ptr() as *const c_longlong, + padding.get().as_ptr() as *const dim_t, dilation.ndims() as c_uint, - dilation.get().as_ptr() as *const c_longlong, - grad_type as c_int, + dilation.get().as_ptr() as *const dim_t, + grad_type as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } diff --git a/src/signal/mod.rs b/src/signal/mod.rs index e837917b7..e9eb27feb 100644 --- a/src/signal/mod.rs +++ b/src/signal/mod.rs @@ -1,179 +1,181 @@ -extern crate libc; -extern crate num; +use super::core::{ + af_array, dim_t, AfError, Array, ComplexFloating, ConvDomain, ConvMode, FloatingPoint, + HasAfEnum, InterpType, RealFloating, HANDLE_ERROR, +}; -use self::libc::{c_double, c_float, c_int, c_longlong, c_uint, size_t}; -use self::num::Complex; -use crate::array::Array; -use crate::defines::{AfError, ConvDomain, ConvMode, InterpType}; -use crate::error::HANDLE_ERROR; -use crate::util::{AfArray, MutAfArray}; -use crate::util::{ComplexFloating, FloatingPoint, HasAfEnum, RealFloating}; +use libc::{c_double, c_float, c_int, c_uint, size_t}; +use num::Complex; -#[allow(dead_code)] extern "C" { fn af_approx1( - out: MutAfArray, - inp: AfArray, - pos: AfArray, - method: c_int, + out: *mut af_array, + inp: af_array, + pos: af_array, + method: c_uint, off_grid: c_float, ) -> c_int; fn af_approx1_v2( - out: MutAfArray, - inp: AfArray, - pos: AfArray, - method: c_int, + out: *mut af_array, + inp: af_array, + pos: af_array, + method: c_uint, off_grid: c_float, ) -> c_int; fn af_approx1_uniform( - out: MutAfArray, - inp: AfArray, - pos: AfArray, + out: *mut af_array, + inp: af_array, + pos: af_array, interp_dim: c_int, idx_start: c_double, idx_step: c_double, - method: c_int, + method: c_uint, off_grid: c_float, ) -> c_int; fn af_approx1_uniform_v2( - out: MutAfArray, - inp: AfArray, - pos: AfArray, + out: *mut af_array, + inp: af_array, + pos: af_array, interp_dim: c_int, idx_start: c_double, idx_step: c_double, - method: c_int, + method: c_uint, off_grid: c_float, ) -> c_int; fn af_approx2( - out: MutAfArray, - inp: AfArray, - pos0: AfArray, - pos1: AfArray, - method: c_int, + out: *mut af_array, + inp: af_array, + pos0: af_array, + pos1: af_array, + method: c_uint, off_grid: c_float, ) -> c_int; fn af_approx2_v2( - out: MutAfArray, - inp: AfArray, - pos0: AfArray, - pos1: AfArray, - method: c_int, + out: *mut af_array, + inp: af_array, + pos0: af_array, + pos1: af_array, + method: c_uint, off_grid: c_float, ) -> c_int; fn af_approx2_uniform( - out: MutAfArray, - inp: AfArray, - pos0: AfArray, + out: *mut af_array, + inp: af_array, + pos0: af_array, interp_dim0: c_int, idx_start_dim0: c_double, idx_step_dim0: c_double, - pos1: AfArray, + pos1: af_array, interp_dim1: c_int, idx_start_dim1: c_double, idx_step_dim1: c_double, - method: c_int, + method: c_uint, off_grid: c_float, ) -> c_int; fn af_approx2_uniform_v2( - out: MutAfArray, - inp: AfArray, - pos0: AfArray, + out: *mut af_array, + inp: af_array, + pos0: af_array, interp_dim0: c_int, idx_start_dim0: c_double, idx_step_dim0: c_double, - pos1: AfArray, + pos1: af_array, interp_dim1: c_int, idx_start_dim1: c_double, idx_step_dim1: c_double, - method: c_int, + method: c_uint, 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; + fn af_fft(out: *mut af_array, arr: af_array, nfac: c_double, odim0: dim_t) -> c_int; fn af_fft2( - out: MutAfArray, - arr: AfArray, + out: *mut af_array, + arr: af_array, nfac: c_double, - odim0: c_longlong, - odim1: c_longlong, + odim0: dim_t, + odim1: dim_t, ) -> c_int; fn af_fft3( - out: MutAfArray, - arr: AfArray, + out: *mut af_array, + arr: af_array, nfac: c_double, - odim0: c_longlong, - odim1: c_longlong, - odim2: c_longlong, + odim0: dim_t, + odim1: dim_t, + odim2: dim_t, ) -> c_int; - fn af_ifft(out: MutAfArray, arr: AfArray, nfac: c_double, odim0: c_longlong) -> c_int; + fn af_ifft(out: *mut af_array, arr: af_array, nfac: c_double, odim0: dim_t) -> c_int; fn af_ifft2( - out: MutAfArray, - arr: AfArray, + out: *mut af_array, + arr: af_array, nfac: c_double, - odim0: c_longlong, - odim1: c_longlong, + odim0: dim_t, + odim1: dim_t, ) -> c_int; fn af_ifft3( - out: MutAfArray, - arr: AfArray, + out: *mut af_array, + arr: af_array, nfac: c_double, - odim0: c_longlong, - odim1: c_longlong, - odim2: c_longlong, + odim0: dim_t, + odim1: dim_t, + odim2: dim_t, ) -> c_int; - fn af_fft_inplace(arr: AfArray, nfac: c_double) -> c_int; - fn af_fft2_inplace(arr: AfArray, nfac: c_double) -> c_int; - fn af_fft3_inplace(arr: AfArray, nfac: c_double) -> c_int; - fn af_ifft_inplace(arr: AfArray, nfac: c_double) -> c_int; - fn af_ifft2_inplace(arr: AfArray, nfac: c_double) -> c_int; - fn af_ifft3_inplace(arr: AfArray, nfac: c_double) -> c_int; + fn af_fft_inplace(arr: *mut af_array, nfac: c_double) -> c_int; + fn af_fft2_inplace(arr: *mut af_array, nfac: c_double) -> c_int; + fn af_fft3_inplace(arr: *mut af_array, nfac: c_double) -> c_int; + fn af_ifft_inplace(arr: *mut af_array, nfac: c_double) -> c_int; + fn af_ifft2_inplace(arr: *mut af_array, nfac: c_double) -> c_int; + fn af_ifft3_inplace(arr: *mut af_array, nfac: c_double) -> c_int; - fn af_fft_r2c(out: MutAfArray, arr: AfArray, nfac: c_double, pad0: c_longlong) -> c_int; + fn af_fft_r2c(out: *mut af_array, arr: af_array, nfac: c_double, pad0: dim_t) -> c_int; fn af_fft2_r2c( - out: MutAfArray, - arr: AfArray, + out: *mut af_array, + arr: af_array, nfac: c_double, - pad0: c_longlong, - pad1: c_longlong, + pad0: dim_t, + pad1: dim_t, ) -> c_int; fn af_fft3_r2c( - out: MutAfArray, - arr: AfArray, + out: *mut af_array, + arr: af_array, nfac: c_double, - pad0: c_longlong, - pad1: c_longlong, - pad2: c_longlong, + pad0: dim_t, + pad1: dim_t, + pad2: dim_t, ) -> c_int; - fn af_fft_c2r(out: MutAfArray, input: AfArray, nfac: c_double, is_odd: c_int) -> c_int; - fn af_fft2_c2r(out: MutAfArray, input: AfArray, nfac: c_double, is_odd: c_int) -> c_int; - fn af_fft3_c2r(out: MutAfArray, input: AfArray, nfac: c_double, is_odd: c_int) -> c_int; + fn af_fft_c2r(out: *mut af_array, input: af_array, nfac: c_double, is_odd: bool) -> c_int; + fn af_fft2_c2r(out: *mut af_array, input: af_array, nfac: c_double, is_odd: bool) -> c_int; + fn af_fft3_c2r(out: *mut af_array, input: af_array, nfac: c_double, is_odd: bool) -> c_int; - fn af_convolve1(out: MutAfArray, s: AfArray, f: AfArray, m: c_uint, d: c_uint) -> c_int; - fn af_convolve2(out: MutAfArray, s: AfArray, f: AfArray, m: c_uint, d: c_uint) -> c_int; - fn af_convolve3(out: MutAfArray, s: AfArray, f: AfArray, m: c_uint, d: c_uint) -> c_int; - fn af_convolve2_sep(o: MutAfArray, c: AfArray, r: AfArray, s: AfArray, m: c_uint) -> c_int; - fn af_fft_convolve1(out: MutAfArray, s: AfArray, f: AfArray, m: c_uint) -> c_int; - fn af_fft_convolve2(out: MutAfArray, s: AfArray, f: AfArray, m: c_uint) -> c_int; - fn af_fft_convolve3(out: MutAfArray, s: AfArray, f: AfArray, m: c_uint) -> c_int; - fn af_fir(out: MutAfArray, b: AfArray, x: AfArray) -> c_int; - fn af_iir(out: MutAfArray, b: AfArray, a: AfArray, x: AfArray) -> c_int; + fn af_convolve1(out: *mut af_array, s: af_array, f: af_array, m: c_uint, d: c_uint) -> c_int; + fn af_convolve2(out: *mut af_array, s: af_array, f: af_array, m: c_uint, d: c_uint) -> c_int; + fn af_convolve3(out: *mut af_array, s: af_array, f: af_array, m: c_uint, d: c_uint) -> c_int; + fn af_convolve2_sep( + o: *mut af_array, + c: af_array, + r: af_array, + s: af_array, + m: c_uint, + ) -> c_int; + fn af_fft_convolve1(out: *mut af_array, s: af_array, f: af_array, m: c_uint) -> c_int; + fn af_fft_convolve2(out: *mut af_array, s: af_array, f: af_array, m: c_uint) -> c_int; + fn af_fft_convolve3(out: *mut af_array, s: af_array, f: af_array, m: c_uint) -> c_int; + fn af_fir(out: *mut af_array, b: af_array, x: af_array) -> c_int; + fn af_iir(out: *mut af_array, b: af_array, a: af_array, x: af_array) -> c_int; } /// Perform signal interpolation for 1d signals @@ -199,18 +201,18 @@ where T: HasAfEnum + FloatingPoint, P: HasAfEnum + RealFloating, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_approx1( - &mut temp as MutAfArray, - input.get() as AfArray, - pos.get() as AfArray, - method as c_int, - off_grid as c_float, + &mut temp as *mut af_array, + input.get(), + pos.get(), + method as c_uint, + off_grid, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Same as [approx1](./fn.approx1.html) but uses existing Array as output @@ -226,11 +228,11 @@ pub fn approx1_v2( { unsafe { let err_val = af_approx1_v2( - output.get() as MutAfArray, - input.get() as AfArray, - pos.get() as AfArray, - method as c_int, - off_grid as c_float, + output.get() as *mut af_array, + input.get(), + pos.get(), + method as c_uint, + off_grid, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -265,21 +267,21 @@ where T: HasAfEnum + FloatingPoint, P: HasAfEnum + RealFloating, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_approx1_uniform( - &mut temp as MutAfArray, - input.get() as AfArray, - pos.get() as AfArray, + &mut temp as *mut af_array, + input.get(), + pos.get(), interp_dim, start, step, - method as c_int, + method as c_uint, off_grid, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Same as [approx1_uniform](./fn.approx1_uniform.html) but uses existing Array as output @@ -299,13 +301,13 @@ pub fn approx1_uniform_v2( { unsafe { let err_val = af_approx1_uniform_v2( - output.get() as MutAfArray, - input.get() as AfArray, - pos.get() as AfArray, + output.get() as *mut af_array, + input.get(), + pos.get(), interp_dim, start, step, - method as c_int, + method as c_uint, off_grid, ); HANDLE_ERROR(AfError::from(err_val)); @@ -337,19 +339,19 @@ where T: HasAfEnum + FloatingPoint, P: HasAfEnum + RealFloating, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_approx2( - &mut temp as MutAfArray, - input.get() as AfArray, - pos0.get() as AfArray, - pos1.get() as AfArray, - method as c_int, - off_grid as c_float, + &mut temp as *mut af_array, + input.get(), + pos0.get(), + pos1.get(), + method as c_uint, + off_grid, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Same as [approx2](./fn.approx2.html) but uses existing Array as output @@ -366,12 +368,12 @@ pub fn approx2_v2( { unsafe { let err_val = af_approx2_v2( - output.get() as MutAfArray, - input.get() as AfArray, - pos0.get() as AfArray, - pos1.get() as AfArray, - method as c_int, - off_grid as c_float, + output.get() as *mut af_array, + input.get(), + pos0.get(), + pos1.get(), + method as c_uint, + off_grid, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -415,25 +417,25 @@ where T: HasAfEnum + FloatingPoint, P: HasAfEnum + RealFloating, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_approx2_uniform( - &mut temp as MutAfArray, - input.get() as AfArray, - pos0.get() as AfArray, + &mut temp as *mut af_array, + input.get(), + pos0.get(), interp_dim0, start0, step0, - pos1.get() as AfArray, + pos1.get(), interp_dim1, start1, step1, - method as c_int, - off_grid as c_float, + method as c_uint, + off_grid, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Same as [approx2_uniform](./fn.approx2_uniform.html) but uses existing Array as output @@ -457,18 +459,18 @@ pub fn approx2_uniform_v2( { unsafe { let err_val = af_approx2_uniform_v2( - output.get() as MutAfArray, - input.get() as AfArray, - pos0.get() as AfArray, + output.get() as *mut af_array, + input.get(), + pos0.get(), interp_dim0, start0, step0, - pos1.get() as AfArray, + pos1.get(), interp_dim1, start1, step1, - method as c_int, - off_grid as c_float, + method as c_uint, + off_grid, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -499,23 +501,17 @@ pub fn set_fft_plan_cache_size(cache_size: usize) { /// # Return Values /// /// Transformed Array -#[allow(unused_mut)] pub fn fft(input: &Array, norm_factor: f64, odim0: i64) -> Array where T: HasAfEnum + FloatingPoint, ::ComplexOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_fft( - &mut temp as MutAfArray, - input.get() as AfArray, - norm_factor as c_double, - odim0 as c_longlong, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_fft(&mut temp as *mut af_array, input.get(), norm_factor, odim0); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Fast fourier transform for 2d signals @@ -531,7 +527,6 @@ where /// # Return Values /// /// Transformed Array -#[allow(unused_mut)] pub fn fft2( input: &Array, norm_factor: f64, @@ -542,18 +537,18 @@ where T: HasAfEnum + FloatingPoint, ::ComplexOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_fft2( - &mut temp as MutAfArray, - input.get() as AfArray, - norm_factor as c_double, - odim0 as c_longlong, - odim1 as c_longlong, + &mut temp as *mut af_array, + input.get(), + norm_factor, + odim0, + odim1, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Fast fourier transform for 3d signals @@ -570,7 +565,6 @@ where /// # Return Values /// /// Transformed Array -#[allow(unused_mut)] pub fn fft3( input: &Array, norm_factor: f64, @@ -582,19 +576,19 @@ where T: HasAfEnum + FloatingPoint, ::ComplexOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_fft3( - &mut temp as MutAfArray, - input.get() as AfArray, - norm_factor as c_double, - odim0 as c_longlong, - odim1 as c_longlong, - odim2 as c_longlong, + &mut temp as *mut af_array, + input.get(), + norm_factor, + odim0, + odim1, + odim2, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Inverse fast fourier transform for 1d signals @@ -610,23 +604,17 @@ where /// # Return Values /// /// Transformed Array -#[allow(unused_mut)] pub fn ifft(input: &Array, norm_factor: f64, odim0: i64) -> Array where T: HasAfEnum + FloatingPoint, ::ComplexOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_ifft( - &mut temp as MutAfArray, - input.get() as AfArray, - norm_factor as c_double, - odim0 as c_longlong, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_ifft(&mut temp as *mut af_array, input.get(), norm_factor, odim0); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Inverse fast fourier transform for 2d signals @@ -642,7 +630,6 @@ where /// # Return Values /// /// Transformed Array -#[allow(unused_mut)] pub fn ifft2( input: &Array, norm_factor: f64, @@ -653,18 +640,18 @@ where T: HasAfEnum + FloatingPoint, ::ComplexOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_ifft2( - &mut temp as MutAfArray, - input.get() as AfArray, - norm_factor as c_double, - odim0 as c_longlong, - odim1 as c_longlong, + &mut temp as *mut af_array, + input.get(), + norm_factor, + odim0, + odim1, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Inverse fast fourier transform for 3d signals @@ -681,7 +668,6 @@ where /// # Return Values /// /// Transformed Array -#[allow(unused_mut)] pub fn ifft3( input: &Array, norm_factor: f64, @@ -693,19 +679,19 @@ where T: HasAfEnum + FloatingPoint, ::ComplexOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_ifft3( - &mut temp as MutAfArray, - input.get() as AfArray, - norm_factor as c_double, - odim0 as c_longlong, - odim1 as c_longlong, - odim2 as c_longlong, + &mut temp as *mut af_array, + input.get(), + norm_factor, + odim0, + odim1, + odim2, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } macro_rules! conv_func_def { @@ -724,7 +710,6 @@ macro_rules! conv_func_def { ///# Return Values /// /// Convolved Array - #[allow(unused_mut)] pub fn $fn_name( signal: &Array, filter: &Array, @@ -735,18 +720,18 @@ macro_rules! conv_func_def { T: HasAfEnum, F: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = $ffi_name( - &mut temp as MutAfArray, - signal.get() as AfArray, - filter.get() as AfArray, + &mut temp as *mut af_array, + signal.get(), + filter.get(), mode as c_uint, domain as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } }; } @@ -767,7 +752,6 @@ conv_func_def!("3d convolution", convolve3, af_convolve3); /// # Return Values /// /// The convolved Array -#[allow(unused_mut)] pub fn convolve2_sep( cfilt: &Array, rfilt: &Array, @@ -778,18 +762,18 @@ where T: HasAfEnum, F: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_convolve2_sep( - &mut temp as MutAfArray, - cfilt.get() as AfArray, - rfilt.get() as AfArray, - signal.get() as AfArray, + &mut temp as *mut af_array, + cfilt.get(), + rfilt.get(), + signal.get(), mode as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } macro_rules! fft_conv_func_def { @@ -806,23 +790,18 @@ macro_rules! fft_conv_func_def { ///# Return Values /// /// Convolved Array - #[allow(unused_mut)] pub fn $fn_name(signal: &Array, filter: &Array, mode: ConvMode) -> Array where T: HasAfEnum, F: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = $ffi_name( - &mut temp as MutAfArray, - signal.get() as AfArray, - filter.get() as AfArray, - mode as c_uint, - ); + &mut temp as *mut af_array, signal.get(), filter.get(), mode as c_uint); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } }; } @@ -853,22 +832,17 @@ fft_conv_func_def!( /// # Return Values /// /// Filtered Array -#[allow(unused_mut)] pub fn fir(b: &Array, x: &Array) -> Array where B: HasAfEnum, X: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_fir( - &mut temp as MutAfArray, - b.get() as AfArray, - x.get() as AfArray, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_fir(&mut temp as *mut af_array, b.get(), x.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Infinite impulse response filter @@ -882,19 +856,13 @@ where /// # Return Values /// /// Filtered Array -#[allow(unused_mut)] pub fn iir(b: &Array, a: &Array, x: &Array) -> Array { - let mut temp: i64 = 0; unsafe { - let err_val = af_iir( - &mut temp as MutAfArray, - b.get() as AfArray, - a.get() as AfArray, - x.get() as AfArray, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_iir(&mut temp as *mut af_array, b.get(), a.get(), x.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// In place 1d dimensional Fast fourier transform @@ -908,7 +876,7 @@ where T: HasAfEnum + ComplexFloating, { unsafe { - let err_val = af_fft_inplace(input.get() as AfArray, norm_factor as c_double); + let err_val = af_fft_inplace(input.get() as *mut af_array, norm_factor); HANDLE_ERROR(AfError::from(err_val)); } } @@ -924,7 +892,7 @@ where T: HasAfEnum + ComplexFloating, { unsafe { - let err_val = af_fft2_inplace(input.get() as AfArray, norm_factor as c_double); + let err_val = af_fft2_inplace(input.get() as *mut af_array, norm_factor); HANDLE_ERROR(AfError::from(err_val)); } } @@ -940,7 +908,7 @@ where T: HasAfEnum + ComplexFloating, { unsafe { - let err_val = af_fft3_inplace(input.get() as AfArray, norm_factor as c_double); + let err_val = af_fft3_inplace(input.get() as *mut af_array, norm_factor); HANDLE_ERROR(AfError::from(err_val)); } } @@ -956,7 +924,7 @@ where T: HasAfEnum + ComplexFloating, { unsafe { - let err_val = af_ifft_inplace(input.get() as AfArray, norm_factor as c_double); + let err_val = af_ifft_inplace(input.get() as *mut af_array, norm_factor); HANDLE_ERROR(AfError::from(err_val)); } } @@ -972,7 +940,7 @@ where T: HasAfEnum + ComplexFloating, { unsafe { - let err_val = af_ifft2_inplace(input.get() as AfArray, norm_factor as c_double); + let err_val = af_ifft2_inplace(input.get() as *mut af_array, norm_factor); HANDLE_ERROR(AfError::from(err_val)); } } @@ -988,7 +956,7 @@ where T: HasAfEnum + ComplexFloating, { unsafe { - let err_val = af_ifft3_inplace(input.get() as AfArray, norm_factor as c_double); + let err_val = af_ifft3_inplace(input.get() as *mut af_array, norm_factor); HANDLE_ERROR(AfError::from(err_val)); } } @@ -1009,17 +977,12 @@ where T: HasAfEnum + RealFloating, Complex: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_fft_r2c( - &mut temp as MutAfArray, - input.get() as AfArray, - norm_factor as c_double, - pad0 as c_longlong, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_fft_r2c(&mut temp as *mut af_array, input.get(), norm_factor, pad0); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// 2d Real to Complex fast fourier transform @@ -1039,18 +1002,18 @@ where T: HasAfEnum + RealFloating, Complex: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_fft2_r2c( - &mut temp as MutAfArray, - input.get() as AfArray, - norm_factor as c_double, - pad0 as c_longlong, - pad1 as c_longlong, + &mut temp as *mut af_array, + input.get(), + norm_factor, + pad0, + pad1, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// 3d Real to Complex fast fourier transform @@ -1077,19 +1040,19 @@ where T: HasAfEnum + RealFloating, Complex: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_fft3_r2c( - &mut temp as MutAfArray, - input.get() as AfArray, - norm_factor as c_double, - pad0 as c_longlong, - pad1 as c_longlong, - pad2 as c_longlong, + &mut temp as *mut af_array, + input.get(), + norm_factor, + pad0, + pad1, + pad2, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// 1d Complex to Real fast fourier transform @@ -1108,17 +1071,12 @@ where T: HasAfEnum + ComplexFloating, ::BaseType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_fft_c2r( - &mut temp as MutAfArray, - input.get() as AfArray, - norm_factor as c_double, - is_odd as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_fft_c2r(&mut temp as *mut af_array, input.get(), norm_factor, is_odd); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// 2d Complex to Real fast fourier transform @@ -1137,17 +1095,12 @@ where T: HasAfEnum + ComplexFloating, ::BaseType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_fft2_c2r( - &mut temp as MutAfArray, - input.get() as AfArray, - norm_factor as c_double, - is_odd as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_fft2_c2r(&mut temp as *mut af_array, input.get(), norm_factor, is_odd); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// 3d Complex to Real fast fourier transform @@ -1166,15 +1119,10 @@ where T: HasAfEnum + ComplexFloating, ::BaseType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_fft3_c2r( - &mut temp as MutAfArray, - input.get() as AfArray, - norm_factor as c_double, - is_odd as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_fft3_c2r(&mut temp as *mut af_array, input.get(), norm_factor, is_odd); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } diff --git a/src/sparse/mod.rs b/src/sparse/mod.rs index f85bdc205..edd2d5860 100644 --- a/src/sparse/mod.rs +++ b/src/sparse/mod.rs @@ -1,29 +1,25 @@ -extern crate libc; +use super::core::{ + af_array, dim_t, AfError, Array, FloatingPoint, HasAfEnum, SparseFormat, HANDLE_ERROR, +}; -use self::libc::{c_int, c_uint, c_void}; -use crate::array::Array; -use crate::defines::{AfError, SparseFormat}; -use crate::error::HANDLE_ERROR; -use crate::util::{AfArray, DimT, MutAfArray, MutDimT}; -use crate::util::{FloatingPoint, HasAfEnum}; +use libc::{c_int, c_uint, c_void}; -#[allow(dead_code)] extern "C" { fn af_create_sparse_array( - out: MutAfArray, - nRows: DimT, - nCols: DimT, - vals: AfArray, - rowIdx: AfArray, - colIdx: AfArray, + out: *mut af_array, + nRows: dim_t, + nCols: dim_t, + vals: af_array, + rowIdx: af_array, + colIdx: af_array, stype: c_uint, ) -> c_int; fn af_create_sparse_array_from_ptr( - out: MutAfArray, - nRows: DimT, - nCols: DimT, - nNZ: DimT, + out: *mut af_array, + nRows: dim_t, + nCols: dim_t, + nNZ: dim_t, values: *const c_void, rowIdx: *const c_int, colIdx: *const c_int, @@ -32,29 +28,33 @@ extern "C" { src: c_uint, ) -> c_int; - fn af_create_sparse_array_from_dense(out: MutAfArray, dense: AfArray, stype: c_uint) -> c_int; + fn af_create_sparse_array_from_dense( + out: *mut af_array, + dense: af_array, + stype: c_uint, + ) -> c_int; - fn af_sparse_convert_to(out: MutAfArray, input: AfArray, dstStrge: c_uint) -> c_int; + fn af_sparse_convert_to(out: *mut af_array, input: af_array, dstStrge: c_uint) -> c_int; - fn af_sparse_to_dense(out: MutAfArray, sparse: AfArray) -> c_int; + fn af_sparse_to_dense(out: *mut af_array, sparse: af_array) -> c_int; fn af_sparse_get_info( - vals: MutAfArray, - rIdx: MutAfArray, - cIdx: MutAfArray, + vals: *mut af_array, + rIdx: *mut af_array, + cIdx: *mut af_array, stype: *mut c_uint, - input: AfArray, + input: af_array, ) -> c_int; - fn af_sparse_get_values(out: MutAfArray, input: AfArray) -> c_int; + fn af_sparse_get_values(out: *mut af_array, input: af_array) -> c_int; - fn af_sparse_get_row_idx(out: MutAfArray, input: AfArray) -> c_int; + fn af_sparse_get_row_idx(out: *mut af_array, input: af_array) -> c_int; - fn af_sparse_get_col_idx(out: MutAfArray, input: AfArray) -> c_int; + fn af_sparse_get_col_idx(out: *mut af_array, input: af_array) -> c_int; - fn af_sparse_get_nnz(out: MutDimT, input: AfArray) -> c_int; + fn af_sparse_get_nnz(out: *mut dim_t, input: af_array) -> c_int; - fn af_sparse_get_storage(out: *mut c_uint, input: AfArray) -> c_int; + fn af_sparse_get_storage(out: *mut c_uint, input: af_array) -> c_int; } /// Create sprase matrix from arrays @@ -91,20 +91,20 @@ pub fn sparse( where T: HasAfEnum + FloatingPoint, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); 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, + &mut temp as *mut af_array, + rows as dim_t, + cols as dim_t, + values.get(), + row_indices.get(), + col_indices.get(), format as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Create sprase matrix from data on host memory @@ -144,13 +144,13 @@ where T: HasAfEnum + FloatingPoint, { let aftype = T::get_af_dtype(); - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_create_sparse_array_from_ptr( - &mut temp as MutAfArray, - rows as DimT, - cols as DimT, - nzz as DimT, + &mut temp as *mut af_array, + rows as dim_t, + cols as dim_t, + nzz as dim_t, values.as_ptr() as *const c_void, row_indices.as_ptr() as *const c_int, col_indices.as_ptr() as *const c_int, @@ -159,8 +159,8 @@ where 1, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Convert dense array to sparse array @@ -177,16 +177,16 @@ pub fn sparse_from_dense(dense: &Array, format: SparseFormat) -> Array where T: HasAfEnum + FloatingPoint, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_create_sparse_array_from_dense( - &mut temp as MutAfArray, - dense.get() as AfArray, + &mut temp as *mut af_array, + dense.get(), format as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Convert between sparse formats @@ -203,16 +203,13 @@ pub fn sparse_convert_to(input: &Array, format: SparseFormat) -> Array where T: HasAfEnum + FloatingPoint, { - let mut temp: i64 = 0; unsafe { - let err_val = af_sparse_convert_to( - &mut temp as MutAfArray, - input.get() as AfArray, - format as c_uint, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = + af_sparse_convert_to(&mut temp as *mut af_array, input.get(), format as c_uint); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Convert sparse array to dense array @@ -228,12 +225,12 @@ pub fn sparse_to_dense(input: &Array) -> Array where T: HasAfEnum + FloatingPoint, { - let mut temp: i64 = 0; unsafe { - let err_val = af_sparse_to_dense(&mut temp as MutAfArray, input.get() as AfArray); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_sparse_to_dense(&mut temp as *mut af_array, input.get()); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Get sparse Array information @@ -249,26 +246,26 @@ pub fn sparse_get_info(input: &Array) -> (Array, Array, Array where T: HasAfEnum + FloatingPoint, { - let mut val: i64 = 0; - let mut row: i64 = 0; - let mut col: i64 = 0; - let mut stype: u32 = 0; unsafe { + let mut val: af_array = std::ptr::null_mut(); + let mut row: af_array = std::ptr::null_mut(); + let mut col: af_array = std::ptr::null_mut(); + let mut stype: u32 = 0; let err_val = af_sparse_get_info( - &mut val as MutAfArray, - &mut row as MutAfArray, - &mut col as MutAfArray, + &mut val as *mut af_array, + &mut row as *mut af_array, + &mut col as *mut af_array, &mut stype as *mut c_uint, - input.get() as AfArray, + input.get(), ); HANDLE_ERROR(AfError::from(err_val)); + ( + val.into(), + row.into(), + col.into(), + SparseFormat::from(stype), + ) } - ( - val.into(), - row.into(), - col.into(), - SparseFormat::from(stype), - ) } /// Get values of sparse Array @@ -284,12 +281,12 @@ pub fn sparse_get_values(input: &Array) -> Array where T: HasAfEnum + FloatingPoint, { - let mut val: i64 = 0; unsafe { - let err_val = af_sparse_get_values(&mut val as MutAfArray, input.get() as AfArray); + let mut val: af_array = std::ptr::null_mut(); + let err_val = af_sparse_get_values(&mut val as *mut af_array, input.get()); HANDLE_ERROR(AfError::from(err_val)); + val.into() } - val.into() } /// Get row indices Array @@ -305,12 +302,12 @@ pub fn sparse_get_row_indices(input: &Array) -> Array where T: HasAfEnum + FloatingPoint, { - let mut val: i64 = 0; unsafe { - let err_val = af_sparse_get_row_idx(&mut val as MutAfArray, input.get() as AfArray); + let mut val: af_array = std::ptr::null_mut(); + let err_val = af_sparse_get_row_idx(&mut val as *mut af_array, input.get()); HANDLE_ERROR(AfError::from(err_val)); + val.into() } - val.into() } /// Get cololumn indices Array @@ -326,12 +323,12 @@ pub fn sparse_get_col_indices(input: &Array) -> Array where T: HasAfEnum + FloatingPoint, { - let mut val: i64 = 0; unsafe { - let err_val = af_sparse_get_col_idx(&mut val as MutAfArray, input.get() as AfArray); + let mut val: af_array = std::ptr::null_mut(); + let err_val = af_sparse_get_col_idx(&mut val as *mut af_array, input.get()); HANDLE_ERROR(AfError::from(err_val)); + val.into() } - val.into() } /// Get number of non-zero elements in sparse array @@ -346,7 +343,7 @@ where pub fn sparse_get_nnz(input: &Array) -> i64 { let mut count: i64 = 0; unsafe { - let err_val = af_sparse_get_nnz(&mut count as *mut DimT, input.get() as AfArray); + let err_val = af_sparse_get_nnz(&mut count as *mut dim_t, input.get()); HANDLE_ERROR(AfError::from(err_val)); } count @@ -364,7 +361,7 @@ pub fn sparse_get_nnz(input: &Array) -> i64 { pub fn sparse_get_format(input: &Array) -> SparseFormat { let mut stype: u32 = 0; unsafe { - let err_val = af_sparse_get_storage(&mut stype as *mut c_uint, input.get() as AfArray); + let err_val = af_sparse_get_storage(&mut stype as *mut c_uint, input.get()); HANDLE_ERROR(AfError::from(err_val)); } SparseFormat::from(stype) diff --git a/src/statistics/mod.rs b/src/statistics/mod.rs index d20a7d8cf..0cc1ee5a7 100644 --- a/src/statistics/mod.rs +++ b/src/statistics/mod.rs @@ -1,50 +1,57 @@ -extern crate libc; +use super::core::{ + af_array, dim_t, AfError, Array, CovarianceComputable, HasAfEnum, MedianComputable, + RealFloating, RealNumber, TopkFn, VarianceBias, HANDLE_ERROR, +}; -use self::libc::{c_int, c_uint}; -use crate::array::Array; -use crate::defines::{AfError, TopkFn, VarianceBias}; -use crate::error::HANDLE_ERROR; -use crate::util::{AfArray, DimT, MutAfArray, MutDouble}; -use crate::util::{CovarianceComputable, RealNumber}; -use crate::util::{HasAfEnum, MedianComputable, RealFloating}; +use libc::{c_double, c_int, c_uint}; -#[allow(dead_code)] extern "C" { - fn af_mean(out: MutAfArray, arr: AfArray, dim: DimT) -> c_int; - fn af_stdev(out: MutAfArray, arr: AfArray, dim: DimT) -> c_int; - fn af_median(out: MutAfArray, arr: AfArray, dim: DimT) -> c_int; + fn af_mean(out: *mut af_array, arr: af_array, dim: dim_t) -> c_int; + fn af_stdev(out: *mut af_array, arr: af_array, dim: dim_t) -> c_int; + fn af_median(out: *mut af_array, arr: af_array, dim: dim_t) -> c_int; - fn af_mean_weighted(out: MutAfArray, arr: AfArray, wts: AfArray, dim: DimT) -> c_int; - fn af_var_weighted(out: MutAfArray, arr: AfArray, wts: AfArray, dim: DimT) -> c_int; + fn af_mean_weighted(out: *mut af_array, arr: af_array, wts: af_array, dim: dim_t) -> c_int; + fn af_var_weighted(out: *mut af_array, arr: af_array, wts: af_array, dim: dim_t) -> c_int; - fn af_var(out: MutAfArray, arr: AfArray, isbiased: c_int, dim: DimT) -> c_int; - fn af_cov(out: MutAfArray, X: AfArray, Y: AfArray, isbiased: c_int) -> c_int; - fn af_var_all(real: MutDouble, imag: MutDouble, arr: AfArray, isbiased: c_int) -> c_int; + fn af_var(out: *mut af_array, arr: af_array, isbiased: bool, dim: dim_t) -> c_int; + fn af_cov(out: *mut af_array, X: af_array, Y: af_array, isbiased: bool) -> c_int; + fn af_var_all(real: *mut c_double, imag: *mut c_double, arr: af_array, isbiased: bool) + -> c_int; - fn af_mean_all(real: MutDouble, imag: MutDouble, arr: AfArray) -> c_int; - fn af_stdev_all(real: MutDouble, imag: MutDouble, arr: AfArray) -> c_int; - fn af_median_all(real: MutDouble, imag: MutDouble, arr: AfArray) -> c_int; + fn af_mean_all(real: *mut c_double, imag: *mut c_double, arr: af_array) -> c_int; + fn af_stdev_all(real: *mut c_double, imag: *mut c_double, arr: af_array) -> c_int; + fn af_median_all(real: *mut c_double, imag: *mut c_double, arr: af_array) -> c_int; - fn af_mean_all_weighted(real: MutDouble, imag: MutDouble, arr: AfArray, wts: AfArray) -> c_int; - fn af_var_all_weighted(real: MutDouble, imag: MutDouble, arr: AfArray, wts: AfArray) -> c_int; + fn af_mean_all_weighted( + real: *mut c_double, + imag: *mut c_double, + arr: af_array, + wts: af_array, + ) -> c_int; + fn af_var_all_weighted( + real: *mut c_double, + imag: *mut c_double, + arr: af_array, + wts: af_array, + ) -> c_int; - fn af_corrcoef(real: MutDouble, imag: MutDouble, X: AfArray, Y: AfArray) -> c_int; + fn af_corrcoef(real: *mut c_double, imag: *mut c_double, X: af_array, Y: af_array) -> c_int; fn af_topk( - vals: MutAfArray, - idxs: MutAfArray, - arr: AfArray, + vals: *mut af_array, + idxs: *mut af_array, + arr: af_array, k: c_int, dim: c_int, order: c_uint, ) -> c_int; fn af_meanvar( - mean: MutAfArray, - var: MutAfArray, - input: AfArray, - weights: AfArray, - bias: c_int, - dim: DimT, + mean: *mut af_array, + var: *mut af_array, + input: af_array, + weights: af_array, + bias: c_uint, + dim: dim_t, ) -> c_int; } @@ -59,17 +66,16 @@ extern "C" { /// /// An Array whose size is equal to input except along the dimension which /// median needs to be found. Array size along `dim` will be reduced to one. -#[allow(unused_mut)] pub fn median(input: &Array, dim: i64) -> Array where T: HasAfEnum + MedianComputable, { - let mut temp: i64 = 0; unsafe { - let err_val = af_median(&mut temp as MutAfArray, input.get() as AfArray, dim as DimT); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_median(&mut temp as *mut af_array, input.get(), dim); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } macro_rules! stat_func_def { @@ -85,18 +91,17 @@ macro_rules! stat_func_def { /// /// 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 where T: HasAfEnum, T::MeanOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = $ffi_fn(&mut temp as MutAfArray, input.get() as AfArray, dim as DimT); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = $ffi_fn(&mut temp as *mut af_array, input.get(), dim); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } }; } @@ -122,7 +127,6 @@ macro_rules! stat_wtd_func_def { /// /// 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, @@ -133,17 +137,12 @@ macro_rules! stat_wtd_func_def { T::MeanOutType: HasAfEnum, W: HasAfEnum + RealFloating, { - let mut temp: i64 = 0; unsafe { - let err_val = $ffi_fn( - &mut temp as MutAfArray, - input.get() as AfArray, - weights.get() as AfArray, - dim as DimT, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = $ffi_fn(&mut temp as *mut af_array,input.get(), weights.get(), dim); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } }; } @@ -170,23 +169,17 @@ stat_wtd_func_def!( /// # Return Values /// /// Array with variance of input Array `arr` along dimension `dim`. -#[allow(unused_mut)] pub fn var(arr: &Array, isbiased: bool, dim: i64) -> Array where T: HasAfEnum, T::MeanOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_var( - &mut temp as MutAfArray, - arr.get() as AfArray, - isbiased as c_int, - dim as DimT, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_var(&mut temp as *mut af_array, arr.get(), isbiased, dim); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Compute covariance of two Arrays @@ -200,23 +193,17 @@ where /// # Return Values /// /// An Array with Covariance values -#[allow(unused_mut)] pub fn cov(x: &Array, y: &Array, isbiased: bool) -> Array where T: HasAfEnum + CovarianceComputable, T::MeanOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_cov( - &mut temp as MutAfArray, - x.get() as AfArray, - y.get() as AfArray, - isbiased as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_cov(&mut temp as *mut af_array, x.get(), y.get(), isbiased); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Compute Variance of all elements @@ -229,16 +216,15 @@ where /// # Return Values /// /// A tuple of 64-bit floating point values that has the variance of `input` Array. -#[allow(unused_mut)] pub fn var_all(input: &Array, isbiased: bool) -> (f64, f64) { let mut real: f64 = 0.0; let mut imag: f64 = 0.0; unsafe { let err_val = af_var_all( - &mut real as MutDouble, - &mut imag as MutDouble, - input.get() as AfArray, - isbiased as c_int, + &mut real as *mut c_double, + &mut imag as *mut c_double, + input.get(), + isbiased, ); HANDLE_ERROR(AfError::from(err_val)); } @@ -256,15 +242,14 @@ macro_rules! stat_all_func_def { ///# Return Values /// /// A tuple of 64-bit floating point values with the stat values. - #[allow(unused_mut)] pub fn $fn_name(input: &Array) -> (f64, f64) { let mut real: f64 = 0.0; let mut imag: f64 = 0.0; unsafe { let err_val = $ffi_fn( - &mut real as MutDouble, - &mut imag as MutDouble, - input.get() as AfArray, + &mut real as *mut c_double, + &mut imag as *mut c_double, + input.get(), ); HANDLE_ERROR(AfError::from(err_val)); } @@ -289,7 +274,6 @@ stat_all_func_def!( ///# Return Values /// /// A tuple of 64-bit floating point values with the median -#[allow(unused_mut)] pub fn median_all(input: &Array) -> (f64, f64) where T: HasAfEnum + MedianComputable, @@ -298,9 +282,9 @@ where let mut imag: f64 = 0.0; unsafe { let err_val = af_median_all( - &mut real as MutDouble, - &mut imag as MutDouble, - input.get() as AfArray, + &mut real as *mut c_double, + &mut imag as *mut c_double, + input.get(), ); HANDLE_ERROR(AfError::from(err_val)); } @@ -319,7 +303,6 @@ macro_rules! stat_wtd_all_func_def { ///# Return Values /// /// A tuple of 64-bit floating point values with the stat values. - #[allow(unused_mut)] pub fn $fn_name(input: &Array, weights: &Array) -> (f64, f64) where T: HasAfEnum, @@ -329,10 +312,10 @@ macro_rules! stat_wtd_all_func_def { let mut imag: f64 = 0.0; unsafe { let err_val = $ffi_fn( - &mut real as MutDouble, - &mut imag as MutDouble, - input.get() as AfArray, - weights.get() as AfArray, + &mut real as *mut c_double, + &mut imag as *mut c_double, + input.get(), + weights.get(), ); HANDLE_ERROR(AfError::from(err_val)); } @@ -361,7 +344,6 @@ stat_wtd_all_func_def!( /// /// # Return Values /// A tuple of 64-bit floating point values with the coefficients. -#[allow(unused_mut)] pub fn corrcoef(x: &Array, y: &Array) -> (f64, f64) where T: HasAfEnum + RealNumber, @@ -370,10 +352,10 @@ where let mut imag: f64 = 0.0; unsafe { let err_val = af_corrcoef( - &mut real as MutDouble, - &mut imag as MutDouble, - x.get() as AfArray, - y.get() as AfArray, + &mut real as *mut c_double, + &mut imag as *mut c_double, + x.get(), + y.get(), ); HANDLE_ERROR(AfError::from(err_val)); } @@ -407,20 +389,20 @@ pub fn topk(input: &Array, k: u32, dim: i32, order: TopkFn) -> (Array, where T: HasAfEnum, { - let mut t0: i64 = 0; - let mut t1: i64 = 0; unsafe { + let mut t0: af_array = std::ptr::null_mut(); + let mut t1: af_array = std::ptr::null_mut(); let err_val = af_topk( - &mut t0 as MutAfArray, - &mut t1 as MutAfArray, - input.get() as AfArray, + &mut t0 as *mut af_array, + &mut t1 as *mut af_array, + input.get(), k as c_int, dim as c_int, order as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + (t0.into(), t1.into()) } - (t0.into(), t1.into()) } /// Calculate mean and variance in single API call @@ -450,18 +432,18 @@ where T::MeanOutType: HasAfEnum, W: HasAfEnum + RealFloating, { - let mut mean: i64 = 0; - let mut var: i64 = 0; unsafe { + let mut mean: af_array = std::ptr::null_mut(); + let mut var: af_array = std::ptr::null_mut(); let err_val = af_meanvar( - &mut mean as MutAfArray, - &mut var as MutAfArray, - input.get() as AfArray, - weights.get() as AfArray, - bias as c_int, - dim as DimT, + &mut mean as *mut af_array, + &mut var as *mut af_array, + input.get(), + weights.get(), + bias as c_uint, + dim, ); HANDLE_ERROR(AfError::from(err_val)); + (mean.into(), var.into()) } - (mean.into(), var.into()) } diff --git a/src/vision/mod.rs b/src/vision/mod.rs index d72602b0c..484a710fb 100644 --- a/src/vision/mod.rs +++ b/src/vision/mod.rs @@ -1,41 +1,38 @@ -extern crate libc; +use super::core::{ + af_array, af_features, dim_t, AfError, Array, HasAfEnum, HomographyType, ImageFilterType, + MatchType, RealFloating, HANDLE_ERROR, +}; -use self::libc::{c_double, c_float, c_int, c_longlong, c_uint, c_void}; -use crate::array::Array; -use crate::defines::{AfError, HomographyType, MatchType}; -use crate::error::HANDLE_ERROR; -use crate::util::{AfArray, DimT, Feat, MutAfArray, MutFeat}; -use crate::util::{HasAfEnum, ImageFilterType, RealFloating}; +use libc::{c_float, c_int, c_uint}; use std::mem; // af_sift and af_gloh uses patented algorithms, so didn't add them -// they are built using installer builds +// they are NOT built using installer builds -#[allow(dead_code)] extern "C" { - fn af_create_features(feat: MutFeat, num: DimT) -> c_int; - fn af_retain_features(feat: MutFeat, feat: Feat) -> c_int; - fn af_get_features_num(num: *mut DimT, feat: Feat) -> c_int; - fn af_get_features_xpos(out: MutAfArray, feat: Feat) -> c_int; - fn af_get_features_ypos(out: MutAfArray, feat: Feat) -> c_int; - fn af_get_features_score(out: MutAfArray, feat: Feat) -> c_int; - fn af_get_features_orientation(out: MutAfArray, feat: Feat) -> c_int; - fn af_get_features_size(out: MutAfArray, feat: Feat) -> c_int; - fn af_release_features(feat: *mut c_void) -> c_int; + fn af_create_features(feat: *mut af_features, num: dim_t) -> c_int; + fn af_retain_features(feat: *mut af_features, feat: af_features) -> c_int; + fn af_get_features_num(num: *mut dim_t, feat: af_features) -> c_int; + fn af_get_features_xpos(out: *mut af_array, feat: af_features) -> c_int; + fn af_get_features_ypos(out: *mut af_array, feat: af_features) -> c_int; + fn af_get_features_score(out: *mut af_array, feat: af_features) -> c_int; + fn af_get_features_orientation(out: *mut af_array, feat: af_features) -> c_int; + fn af_get_features_size(out: *mut af_array, feat: af_features) -> c_int; + fn af_release_features(feat: af_features) -> c_int; fn af_fast( - out: MutFeat, - input: AfArray, + out: *mut af_features, + input: af_array, thr: c_float, arc_len: c_uint, - non_max: c_int, + non_max: bool, feature_ratio: c_float, edge: c_uint, ) -> c_int; fn af_harris( - out: MutFeat, - input: AfArray, + out: *mut af_features, + input: af_array, m: c_uint, r: c_float, s: c_float, @@ -44,45 +41,45 @@ extern "C" { ) -> c_int; fn af_orb( - out: MutFeat, - desc: MutAfArray, - arr: AfArray, + out: *mut af_features, + desc: *mut af_array, + arr: af_array, fast_thr: c_float, max_feat: c_uint, scl_fctr: c_float, levels: c_uint, - blur_img: c_int, + blur_img: bool, ) -> c_int; fn af_hamming_matcher( - idx: MutAfArray, - dist: MutAfArray, - query: AfArray, - train: AfArray, - dist_dim: DimT, + idx: *mut af_array, + dist: *mut af_array, + query: af_array, + train: af_array, + dist_dim: dim_t, n_dist: c_uint, ) -> c_int; fn af_nearest_neighbour( - idx: MutAfArray, - dist: MutAfArray, - q: AfArray, - t: AfArray, - dist_dim: DimT, + idx: *mut af_array, + dist: *mut af_array, + q: af_array, + t: af_array, + dist_dim: dim_t, n_dist: c_uint, dist_type: c_int, ) -> c_int; fn af_match_template( - out: MutAfArray, - search_img: AfArray, - template_img: AfArray, + out: *mut af_array, + search_img: af_array, + template_img: af_array, mtype: c_uint, ) -> c_int; fn af_susan( - feat: MutFeat, - i: AfArray, + feat: *mut af_features, + i: af_array, r: c_uint, d: c_float, g: c_float, @@ -90,32 +87,19 @@ extern "C" { e: c_uint, ) -> c_int; - fn af_dog(out: MutAfArray, i: AfArray, r1: c_int, r2: c_int) -> c_int; + fn af_dog(out: *mut af_array, i: af_array, r1: c_int, r2: c_int) -> c_int; fn af_homography( - H: MutAfArray, + H: *mut af_array, inliers: *mut c_int, - x_src: AfArray, - y_src: AfArray, - x_dst: AfArray, - y_dst: AfArray, - htype: c_int, + x_src: af_array, + y_src: af_array, + x_dst: af_array, + y_dst: af_array, + htype: c_uint, inlier_thr: c_float, iterations: c_uint, - otype: c_int, - ) -> c_int; - - fn af_gloh( - out: MutFeat, - desc: MutAfArray, - input: AfArray, - n_layers: c_uint, - contrast_thr: c_float, - edge_thr: c_float, - init_sigma: c_float, - double_input: c_double, - intensity_scale: c_float, - feature_ratio: c_float, + otype: c_uint, ) -> c_int; } @@ -131,7 +115,7 @@ extern "C" { /// - Orientations of the features /// - Sizes of the features pub struct Features { - feat: i64, + feat: af_features, } macro_rules! feat_func_def { @@ -139,14 +123,14 @@ macro_rules! feat_func_def { #[doc=$doc_str] pub fn $fn_name(&self) -> Array { unsafe { - let mut temp: i64 = 0; - let err_val = $ffi_name(&mut temp as MutAfArray, self.feat as Feat); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = $ffi_name(&mut temp as *mut af_array, self.feat); + HANDLE_ERROR(AfError::from(err_val)); let temp_array: Array = temp.into(); let retained = temp_array.clone(); mem::forget(temp_array); - HANDLE_ERROR(AfError::from(err_val)); retained } } @@ -157,11 +141,10 @@ 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) -> Self { unsafe { - let mut temp: i64 = 0; - let err_val = af_create_features(&mut temp as *mut c_longlong as MutFeat, n as DimT); + let mut temp: af_features = std::ptr::null_mut(); + let err_val = af_create_features(&mut temp as *mut af_features, n as dim_t); HANDLE_ERROR(AfError::from(err_val)); Self { feat: temp } } @@ -169,15 +152,15 @@ impl Features { /// Get total number of features found pub fn num_features(&self) -> i64 { + let mut temp: i64 = 0; unsafe { - let mut temp: i64 = 0; let err_val = af_get_features_num( - &mut temp as *mut DimT, - self.feat as *const c_longlong as Feat, + &mut temp as *mut dim_t, + self.feat as *const dim_t as af_features, ); HANDLE_ERROR(AfError::from(err_val)); - temp } + temp } feat_func_def!("Get x coordinates Array", xpos, af_get_features_xpos); @@ -191,7 +174,7 @@ impl Features { 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 { + pub unsafe fn get(&self) -> af_features { self.feat } } @@ -199,11 +182,8 @@ impl Features { impl Clone for Features { fn clone(&self) -> Self { unsafe { - let mut temp: i64 = 0; - let ret_val = af_retain_features( - &mut temp as *mut c_longlong as MutFeat, - self.feat as *const c_longlong as Feat, - ); + let mut temp: af_features = std::ptr::null_mut(); + let ret_val = af_retain_features(&mut temp as *mut af_features, self.feat); HANDLE_ERROR(AfError::from(ret_val)); Self { feat: temp } } @@ -213,7 +193,7 @@ impl Clone for Features { impl Drop for Features { fn drop(&mut self) { unsafe { - let ret_val = af_release_features(self.feat as *mut c_longlong as *mut c_void); + let ret_val = af_release_features(self.feat); HANDLE_ERROR(AfError::from(ret_val)); } } @@ -247,7 +227,6 @@ impl Drop for Features { /// This function returns an object of struct [Features](./struct.Features.html) containing Arrays /// for x and y coordinates and score, while array oreientation is set to 0 as FAST does not /// compute orientation. Size is set to 1 as FAST does not compute multiple scales. -#[allow(unused_mut)] pub fn fast( input: &Array, thr: f32, @@ -259,20 +238,20 @@ pub fn fast( where T: HasAfEnum + ImageFilterType, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_features = std::ptr::null_mut(); let err_val = af_fast( - &mut temp as *mut c_longlong as MutFeat, - input.get() as AfArray, - thr as c_float, - arc_len as c_uint, - non_max as c_int, - feat_ratio as c_float, - edge as c_uint, + &mut temp as *mut af_features, + input.get(), + thr, + arc_len, + non_max, + feat_ratio, + edge, ); HANDLE_ERROR(AfError::from(err_val)); + Features { feat: temp } } - Features { feat: temp } } /// Harris corner detector. @@ -296,7 +275,6 @@ where /// This function returns an object of struct [Features](./struct.Features.html) containing Arrays /// for x and y coordinates and score, while array oreientation & size are set to 0 & 1, /// respectively, since harris doesn't compute that information -#[allow(unused_mut)] pub fn harris( input: &Array, max_corners: u32, @@ -308,20 +286,20 @@ pub fn harris( where T: HasAfEnum + RealFloating, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_features = std::ptr::null_mut(); let err_val = af_harris( - &mut temp as *mut c_longlong as MutFeat, - input.get() as AfArray, - max_corners as c_uint, - min_response as c_float, - sigma as c_float, - block_size as c_uint, - k_thr as c_float, + &mut temp as *mut af_features, + input.get(), + max_corners, + min_response, + sigma, + block_size, + k_thr, ); HANDLE_ERROR(AfError::from(err_val)); + Features { feat: temp } } - Features { feat: temp } } /// ORB feature descriptor @@ -346,7 +324,6 @@ where /// # Return Values /// /// This function returns a tuple of [`Features`](./struct.Features.html) and [`Array`](./struct.Array.html). The features objects composed of Arrays for x and y coordinates, score, orientation and size of selected features. The Array object is a two dimensional Array of size Nx8 where N is number of selected features. -#[allow(unused_mut)] pub fn orb( input: &Array, fast_thr: f32, @@ -358,22 +335,22 @@ pub fn orb( where T: HasAfEnum + RealFloating, { - let mut f: i64 = 0; - let mut d: i64 = 0; unsafe { + let mut f: af_features = std::ptr::null_mut(); + let mut d: af_array = std::ptr::null_mut(); let err_val = af_orb( - &mut f as *mut c_longlong as MutFeat, - &mut d as MutAfArray, - input.get() as AfArray, - fast_thr as c_float, - max_feat as c_uint, - scl_fctr as c_float, - levels as c_uint, - blur_img as c_int, + &mut f as *mut af_features, + &mut d as *mut af_array, + input.get(), + fast_thr, + max_feat, + scl_fctr, + levels, + blur_img, ); HANDLE_ERROR(AfError::from(err_val)); + (Features { feat: f }, d.into()) } - (Features { feat: f }, d.into()) } /// Hamming feature matcher @@ -408,7 +385,6 @@ where /// Second Array is an array of MxN size, where M is equal to the number of query features and N is /// equal to n_dist. The value at position IxJ indicates the Hamming distance of the Jth smallest /// distance to the Ith query value in the train data array. -#[allow(unused_mut)] pub fn hamming_matcher( query: &Array, train: &Array, @@ -419,20 +395,20 @@ where T: HasAfEnum + ImageFilterType, T::AggregateOutType: HasAfEnum, { - let mut idx: i64 = 0; - let mut dist: i64 = 0; unsafe { + let mut idx: af_array = std::ptr::null_mut(); + let mut dist: af_array = std::ptr::null_mut(); let err_val = af_hamming_matcher( - &mut idx as MutAfArray, - &mut dist as MutAfArray, - query.get() as AfArray, - train.get() as AfArray, - dist_dims as DimT, - n_dist as c_uint, + &mut idx as *mut af_array, + &mut dist as *mut af_array, + query.get(), + train.get(), + dist_dims, + n_dist, ); HANDLE_ERROR(AfError::from(err_val)); + (idx.into(), dist.into()) } - (idx.into(), dist.into()) } /// Nearest Neighbour. @@ -467,7 +443,6 @@ where /// The second Array is is an array of MxN size, where M is equal to the number of query features /// and N is equal to `n_dist`. The value at position IxJ indicates the distance of the Jth smallest /// distance to the Ith query value in the train data array based on the `dist_type` chosen. -#[allow(unused_mut)] pub fn nearest_neighbour( query: &Array, train: &Array, @@ -479,21 +454,21 @@ where T: HasAfEnum + ImageFilterType, T::AggregateOutType: HasAfEnum, { - let mut idx: i64 = 0; - let mut dist: i64 = 0; unsafe { + let mut idx: af_array = std::ptr::null_mut(); + let mut dist: af_array = std::ptr::null_mut(); let err_val = af_nearest_neighbour( - &mut idx as MutAfArray, - &mut dist as MutAfArray, - query.get() as AfArray, - train.get() as AfArray, - dist_dim as DimT, - n_dist as c_uint, + &mut idx as *mut af_array, + &mut dist as *mut af_array, + query.get(), + train.get(), + dist_dim, + n_dist, dist_type as c_int, ); HANDLE_ERROR(AfError::from(err_val)); + (idx.into(), dist.into()) } - (idx.into(), dist.into()) } /// Image matching @@ -510,7 +485,6 @@ where /// # Return Values /// /// This function returns an Array with disparity values for the window starting at corresponding pixel position. -#[allow(unused_mut)] pub fn match_template( search_img: &Array, template_img: &Array, @@ -520,17 +494,17 @@ where T: HasAfEnum + ImageFilterType, T::AbsOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_match_template( - &mut temp as MutAfArray, - search_img.get() as AfArray, - template_img.get() as AfArray, + &mut temp as *mut af_array, + search_img.get(), + template_img.get(), mtype as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// SUSAN corner detector. @@ -572,7 +546,6 @@ where /// /// # Return Values /// An object of type [Features](./struct.Features.html) composed of arrays for x and y coordinates, score, orientation and size of selected features. -#[allow(unused_mut)] pub fn susan( input: &Array, radius: u32, @@ -584,20 +557,20 @@ pub fn susan( where T: HasAfEnum + ImageFilterType, { - let mut temp: i64 = 0; unsafe { + let mut temp: af_features = std::ptr::null_mut(); let err_val = af_susan( - &mut temp as *mut c_longlong as MutFeat, - input.get() as AfArray, - radius as c_uint, - diff_thr as c_float, - geom_thr as c_float, - feature_ratio as c_float, - edge as c_uint, + &mut temp as *mut af_features, + input.get(), + radius, + diff_thr, + geom_thr, + feature_ratio, + edge, ); HANDLE_ERROR(AfError::from(err_val)); + Features { feat: temp } } - Features { feat: temp } } /// Difference of Gaussians. @@ -614,23 +587,17 @@ where /// # Return Values /// /// Difference of smoothed inputs - An Array. -#[allow(unused_mut)] pub fn dog(input: &Array, radius1: i32, radius2: i32) -> Array where T: HasAfEnum + ImageFilterType, T::AbsOutType: HasAfEnum, { - let mut temp: i64 = 0; unsafe { - let err_val = af_dog( - &mut temp as MutAfArray, - input.get() as AfArray, - radius1 as c_int, - radius2 as c_int, - ); + let mut temp: af_array = std::ptr::null_mut(); + let err_val = af_dog(&mut temp as *mut af_array, input.get(), radius1, radius2); HANDLE_ERROR(AfError::from(err_val)); + temp.into() } - temp.into() } /// Homography estimation @@ -677,22 +644,22 @@ where OutType: HasAfEnum + RealFloating, { let otype = OutType::get_af_dtype(); - let mut inliers: i32 = 0; - let mut temp: i64 = 0; unsafe { + let mut inliers: i32 = 0; + let mut temp: af_array = std::ptr::null_mut(); let err_val = af_homography( - &mut temp as MutAfArray, + &mut temp as *mut af_array, &mut inliers as *mut c_int, - x_src.get() as AfArray, - y_src.get() as AfArray, - x_dst.get() as AfArray, - y_dst.get() as AfArray, - htype as c_int, - inlier_thr as c_float, - iterations as c_uint, - otype as c_int, + x_src.get(), + y_src.get(), + x_dst.get(), + y_dst.get(), + htype as c_uint, + inlier_thr, + iterations, + otype as c_uint, ); HANDLE_ERROR(AfError::from(err_val)); + (temp.into(), inliers) } - (temp.into(), inliers) } diff --git a/tutorials-book/book.toml b/tutorials-book/book.toml index 1b61af964..6cf472978 100644 --- a/tutorials-book/book.toml +++ b/tutorials-book/book.toml @@ -8,4 +8,4 @@ title = "Rust Wrapper for ArrayFire HPC Library" [output.html] theme = "src/theme" mathjax-support = true -default-theme = "ayu" +default-theme = "Coal" diff --git a/tutorials-book/src/SUMMARY.md b/tutorials-book/src/SUMMARY.md index 2ecb6aaa2..1abc76885 100644 --- a/tutorials-book/src/SUMMARY.md +++ b/tutorials-book/src/SUMMARY.md @@ -5,3 +5,5 @@ - [Array and Matrix Manipulation](./array_and_matrix_manipulation.md) - [Indexing](./indexing.md) - [Configuring ArrayFire Runtime Environment](./configuring_arrayfire_environment.md) +- [Interoperability with CUDA](./cuda-interop.md) +- [Interoperability with OpenCL](./opencl-interop.md) diff --git a/tutorials-book/src/array_and_matrix_manipulation.md b/tutorials-book/src/array_and_matrix_manipulation.md index 5bdb9f534..99d28732d 100644 --- a/tutorials-book/src/array_and_matrix_manipulation.md +++ b/tutorials-book/src/array_and_matrix_manipulation.md @@ -1,7 +1,7 @@ # Array and Matrix Manipulation -ArrayFire provides several different methods for manipulating arrays and matrices. -The functionality includes: +ArrayFire provides several different methods for manipulating arrays and matrices. The functionality +includes: * [moddims()](#moddims) - change the dimensions of an array without changing the data * [flat()](#flat) - flatten an array to one dimension @@ -16,11 +16,10 @@ Below we provide several examples of these functions and their use. ### moddims() -The [moddims](../fn.moddims.html) function changes the dimensions of an array without -changing its data or order. Note that this function modifies only the _metadata_ -associated with the array. It does not modify the content of the array. -Here is an example of moddims() converting an 8x1 array into a 2x4 and then -back to a 8x1: +The [moddims][1] function changes the dimensions of an array without changing its data or order. +Note that this function modifies only the _metadata_ associated with the array. It does not modify +the content of the array. Here is an example of moddims() converting an 8x1 array into a 2x4 and +then back to a 8x1: ```rust,noplaypen a [8 1 1 1] @@ -53,7 +52,7 @@ let out = moddims(&a, a.elements(), 1, 1, 1); ### flat() -The [flat](../fn.flat.html) function flattens an array to one dimension: +The [flat][2] function flattens an array to one dimension: ``` a [3 3 1 1] @@ -76,9 +75,9 @@ flat(&a) ### flip() -The [flip](../fn.flip.html) function flips the contents of an array along a -chosen dimension. In the example below, we show the 5x2 array flipped -along the zeroth (i.e. within a column) and first (e.g. across rows) axes: +The [flip][3] function flips the contents of an array along a chosen dimension. In the example +below, we show the 5x2 array flipped along the zeroth (i.e. within a column) and first (e.g. +across rows) axes: ```rust,noplaypen a [5 2 1 1] @@ -105,8 +104,7 @@ flip(a, 1) [5 2 1 1] ### join() -The [join](../fn.join.html), [join_many](../fn.join_many.html) functions can be -used to join arrays along a specific dimension. +The [join][4], [join\_many][5] functions can be used to join arrays along a specific dimension. Here is an example of how to use join an array to itself: @@ -140,9 +138,8 @@ join(1, a, a) [5 2 1 1] ### reorder() -The [reorder](../fn.reorder.html) function modifies the order of data within an array by -exchanging data according to the change in dimensionality. The linear ordering -of data within the array is preserved. +The [reorder][6] function modifies the order of data within an array by exchanging data according to +the change in dimensionality. The linear ordering of data within the array is preserved. ```rust,noplaypen a [2 2 3 1] @@ -181,8 +178,8 @@ reorder(&a, 2, 0, 1) ### shift() -The [shift](../fn.shift.html) function shifts data in a circular buffer fashion along a -chosen dimension. Consider the following example: +The [shift][7] function shifts data in a circular buffer fashion along a chosen dimension. Consider +the following example: ```rust,noplaypen a [3 5 1 1] @@ -205,9 +202,8 @@ shift(&a, -1, 2 ) ### tile() -The [tile](../fn.tile.html) function repeats an array along the specified dimension. -For example below we show how to tile an array along the zeroth and first -dimensions of an array: +The [tile][8] function repeats an array along the specified dimension. For example below we show how +to tile an array along the zeroth and first dimensions of an array: ```rust,noplaypen a [3 1 1 1] @@ -254,8 +250,8 @@ tile(a, tile_dims) [3 2 3 1] ### transpose() -The [transpose](../fn.transpose.html) function performs a standard matrix transpose. The input -array must have the dimensions of a 2D-matrix. +The [transpose][9] function performs a standard matrix transpose. The input array must have the +dimensions of a 2D-matrix. ```rust,noplaypen a [3 3 1 1] @@ -298,3 +294,13 @@ The output for a `[3 3 1 1]` matrix will be the following. 1 2 2 2 ``` + +[1]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.moddims.html +[2]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.flat.html +[3]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.flip.html +[4]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.join.html +[5]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.join_many.html +[6]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.reorder.html +[7]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.shift.html +[8]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.tile.html +[9]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.transpose.html diff --git a/tutorials-book/src/configuring_arrayfire_environment.md b/tutorials-book/src/configuring_arrayfire_environment.md index 08532977c..7db86482d 100644 --- a/tutorials-book/src/configuring_arrayfire_environment.md +++ b/tutorials-book/src/configuring_arrayfire_environment.md @@ -1,64 +1,58 @@ # Configuring Arrayfire Environment -Following are the list of environment and runtime configurations that will help enhance -your experience with ArrayFire. +Following are the list of environment and runtime configurations that will help enhance your +experience with ArrayFire. -## AF_PATH +## AF\_PATH -This is the path with ArrayFire gets installed, ie. the includes and libs are -present in this directory. You can use this variable to add include paths and -libraries to your projects. +This is the path with ArrayFire gets installed, ie. the includes and libs are present in this +directory. You can use this variable to add include paths and libraries to your projects. -## AF_PRINT_ERRORS +## AF\_PRINT\_ERRORS -When AF_PRINT_ERRORS is set to 1, the exceptions thrown are more verbose and -detailed. This helps in locating the exact failure. +When `AF\_PRINT\_ERRORS` is set to 1, the exceptions thrown are more verbose and detailed. This +helps in locating the exact failure. ``` AF_PRINT_ERRORS=1 ./myprogram ``` -## AF_CUDA_DEFAULT_DEVICE +## AF\_CUDA\_DEFAULT\_DEVICE -Use this variable to set the default CUDA device. Valid values for this -variable are the device identifiers shown when [af::info](../fn.info.html) is run. +Use this variable to set the default CUDA device. Valid values for this variable are the device +identifiers shown when [info][1] is run. ``` AF_CUDA_DEFAULT_DEVICE=1 ./myprogram ``` -Note: af::setDevice call in the source code will take precedence over this -variable. +Note: [set\_device][2] call in the source code will take precedence over this variable. -## AF_OPENCL_DEFAULT_DEVICE +## AF\_OPENCL\_DEFAULT\_DEVICE -Use this variable to set the default OpenCL device. Valid values for this -variable are the device identifiers shown when [af::info](../fn.info.html) is run. +Use this variable to set the default OpenCL device. Valid values for this variable are the device +identifiers shown when [info][1] is run. ``` AF_OPENCL_DEFAULT_DEVICE=1 ./myprogram ``` -Note: [af::set_device](../fn.set_device.html) call in the source code will take precedence over this -variable. - -## AF_OPENCL_DEFAULT_DEVICE_TYPE +Note: [set\_device][2] call in the source code will take precedence over this variable. -Use this variable to set the default OpenCL device type. Valid values for this -variable are: CPU, GPU, ACC (Accelerators). +## AF\_OPENCL\_DEFAULT\_DEVICE\_TYPE -When set, the first device of the specified type is chosen as default device. +Use this variable to set the default OpenCL device type. Valid values for this variable are: CPU, +GPU, ACC (Accelerators). When set, the first device of the specified type is chosen as default device. ``` AF_OPENCL_DEFAULT_DEVICE_TYPE=CPU ./myprogram ``` -Note: `AF_OPENCL_DEFAULT_DEVICE` and [af::set_device](../fn.set_device.html) takes precedence over this variable. +Note: `AF_OPENCL_DEFAULT_DEVICE` and [set\_device][2] takes precedence over this variable. -## AF_OPENCL_DEVICE_TYPE +## AF\_OPENCL\_DEVICE\_TYPE -Use this variable to only choose OpenCL devices of specified type. Valid values for this -variable are: +Use this variable to only choose OpenCL devices of specified type. Valid values for this variable are: - ALL: All OpenCL devices. (Default behavior). - CPU: CPU devices only. @@ -71,91 +65,79 @@ When set, the remaining OpenCL device types are ignored by the OpenCL backend. AF_OPENCL_DEVICE_TYPE=CPU ./myprogram ``` -## AF_OPENCL_CPU_OFFLOAD - -When ArrayFire runs on devices with unified memory with the host (ie. -`CL_DEVICE_HOST_UNIFIED_MENORY` is true for the device) then certain functions -are offloaded to run on the CPU using mapped buffers. - -ArrayFire takes advantage of fast libraries such as MKL while spending no time -copying memory from device to host. The device memory is mapped to a host -pointer which can be used in the offloaded functions. - -This functionality can be disabled by using the environment variable -`AF_OPENCL_CPU_OFFLOAD=0`. +## AF\_OPENCL\_CPU\_OFFLOAD -The default bevaior of this has changed in version 3.4. +When ArrayFire runs on devices with unified memory with the host (ie. `CL_DEVICE_HOST_UNIFIED_MENORY` +is true for the device) then certain functions are offloaded to run on the CPU using mapped buffers. -Prior to v3.4, CPU Offload functionality was used only when the user set -`AF_OPENCL_CPU_OFFLOAD=1` and disabled otherwise. +ArrayFire takes advantage of fast libraries such as MKL while spending no time copying memory from +device to host. The device memory is mapped to a host pointer which can be used in the offloaded +functions. -From v3.4 onwards, CPU Offload is enabled by default and is disabled only when -`AF_OPENCL_CPU_OFFLOAD=0` is set. +This functionality can be disabled by using the environment variable `AF_OPENCL_CPU_OFFLOAD=0`. -## AF_OPENCL_SHOW_BUILD_INFO +The default bevaior of this has changed in version 3.4. Prior to v3.4, CPU Offload functionality was +used only when the user set `AF_OPENCL_CPU_OFFLOAD=1` and disabled otherwise. From v3.4 onwards, CPU +Offload is enabled by default and is disabled only when `AF_OPENCL_CPU_OFFLOAD=0` is set. -This variable is useful when debuggin OpenCL kernel compilation failures. When -this variable is set to 1, and an error occurs during a OpenCL kernel -compilation, then the log and kernel are printed to screen. +## AF\_OPENCL\_SHOW\_BUILD\_INFO -## AF_DISABLE_GRAPHICS +This variable is useful when debuggin OpenCL kernel compilation failures. When this variable is set +to 1, and an error occurs during a OpenCL kernel compilation, then the log and kernel are printed to screen. -Setting this variable to 1 will disable window creation when graphics -functions are being called. Disabling window creation will disable all other -graphics calls at runtime as well. +## AF\_DISABLE\_GRAPHICS -This is a useful enviornment variable when running code on servers and systems -without displays. When graphics calls are run on such machines, they will -print warning about window creation failing. To suppress those calls, set this +Setting this variable to 1 will disable window creation when graphics functions are being called. +Disabling window creation will disable all other graphics calls at runtime. This is a useful +when running code on servers and systems without displays. When graphics calls are run on such +machines, they will print warning about window creation failing. To suppress those calls, set this variable. -## AF_SYNCHRONOUS_CALLS +## AF\_SYNCHRONOUS\_CALLS -When this environment variable is set to 1, ArrayFire will execute all -functions synchronously. +When this environment variable is set to 1, ArrayFire will execute all functions synchronously. -## AF_SHOW_LOAD_PATH +## AF\_SHOW\_LOAD\_PATH -When using the Unified backend, if this variable is set to 1, it will show the -path where the ArrayFire backend libraries are loaded from. +When using the Unified backend, if this variable is set to 1, it will show the path where the ArrayFire +backend libraries are loaded from. -If the libraries are loaded from system paths, such as PATH or LD_LIBRARY_PATH -etc, then it will print "system path". If the libraries are loaded from other -paths, then those paths are shown in full. +If the libraries are loaded from system paths, such as PATH or LD\_LIBRARY\_PATH etc, then it will +print "system path". If the libraries are loaded from other paths, then those paths are shown in full. -## AF_MEM_DEBUG +## AF\_MEM\_DEBUG -When AF_MEM_DEBUG is set to 1 (or anything not equal to 0), the caching mechanism in the memory manager is disabled. -The device buffers are allocated using native functions as needed and freed when going out of scope. - -When the environment variable is not set, it is treated to be non zero. +When AF\_MEM\_DEBUG is set to 1 (or anything not equal to 0), the caching mechanism in the memory manager +is disabled. The device buffers are allocated using native functions as needed and freed when going out +of scope. When the environment variable is not set, it is treated to be non zero. ``` AF_MEM_DEBUG=1 ./myprogram ``` -## AF_MAX_BUFFERS - -When AF_MAX_BUFFERS is set, this environment variable specifies the maximum number of buffers allocated before garbage collection kicks in. - -Please note that the total number of buffers that can exist simultaneously can be higher than this number. This variable tells the garbage collector that it should free any available buffers immediately if the treshold is reached. - -When not set, the default value is 1000. - -## AF_OPENCL_MAX_JIT_LEN +## AF\_MAX\_BUFFERS -When set, this environment variable specifies the maximum height of the OpenCL JIT tree after which evaluation is forced. +When AF\_MAX\_BUFFERS is set, this environment variable specifies the maximum number of buffers +allocated before garbage collection kicks in. Please note that the total number of buffers that +can exist simultaneously can be higher than this number. This variable tells the garbage collector +that it should free any available buffers immediately if the treshold is reached. When not set, +the default value is 1000. -The default value, as of v3.4, is 50 on OSX, 100 everywhere else. This value was 20 for older versions. +## AF\_OPENCL\_MAX\_JIT\_LEN -## AF_CUDA_MAX_JIT_LEN +When set, this environment variable specifies the maximum height of the OpenCL JIT tree after +which evaluation is forced. The default value, as of v3.4, is 50 on OSX, 100 everywhere else. +This value was 20 for older versions. -When set, this environment variable specifies the maximum height of the CUDA JIT tree after which evaluation is forced. +## AF\_CUDA\_MAX\_JIT\_LEN -The default value, as of v3.4, 100. This value was 20 for older versions. +When set, this environment variable specifies the maximum height of the CUDA JIT tree after +which evaluation is forced. The default value, as of v3.4, 100. This value was 20 for older versions. -## AF_CPU_MAX_JIT_LEN +## AF\_CPU\_MAX\_JIT\_LEN -When set, this environment variable specifies the maximum length of the CPU JIT tree after which evaluation is forced. +When set, this environment variable specifies the maximum length of the CPU JIT tree after +which evaluation is forced. The default value, as of v3.4, 100. This value was 20 for older versions. -The default value, as of v3.4, 100. This value was 20 for older versions. +[1]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.info.html +[2]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.set_device.html diff --git a/tutorials-book/src/cuda-interop.md b/tutorials-book/src/cuda-interop.md new file mode 100644 index 000000000..1d244ff02 --- /dev/null +++ b/tutorials-book/src/cuda-interop.md @@ -0,0 +1,105 @@ +# Interoperability with CUDA + +{{#include interop_excerpts.md:1:4}} + +ArrayFire manages its own memory, runs within its own CUDA stream, and creates custom IDs for +devices. As such, most of the interoperability functions focus on reducing potential synchronization +conflicts between ArrayFire and CUDA. + +## Basics + +{{#include interop_excerpts.md:6:7}} + +| Function | Purpose | +|------------------------------------|-----------------------------------------------------------| +| [Array::new\_from\_device\_ptr][1] | Construct an ArrayFire [Array][14] from device memory | +| [Array::device\_ptr][2] | Obtain a pointer to the device memory (implies `lock()`) | +| [Array::lock][3] | Removes ArrayFire's control of a device memory pointer | +| [Array::unlock][4] | Restores ArrayFire's control over a device memory pointer | +| [get\_device][5] | Gets the current ArrayFire device ID | +| [set\_device][6] | Switches ArrayFire to the specified device | +| [get\_device\_native\_id][7] | Fetches CUDA deviceID for a given ArrayFire device ID | +| [set\_device\_native\_id][8] | Switches active device to the specified CUDA device ID | +| [get\_stream][9] | Get the current CUDA stream used by ArrayFire | + +## Using custom CUDA kernels in existing ArrayFire application + +By default, ArrayFire manages its own memory and operates in its own CUDA stream. Thus there is a +slight amount of bookkeeping that needs to be done in order to integrate your custom CUDA kernel. + +Ideally, we recommend using ArrayFire's CUDA stream to launch your custom kernels. However, this +is currently not possible due to limitation on [RustaCUDA][10] not being to able to wrap an +existing cudaStream\_t/CUstream\_t objects. The current work around is to create a stream of your +own and launch the kernel on it. + +Notice that since ArrayFire and your kernels are not sharing the same CUDA stream, there is a need +to perform explicit synchronization before launching kernel on your stream that depends on the +computation carried out by ArrayFire earlier. This extra step is unnecessary once the above stated +limiation of RustaCUDA's stream is eliminated. + +This process is best illustrated with a fully worked example: +```rust +{{#include ../../cuda-interop/examples/custom_kernel.rs}} +``` + +## Adding ArrayFire to existing CUDA Application + +{{#include interop_excerpts.md:9:15}} + + 1. Finish any pending CUDA operations (e.g. cudaDeviceSynchronize() or similar stream functions) + 2. Create ArrayFire arrays from existing CUDA pointers + 3. Perform operations on ArrayFire arrays + 4. Instruct ArrayFire to finish operations using [eval][11] and [sync][12] + 5. Obtain pointers to important memory + 6. Continue your CUDA application. + 7. Free non-managed memory + +To create the [Array][14] fom device pointer, you should use one of the following approaches: + +Using DeviceBuffer from [RustaCUDA][10], or a Wrapper Object for CUDA device memory +```rust +let mut buffer = memory::DeviceBuffer::from_slice(&v).unwrap(); + +let array_dptr = Array::new_from_device_ptr( + buffer.as_device_ptr().as_raw_mut(), dim4!(10, 10)); + +array_dptr.lock(); // Needed to avoid free as arrayfire takes ownership +``` + +Using raw pointer returned from cuda\_malloc interface exposed by [RustaCUDA][10] +```rust +let mut dptr: *mut f32 = std::ptr::null_mut(); +unsafe { + dptr = memory::cuda_malloc::(10*10).unwrap().as_raw_mut(); +} + +let array_dptr = Array::new_from_device_ptr(dptr, dim4!(10, 10)); +// After ArrayFire takes over ownership of the pointer, you can use other +// arrayfire functions as usual. +``` + +ArrayFire's memory manager automatically assumes responsibility for any memory provided to it. +Thus ArrayFire could free or reuse the memory at any later time. If this behavior is not desired, +you may call [Array::unlock][13] and manage the memory yourself. However, if you do so, please be +cautious not to free memory when ArrayFire might be using it! + +The seven steps above are best illustrated using a fully-worked example: + +```rust +{{#include ../../cuda-interop/examples/cuda_af_app.rs}} +``` + +[1]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html#method.new_from_device_ptr +[2]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html#method.device_ptr +[3]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html#method.lock +[4]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html#method.unlock +[5]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.get_device.html +[6]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.set_device.html +[7]: http://arrayfire.org/arrayfire-rust/af_cuda_interop/fn.get_device_native_id.html +[8]: http://arrayfire.org/arrayfire-rust/af_cuda_interop/fn.set_device_native_id.html +[9]: http://arrayfire.org/arrayfire-rust/af_cuda_interop/fn.get_stream.html +[10]: https://github.com/bheisler/RustaCUDA +[11]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html#method.eval +[12]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.sync.html +[13]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html#method.unlock +[14]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html diff --git a/tutorials-book/src/getting_started.md b/tutorials-book/src/getting_started.md index 7cce48638..5f31ab7d8 100644 --- a/tutorials-book/src/getting_started.md +++ b/tutorials-book/src/getting_started.md @@ -1,58 +1,52 @@ -ArrayFire is a high performance software library for parallel computing with -an easy-to-use API. ArrayFire abstracts away much of the details of -programming parallel architectures by providing a high-level container object, -the [Array](../struct.Array.html), that represents data stored on a CPU, GPU, FPGA, -or other type of accelerator. This abstraction permits developers to write -massively parallel applications in a high-level language where they need -not be concerned about low-level optimizations that are frequently required to -achieve high throughput on most parallel architectures. +ArrayFire is a high performance software library for parallel computing with an easy-to-use API. +ArrayFire abstracts away much of the details of programming parallel architectures by providing +a high-level container object, the [Array][1], that represents data stored on a CPU, GPU, FPGA, +or other type of accelerator. This abstraction permits developers to write massively parallel +applications in a high-level language where they need not be concerned about low-level optimizations +that are frequently required to achieve high throughput on most parallel architectures. ## Supported data types -ArrayFire provides one generic container object, the [Array](../struct.Array.html) -on which functions and mathematical operations are performed. The `Array` -can represent one of many different [basic data types](../enum.DType.html): - -* [F32](../enum.DType.html) real single-precision (`float`) -* [C32](../enum.DType.html) complex single-precision (`cfloat`) -* [F64](../enum.DType.html) real double-precision (`double`) -* [C64](../enum.DType.html) complex double-precision (`cdouble`) -* [B8 ](../enum.DType.html) 8-bit boolean values (`bool`) -* [S32](../enum.DType.html) 32-bit signed integer (`int`) -* [U32](../enum.DType.html) 32-bit unsigned integer (`unsigned`) -* [U8 ](../enum.DType.html) 8-bit unsigned values (`unsigned char`) -* [S64](../enum.DType.html) 64-bit signed integer (`intl`) -* [U64](../enum.DType.html) 64-bit unsigned integer (`uintl`) -* [S16](../enum.DType.html) 16-bit signed integer (`short`) -* [U16](../enum.DType.html) 16-bit unsigned integer (`unsigned short`) -* [F16](../enum.DType.html) 16-bit floating point number ([`half::f16`](https://crates.io/crates/half)) - -Most of these data types are supported on all modern GPUs; however, some -older devices may lack support for double precision arrays. In this case, -a runtime error will be generated when the array is constructed. - -If not specified otherwise, `Array`s are created as single precision floating -point numbers ([F32](../enum.DType.html)). +ArrayFire provides one generic container object, the [Array][1] on which functions and mathematical +operations are performed. The `Array` can represent one of many different [basic data types][2]: + +* [F32][2] real single-precision (`float`) +* [C32][2] complex single-precision (`cfloat`) +* [F64][2] real double-precision (`double`) +* [C64][2] complex double-precision (`cdouble`) +* [B8 ][2] 8-bit boolean values (`bool`) +* [S32][2] 32-bit signed integer (`int`) +* [U32][2] 32-bit unsigned integer (`unsigned`) +* [U8 ][2] 8-bit unsigned values (`unsigned char`) +* [S64][2] 64-bit signed integer (`intl`) +* [U64][2] 64-bit unsigned integer (`uintl`) +* [S16][2] 16-bit signed integer (`short`) +* [U16][2] 16-bit unsigned integer (`unsigned short`) +* [F16][2] 16-bit floating point number ([`half::f16`][3]) + +Most of these data types are supported on all modern GPUs; however, some older devices may lack +support for double precision arrays. In this case, a runtime error will be generated when the array +is constructed. + +If not specified, `Array`s are created as single precision floating point numbers ([F32][2]). ## Creating and populating an Array -ArrayFire [Array](../struct.Array.html)s represent memory stored on the device. -As such, creation and population of an array will consume memory on the device -which cannot freed until the `array` object goes out of scope. As device memory -allocation can be expensive, ArrayFire also includes a memory manager which +ArrayFire [Array][1]'s represent memory stored on the device. As such, creation and population of +an array will consume memory on the device which cannot freed until the `array` object goes out of +scope. As device memory allocation can be expensive, ArrayFire also includes a memory manager which will re-use device memory whenever possible. -Arrays can be created using one of the [array constructors](../struct.Array.html#method.new_empty). -Below we show how to create 1D, 2D, and 3D arrays with uninitialized values: +Arrays can be created using one of the [array constructors][4]. Below we show how to create 1D, 2D, +and 3D arrays with uninitialized values: ```rust,noplaypen let garbageVals = Array::new_empty(Dim4::new(&[3, 1, 1, 1]), DType::F32); ``` -However, uninitialized memory is likely not useful in your application. -ArrayFire provides several convenient functions for creating arrays that contain -pre-populated values including constants, uniform random numbers, uniform -normally distributed numbers, and the identity matrix: +However, uninitialized memory is likely not useful in your application. ArrayFire provides several +convenient functions for creating arrays that contain pre-populated values including constants, +uniform random numbers, uniform normally distributed numbers, and the identity matrix: ```rust,noplaypen // Create an array filled with constant value of 2.0 of type floating point @@ -67,11 +61,10 @@ let a = randu::(dims); print(&a); ``` -As stated above, the default data type for arrays is [F32](../enum.DType.html) (a -32-bit floating point number) unless specified otherwise. +As stated above, the default data type for arrays is [F32][2](32-bit floating point number) unless +specified otherwise. -ArrayFire `Array`s may also be populated from data found on the host. -For example: +ArrayFire `Array`s may also be populated from data found on the host. For example: ```rust,noplaypen let values: [u32; 3] = [1u32, 2, 3]; @@ -79,27 +72,13 @@ let indices = Array::new(&values, Dim4::new(&[3, 1, 1, 1])); print(&indices); ``` - - ## Properties of an Array -ArrayFire provides several functions to determine various aspects of arrays. -This includes functions to print the contents, query the dimensions, and -determine various other aspects of arrays. +ArrayFire provides several functions to determine various aspects of arrays. This includes +functions to print the contents, query dimensions, and determine various other aspects of arrays. -The [print](../fn.print.html) function can be used to print arrays that -have already been generated or any expression involving arrays: +The [print][5] function can be used to print arrays that have already been generated or any +expression involving arrays: ```rust,noplaypen let values: [f32; 3] = [1.0, 2.0, 3.0]; @@ -107,7 +86,8 @@ let indices = Array::new(&values, Dim4::new(&[3, 1, 1, 1])); print(&indices); ``` -The dimensions of an array may be determined using either a [Dim4](../struct.Dim4.html) object or by accessing the dimensions directly using the [Dim4::get](../struct.Dim4.html#method.get) and [Dim4::numdims](../struct.Dim4.html#method.ndims) functions: +The dimensions of an array may be determined using either a [Dim4][6] object or by accessing the +dimensions directly using the [Dim4::get][7] and [Dim4::numdims][8] functions: ```rust,noplaypen let values: [f32; 3] = [1.0, 2.0, 3.0]; @@ -116,32 +96,25 @@ let indices = Array::new(&values, dims); println!("Dims {:?} with dimensions {}", dims.get(), dims.ndims()); ``` -In addition to dimensions, arrays also carry several properties including -methods to determine the underlying type and size (in bytes). You can even -determine whether the array is empty, real/complex, a row/column, or a scalar -or a vector. For further information on these capabilities, we suggest you consult the -full documentation on the [Array](../struct.Array.html). +In addition to dimensions, arrays also carry several properties including methods to determine the +underlying type and size (in bytes). You can even determine whether the array is empty, real/complex, +a row/column, or a scalar or a vector. For further information on these capabilities, we suggest you +consult the full documentation on the [Array][1]. ## Writing math expressions using ArrayFire -ArrayFire features an intelligent Just-In-Time (JIT) compilation engine that -converts expressions using arrays into the smallest number of CUDA/OpenCL -kernels. For most operations on Arrays, ArrayFire functions like a vector library. -That means that an element-wise operation, like `c[i] = a[i] + b[i]` in C, -would be written more concisely without indexing, like `c = a + b`. -When there are multiple expressions involving arrays, ArrayFire's JIT engine -will merge them together. This "kernel fusion" technology not only decreases -the number of kernel calls, but, more importantly, avoids extraneous global -memory operations. - -Our JIT functionality extends across C API boundary and only ends -when a non-JIT function is encountered or a synchronization operation is -explicitly called by the code. - -ArrayFire provides hundreds of functions for element-wise -operations. All of the standard operators (e.g. +,-,\*,/) are supported -as are most transcendental functions (sin, cos, log, sqrt, etc.). -Here are a few examples: +ArrayFire features an intelligent Just-In-Time (JIT) compilation engine that converts expressions +using arrays into the smallest number of CUDA/OpenCL kernels. For most operations on Arrays, +ArrayFire functions like a vector library. That means that an element-wise operation, like +`c[i] = a[i] + b[i]` in C, would be written more concisely without indexing, like `c = a + b`. When +there are multiple expressions involving arrays, ArrayFire's JIT engine will merge them together. +his "kernel fusion" technology not only decreases the number of kernel calls, but, more importantly, avoids extraneous global memory operations. + +Our JIT functionality extends across C API boundary and only ends when a non-JIT function is +encountered or a synchronization operation is explicitly called by the code. + +ArrayFire provides hundreds of functions for element-wise operations. All of the standard operators +(e.g. +,-,\*,/) are supported as are most transcendental functions (sin, cos, log, sqrt, etc.). Here are a few examples: ```rust,noplaypen let num_rows: u64 = 5; @@ -161,66 +134,36 @@ d += e; print(&d); ``` - - ## Indexing -Like all functions in ArrayFire, indexing is also executed in parallel on -the OpenCL/CUDA device. To index `Array`s you may use one or a combination of the following functions: +Like all functions in ArrayFire, indexing is also executed in parallel on the OpenCL/CUDA device. To +index `Array`s you may use one or a combination of the following functions: -* [Seq](../struct.Seq.html) representing a linear sequence -* [Seq::Default()](../struct.Seq.html) representing the entire dimension -* [row(&Array, i)](../fn.row.html) or [col(&Array, i)](../fn.col.html) specifying a single row/column -* [rows(&Array, first,last)](../fn.rows.html) or [cols(&Array, first,last)](../fn.cols.html) - specifying a span of rows or columns +* [Seq][9] representing a linear sequence +* [Seq::Default()][9] representing the entire dimension +* [row(&Array, i)][10] or [col(&Array, i)][11] specifying a single row/column +* [rows(&Array, first,last)][12] or [cols(&Array, first,last)][13] specifying a span of rows or columns -Please see the [indexing page](./indexing.md) for several examples of how to -use these functions. +Please see the [indexing page](./indexing.md) for several examples of how to use these functions. ## Access to Array memory on the host -Memory in `af::Array`s may be accessed using the [Array::host()](../struct.Array.html#method.host) method. -The `host` function *copies* the data from the device and makes it available -in a standard slice or similar container on the host. As such, it is up to the developer to manage -any memory returned by `host`. - +Memory in `af::Array`s may be accessed using the [Array::host()][14] method. The `host` function +*copies* the data from the device and makes it available in a standard slice or similar container on +the host. As such, it is up to the developer to manage any memory returned by `host`. ## Bitwise operators -In addition to supporting standard mathematical functions, Arrays -that contain integer data types also support bitwise operators including -and, or, and shift etc. Operator traits for Array as well as separate functions -are also defined to support various use cases. +In addition to supporting standard mathematical functions, Arrays that contain integer data types +also support bitwise operators including and, or, and shift etc. Operator traits for Array as well +as separate functions are also defined to support various use cases. ```rust,noplaypen let dims = Dim4::new(&[5, 3, 1, 1]); @@ -239,7 +182,27 @@ print(&d); ## Where to go for help? -* [Google Groups](https://groups.google.com/forum/#!forum/arrayfire-users) -* ArrayFire Services: [Consulting](http://arrayfire.com/consulting/) | [Support](http://arrayfire.com/support/) | [Training](http://arrayfire.com/training/) -* [ArrayFire Blogs](http://arrayfire.com/blog/) +* [Google Groups][15] +* ArrayFire Services: [Consulting][16] | [Support][17] | [Training][18] +* [ArrayFire Blogs][19] * Email: + +[1]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html +[2]: http://arrayfire.org/arrayfire-rust/arrayfire/enum.DType.html +[3]: https://crates.io/crates/half +[4]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html#method.new_empty +[5]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.print.html +[6]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Dim4.html +[7]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Dim4.html#method.get +[8]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Dim4.html#method.ndims +[9]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Seq.html +[10]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.row.html +[11]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.col.html +[12]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.rows.html +[13]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.cols.html +[14]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Dim4.html#method.host +[15]: https://groups.google.com/forum/#!forum/arrayfire-users +[16]: http://arrayfire.com/consulting/ +[17]: http://arrayfire.com/support/ +[18]: http://arrayfire.com/training/ +[19]: http://arrayfire.com/blog/ diff --git a/tutorials-book/src/indexing.md b/tutorials-book/src/indexing.md index d3d39766e..49a077cb5 100644 --- a/tutorials-book/src/indexing.md +++ b/tutorials-book/src/indexing.md @@ -1,19 +1,16 @@ # Indexing -Indexing in ArrayFire is a powerful but easy to abuse feature. This feature -allows you to reference or copy subsections of a larger array and perform -operations on only a subset of elements. +Indexing in ArrayFire is a powerful but easy to abuse feature. This feature allows you to reference +or copy subsections of a larger array and perform operations on only a subset of elements. -[Indexer](../struct.Indexer.html) structure is the key element used in Rust -wrapper of ArrayFire for creating references to existing Arrays. Given -below are few of such functions and their corresponding use cases. -Use [Indexer::new](../struct.Indexer.html#method.new) to create an Indexer -object and set either a `Seq` object or `Array` as indexing object for a -given dimension. +[Indexer][1] structure is the key element used in Rust wrapper of ArrayFire for creating references +to existing Arrays. Given below are few of such functions and their corresponding use cases. Use +[Indexer::new][2] to create an Indexer object and set either a `Seq` object or `Array` as indexing +object for a given dimension. ## Using Seq objects to index Array -Create a view of an existing Array using Sequences and the function [index](../fn.index.html). +Create a view of an existing Array using Sequences and the function [index][3]. ```rust,noplaypen let dims = Dim4::new(&[5, 5, 1, 1]); @@ -37,7 +34,7 @@ af_print!("a(seq(1,3,1), span)", sub); // 0.1386 0.9455 0.9434 0.2330 0.2657 ``` -Set a sub-portion of an existing Array with a constant value using [assign_seq](../fn.assign_seq.html). +Set a sub-portion of an existing Array with a constant value using [assign\_seq][4]. ```rust,noplaypen let a = constant(2.0 as f32, Dim4::new(&[5, 3, 1, 1])); @@ -135,7 +132,19 @@ print(&row(&a, 4)); print(&col(&a, 4)); ``` -You can also use [rows](../fn.rows.html) & [cols](../fn.cols.html) to retrieve a -subset of rows or coloumns respectively. - -Similarly, [set_row](../fn.set_row.html) & [set_rows](../fn.set_rows.html) can be used to change the values in a particular set of rows using another Array. [set_col](../fn.set_col.html) & [set_cols](../fn.set_cols.html) has same functionality, except that it is for coloumns. +You can also use [rows][5] & [cols][6] to retrieve a subset of rows or coloumns respectively. + +Similarly, [set\_row][7] & [set\_rows][9] can be used to change the values in a particular set of +rows using another Array. [set\_col][8] & [set\_cols][10] has same functionality, except that it is +for coloumns. + +[1]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Indexer.html +[2]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Indexer.html#method.new +[3]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.index.html +[4]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.assign_seq.html +[5]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.rows.html +[6]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.cols.html +[7]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.set_row.html +[8]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.set_col.html +[9]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.set_rows.html +[10]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.set_cols.html diff --git a/tutorials-book/src/interop_excerpts.md b/tutorials-book/src/interop_excerpts.md new file mode 100644 index 000000000..6689522af --- /dev/null +++ b/tutorials-book/src/interop_excerpts.md @@ -0,0 +1,15 @@ +Although ArrayFire is quite extensive, there remain many cases in which you may want to write custom +kernels in CUDA or OpenCL. For example, you may wish to add ArrayFire to an existing code base to +increase your productivity, or you may need to supplement ArrayFire's functionality with your own +custom implementation of specific algorithms. + +It is fairly straightforward to interface ArrayFire with your own custom code. ArrayFire provides +several functions to ease this process including: + +Adding ArrayFire to an existing application is slightly more involved and can be somewhat tricky due +to several optimizations we implement. The most important are as follows: + +- ArrayFire assumes control of all memory provided to it. +- ArrayFire does not (in general) support in-place memory transactions. + +We will discuss the implications of these items below. To add ArrayFire to existing code you need to: diff --git a/tutorials-book/src/opencl-interop.md b/tutorials-book/src/opencl-interop.md new file mode 100644 index 000000000..e51148e33 --- /dev/null +++ b/tutorials-book/src/opencl-interop.md @@ -0,0 +1,128 @@ +# Interoperability with OpenCL + +{{#include interop_excerpts.md:1:4}} + +ArrayFire manages its own context, queue, memory, and creates custom IDs for devices. As such, most +of the interoperability functions focus on reducing potential synchronization conflicts between +ArrayFire and OpenCL. + +## Basics + +{{#include interop_excerpts.md:6:7}} + +| Function | Purpose | +|------------------------------------|-----------------------------------------------------------| +| [Array::new\_from\_device\_ptr][1] | Construct an ArrayFire Array from cl\_mem | +| [Array::device\_ptr][2] | Obtain a pointer to the device memory (implies `lock`) | +| [Array::lock][3] | Removes ArrayFire's control of a device memory pointer | +| [Array::unlock][4] | Restores ArrayFire's control over a device memory pointer | +| [get\_platform][7] | Get ArrayFire's current cl\_platform | +| [get\_device][5] | Gets the current ArrayFire device ID | +| [get\_device\_id][8] | Get ArrayFire's current cl\_device\_id | +| [set\_device\_id][9] | Set ArrayFire's device from a cl\_device\_id | +| [set\_device][6] | Switches ArrayFire to the specified device | +| [get\_context][10] | Get ArrayFire's current cl\_context | +| [get\_queue][11] | Get ArrayFire's current cl\_command\_queue | +| [get\_device\_type][12] | Get the current [DeviceType][16] | + +Note that the pointer returned by [Array::device\_ptr][2] should be cast to `cl_mem` before using +it with OpenCL opaque types. The pointer is a `cl_mem` internally that is force casted to pointer +type by ArrayFire before returning the value to caller. + +Additionally, the OpenCL backend permits the programmer to add and remove custom devices from the +ArrayFire device manager. These permit you to attach ArrayFire directly to the OpenCL queue used by +other portions of your application. + +| Function | Purpose | +|-------------------------------|----------------------------------------------------------| +| [add\_device\_context][13] | Add a new device to ArrayFire's device manager | +| [set\_device\_context][15] | Set ArrayFire's device from cl\_device\_id & cl\_context | +| [delete\_device\_context][14] | Remove a device from ArrayFire's device manager | + +Below we provide two worked examples on how ArrayFire can be integrated +into new and existing projects. + +## Adding custom OpenCL kernels to an existing ArrayFire application + +By default, ArrayFire manages its own context, queue, memory, and creates custom IDs for devices. +Thus there is some bookkeeping that needs to be done to integrate your custom OpenCL kernel. + +If your kernels can share operate in the same queue as ArrayFire, you should: + +1. Obtain the OpenCL context, device, and queue used by ArrayFire +2. Obtain cl\_mem references to [Array][18] objects +3. Load, build, and use your kernels +4. Return control of [Array][18] memory to ArrayFire + +Note, ArrayFire uses an in-order queue, thus when ArrayFire and your kernels are operating in the +same queue, there is no need to perform any synchronization operations. + +This process is best illustrated with a fully worked example: + +```rust +{{#include ../../opencl-interop/examples/custom_kernel.rs}} +``` + +If your kernels needs to operate in their own OpenCL queue, the process is essentially identical, +except you need to instruct ArrayFire to complete its computations using the [sync][17] function +prior to launching your own kernel and ensure your kernels are complete using `clFinish` +(or similar) commands prior to returning control of the memory to ArrayFire: + +1. Obtain the OpenCL context, device, and queue used by ArrayFire +2. Obtain cl\_mem references to [Array][18] objects +3. Instruct ArrayFire to finish operations using [sync][17] +4. Load, build, and use your kernels +5. Instruct OpenCL to finish operations using clFinish() or similar commands. +6. Return control of [Array][18] memory to ArrayFire + +## Adding ArrayFire to an existing OpenCL application + +{{#include interop_excerpts.md:9:15}} + +1. Instruct OpenCL to complete its operations using clFinish (or similar) +2. Instruct ArrayFire to use the user-created OpenCL Context +3. Create ArrayFire arrays from OpenCL memory objects +4. Perform ArrayFire operations on the [Array][18]s +5. Instruct ArrayFire to finish operations using [sync][17] +6. Obtain cl\_mem references for important memory +7. Continue your OpenCL application + + + +> ArrayFire's memory manager automatically assumes responsibility for any memory provided to +it. If you are creating an array from another RAII style object, you should retain it to ensure +your memory is not deallocated if your RAII object were to go out of scope. + +> If you do not wish for ArrayFire to manage your memory, you may call the [Array::unlock][4] +function and manage the memory yourself; however, if you do so, please be cautious not to call +`clReleaseMemObj` on a `cl_mem` when ArrayFire might be using it! + +Given below is a fully working example: + +```rust +{{#include ../../opencl-interop/examples/ocl_af_app.rs}} +``` + +[1]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html#method.new_from_device_ptr +[2]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html#method.device_ptr +[3]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html#method.lock +[4]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html#method.unlock +[5]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.get_device.html +[6]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.set_device.html +[7]: http://arrayfire.org/arrayfire-rust/af_opencl_interop/fn.get_platform.html +[8]: http://arrayfire.org/arrayfire-rust/af_opencl_interop/fn.get_device_id.html +[9]: http://arrayfire.org/arrayfire-rust/af_opencl_interop/fn.set_device_id.html +[10]: http://arrayfire.org/arrayfire-rust/af_opencl_interop/fn.get_context.html +[11]: http://arrayfire.org/arrayfire-rust/af_opencl_interop/fn.get_queue.html +[12]: http://arrayfire.org/arrayfire-rust/af_opencl_interop/fn.get_device_type.html +[13]: http://arrayfire.org/arrayfire-rust/af_opencl_interop/fn.add_device_context.html +[14]: http://arrayfire.org/arrayfire-rust/af_opencl_interop/fn.delete_device_context.html +[15]: http://arrayfire.org/arrayfire-rust/af_opencl_interop/fn.set_device_context.html +[16]: http://arrayfire.org/arrayfire-rust/af_opencl_interop/enum.DeviceType.html +[17]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.sync.html +[18]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html diff --git a/tutorials-book/src/vectorization.md b/tutorials-book/src/vectorization.md index a1e3ddb8e..13d485d47 100644 --- a/tutorials-book/src/vectorization.md +++ b/tutorials-book/src/vectorization.md @@ -1,48 +1,43 @@ # Vectorization -Programmers and Data Scientists want to take advantage of fast and parallel -computational devices. Writing vectorized code is necessary to get -the best performance out of the current generation parallel hardware and -scientific computing software. However, writing vectorized code may not be -immediately intuitive. ArrayFire provides many ways to vectorize a given code -segment. In this chapter, we present several methods to vectorize code -using ArrayFire and discuss the benefits and drawbacks associated with each method. +Programmers and Data Scientists want to take advantage of fast and parallel computational devices. +Writing vectorized code is necessary to get the best performance out of the current generation +parallel hardware and scientific computing software. However, writing vectorized code may not be +immediately intuitive. ArrayFire provides many ways to vectorize a given code segment. In this +chapter, we present several methods to vectorize code using ArrayFire and discuss the benefits and +drawbacks associated with each method. ## Generic/Default vectorization -By its very nature, ArrayFire is a vectorized library. Most functions operate on -Arrays as a whole -- on all elements in parallel. For example consider the following code: +By its very nature, ArrayFire is a vectorized library. Most functions operate on Arrays as a whole +i.e. on all elements in parallel. For example consider the following code: ```rust,noplaypen let mut a = af::range(Dim::new(&[10, 1, 1, 1])); // [0, 9] a = a + 1; // [1, 10] ``` -This code will result in a single backend kernel that operates on all 10 elements -of `a` in parallel. +This code will result in a single kernel that operates on all 10 elements of `a` in parallel. A small subset of such vectorized ArrayFire functions are given below for quick reference: -| Operator Category | Functions | -|--------------------------------------------------------------|----------------------------| -| Arithmetic operations | +, -, \*, /, %, >>, << | -| Logical operations | &&, \|\|, <, >, ==, != etc. | -| Numeric functions | [abs](../fn.abs.html), [floor](../fn.floor.html), [round](../fn.round.html), [min](../fn.min.html), [max](../fn.max.html), etc. | -| Complex operations | [real](../fn.real.html), [imag](../fn.imag.html), [conjg](../fn.conjg.html), etc. | -| Exponential and logarithmic functions | [exp](../fn.exp.html), [log](../fn.log.html), [expm1](../fn.expm1.html), [log1p](../fn.log1p.html), etc. | -| Trigonometric functions | [sin](../fn.sin.html), [cos](../fn.cos.html), [tan](../fn.tan.html), etc. | -| Hyperbolic functions | [sinh](../fn.sinh.html), [cosh](../fn.cosh.html), [tanh](../fn.tanh.html), etc. | +| Operator Category | Functions | +|----------------------------------|------------------------------------------------------------| +| Arithmetic operations | +, -, \*, /, %, >>, << | +| Logical operations | &&, \|\|, <, >, ==, != etc. | +| Numeric functions | [abs][1], [floor][2], [round][3], [min][4], [max][5], etc. | +| Complex operations | [real][6], [imag][7], [conjg][8], etc. | +| Exponential and logarithmic fns | [exp][9], [log][10], [expm1][11], [log1p][12], etc. | +| Trigonometric functions | [sin][13], [cos][14], [tan][15], etc. | +| Hyperbolic functions | [sinh][16], [cosh][17], [tanh][18], etc. | -In addition to element-wise operations, many other functions are also -vectorized in ArrayFire. +In addition to element-wise operations, many other functions are also vectorized in ArrayFire. -Notice that even functions that perform some form of aggregation (e.g. -[sum](../fn.sum.html) or [min](../fn.min.html)), signal processing (like -[convolve](../fn.convolve1.html)), and image processing functions -(i.e. [rotate](../fn.rotate.html) etc.) - all support vectorization on - different columns or images. +Notice that even functions that perform some form of aggregation (e.g. [sum][19] or [min][14]), +signal processing (like [convolve][20]), and image processing functions (i.e. [rotate][21] etc.) +- all support vectorization on different columns or images. -For example, if we have `NUM` images of size `WIDTH`x`HEIGHT`, one could -convolve each image in a vector fashion as follows: +For example, if we have `NUM` images of size `WIDTH`x`HEIGHT`, one could convolve each image in a +vector fashion as follows: ```rust,noplaypen let g_coef: [f32, 9] = { 1, 2, 1, 2, 4, 2, 1, 2, 1 }; @@ -54,8 +49,7 @@ let signal = randu(WIDTH, HEIGHT, NUM); let conv = convolve2(signal, filter, ConvMode::DEFAULT, ConvDomain::AUTO); ``` -Similarly, one can rotate 100 images by 45 degrees in a single call using -code like the following: +Similarly, one can rotate 100 images by 45 degrees in a single call using code like the following: ```rust,noplaypen // Construct an array of 100 WIDTH x HEIGHT images of random numbers @@ -65,20 +59,41 @@ let imgs = randu(WIDTH, HEIGHT, 100); let rot_imgs = rotate(imgs, 45.0, False, InterpType::LINEAR); ``` -Although *most* functions in ArrayFire do support vectorization, some do not. -Most notably, all linear algebra functions. Even though they are not vectorized -linear algebra operations, they still execute in parallel on your hardware. +Although *most* functions in ArrayFire do support vectorization, some do not. Most notably, all +linear algebra functions. Even though they are not vectorized linear algebra operations, they still +execute in parallel on your hardware. -Using the built in vectorized operations should be the first -and preferred method of vectorizing any code written with ArrayFire. +Using the built in vectorized operations should be the first and preferred method of vectorizing any +code written with ArrayFire. ## GFOR -This construct is similar to gfor loop from C++ API of ArrayFire. It has not -been implemented in rust wrapper. This section will be updated once the feature -has been added to the crate. +This construct is similar to gfor loop from C++ API of ArrayFire. It has not been implemented in +rust wrapper. This section will be updated once the feature has been added to the crate. ## batch\_func -This another pending feature that is similar to our C++ API of -[batchFunc()](http://arrayfire.org/docs/namespaceaf.htm#aa0eb9e160f5be4b95234543e5c47934b) +This another pending feature that is similar to our C++ API of [batchFunc()][22] + +[1]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.abs.html +[2]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.floor.html +[3]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.round.html +[4]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.min.html +[5]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.max.html +[6]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.real.html +[7]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.imag.html +[8]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.conjg.html +[9]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.exp.html +[10]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.log.html +[11]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.expm1.html +[12]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.log1p.html +[13]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.sin.html +[14]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.cos.html +[15]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.tan.html +[16]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.sinh.html +[17]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.cosh.html +[18]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.tanh.html +[19]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.sum.html +[20]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.convolve1.html +[21]: http://arrayfire.org/arrayfire-rust/arrayfire/fn.rotate.html +[22]: http://arrayfire.org/docs/namespaceaf.htm#aa0eb9e160f5be4b95234543e5c47934b