Skip to content

Commit

Permalink
Merge pull request #96 from arrayfire/devel
Browse files Browse the repository at this point in the history
v3.4.1 devel to master
  • Loading branch information
9prady9 authored Jan 11, 2017
2 parents da87964 + 456a335 commit f75a858
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 36 deletions.
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "arrayfire"
description = "ArrayFire is a high performance software library for parallel computing with an easy-to-use API. Its array based function set makes parallel programming simple. ArrayFire's multiple backends (CUDA, OpenCL and native CPU) make it platform independent and highly portable. A few lines of code in ArrayFire can replace dozens of lines of parallel computing code, saving you valuable time and lowering development costs. This crate provides Rust bindings for ArrayFire library."
version = "3.4.0"
version = "3.4.1"
documentation = "http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html"
homepage = "https://github.com/arrayfire/arrayfire"
repository = "https://github.com/arrayfire/arrayfire-rust"
Expand Down Expand Up @@ -46,3 +46,7 @@ path = "examples/snow.rs"
[[example]]
name = "histogram"
path = "examples/histogram.rs"

[[example]]
name = "acoustic_wave"
path = "examples/acoustic_wave.rs"
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
|:-------:|:-------:|:---:|
| [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/rust-linux)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/rust-linux/) | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/rust-windows)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/rust-windows/) | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/rust-osx)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/rust-osx/) |

[ArrayFire](https://github.com/arrayfire/arrayfire) is a high performance library for parallel computing with an easy-to-use API. It enables users to write scientific computing code that is portable across CUDA, OpenCL and CPU devices. This project provides Rust bindings for the ArrayFire library. The wrapper is currently compliant with ArrayFire 3.4 API. If you find any bugs, please report them [here](https://github.com/arrayfire/arrayfire-rust/issues).
[ArrayFire](https://github.com/arrayfire/arrayfire) is a high performance library for parallel computing with an easy-to-use API. It enables users to write scientific computing code that is portable across CUDA, OpenCL and CPU devices. This project provides Rust bindings for the ArrayFire library. The wrapper is currently compliant with ArrayFire 3.4.x API. If you find any bugs, please report them [here](https://github.com/arrayfire/arrayfire-rust/issues).

## Documentation

Expand All @@ -30,7 +30,7 @@ first.
3. Make sure you add the path to library files to your path environment variables.
- On Linux & OSX: do `export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib`
- On Windows: Add `%AF_PATH%\lib` to your PATH environment variable.
4. Add `arrayfire = "3.4.0"` to the dependencies section of your project's Cargo.toml file.
4. Add `arrayfire = "3.4.1"` to the dependencies section of your project's Cargo.toml file.

Once step (4) is over, you should be able to use ArrayFire in your Rust project. If you find any bugs, please report them [here](https://github.com/arrayfire/arrayfire-rust/issues).

Expand Down
81 changes: 81 additions & 0 deletions examples/acoustic_wave.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
extern crate arrayfire as af;

use af::*;
use std::f64::consts::*;

fn main() {
set_device(0);
info();

acoustic_wave_simulation();
}

fn normalise(a: &Array) -> Array {
(a/(max_all(&abs(a)).0 as f32 * 2.0f32)) + 0.5f32
}
fn acoustic_wave_simulation() {
// Speed of sound
let c = 0.1;
// Distance step
let dx = 0.5;
// Time step
let dt = 1.0;

// Grid size.
let nx = 1500;
let ny = 1500;

// Grid dimensions.
let dims = Dim4::new(&[nx, ny, 1, 1]);

// Pressure field
let mut p = constant::<f32>(0.0, dims);
// d(pressure)/dt field
let mut p_dot = p.clone();

// Laplacian (Del^2) convolution kernel.
let laplacian_values = [0.0f32, 1.0, 0.0,
1.0, -4.0, 1.0,
0.0, 1.0, 0.0];
let laplacian_kernel = Array::new(&laplacian_values, Dim4::new(&[3, 3, 1, 1])) / (dx * dx);

// Create a window to show the waves.
let mut win = Window::new(1000, 1000, "Waves".to_string());

// Hann windowed pulse.
let pulse_time = 100.0f64;
let centre_freq = 0.05;

// Number of samples in pulse.
let pulse_n = (pulse_time/dt).floor() as u64;

let i = range::<f32>(Dim4::new(&[pulse_n, 1, 1, 1]), 0);
let t = i.clone() * dt;
let hamming_window = cos(&(i * (2.0 * PI / pulse_n as f64))) * -0.46 + 0.54;
let wave = sin(&(&t * centre_freq * 2.0 * PI));
let pulse = wave * hamming_window;

// Iteration count.
let mut it = 0;

while !win.is_closed() {
// Convole with laplacian to get spacial second derivative.
let lap_p = convolve2(&p, &laplacian_kernel, ConvMode::DEFAULT, ConvDomain::SPATIAL);
// Calculate the updated pressure and d(pressure)/dt fields.
p_dot += lap_p * (c * dt);
p += &p_dot * dt;

if it < pulse_n {
// Location of the source.
let seqs = &[Seq::new(700.0, 800.0, 1.0), Seq::new(800.0, 800.0, 1.0)];
// Set the pressure there.
p = assign_seq(&p, seqs, &index(&pulse, &[Seq::new(it as f64, it as f64, 1.0)]));
}

// Draw the image.
win.set_colormap(af::ColorMap::BLUE);
win.draw_image(&normalise(&p), None);

it += 1;
}
}
30 changes: 28 additions & 2 deletions src/arith/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ extern crate num;

use dim4::Dim4;
use array::Array;
use defines::AfError;
use defines::{AfError, DType, Scalar};
use error::HANDLE_ERROR;
use self::libc::{c_int};
use data::{constant, tile};
use data::{constant, constant_t, tile};
use self::num::Complex;

use std::ops::Neg;

type Complex32 = Complex<f32>;
type Complex64 = Complex<f64>;
type MutAfArray = *mut self::libc::c_longlong;
type MutDouble = *mut self::libc::c_double;
type MutUint = *mut self::libc::c_uint;
Expand Down Expand Up @@ -485,3 +489,25 @@ bit_assign_func!(BitOrAssign, bitor_assign, bitor);
bit_assign_func!(BitXorAssign, bitxor_assign, bitxor);

}

///Implement negation trait for Array
impl Neg for Array {
type Output = Array;

fn neg(self) -> Self::Output {
match self.get_type() {
DType::S64 => (constant_t(Scalar::S64(0 as i64), self.dims(), DType::S64) - self),
DType::U64 => (constant_t(Scalar::U64(0 as u64), self.dims(), DType::U64) - self),
DType::C32 => (constant_t(Scalar::C32(Complex32::new(0.0, 0.0)), self.dims(), DType::C32) - self),
DType::C64 => (constant_t(Scalar::C64(Complex64::new(0.0, 0.0)), self.dims(), DType::C64) - self),
DType::F32 => (constant_t(Scalar::F32(0 as f32), self.dims(), DType::F32) - self),
DType::F64 => (constant_t(Scalar::F64(0 as f64), self.dims(), DType::F64) - self),
DType::B8 => (constant_t(Scalar::B8 (false ), self.dims(), DType::B8 ) - self),
DType::S32 => (constant_t(Scalar::S32(0 as i32), self.dims(), DType::S32) - self),
DType::U32 => (constant_t(Scalar::U32(0 as u32), self.dims(), DType::U32) - self),
DType::U8 => (constant_t(Scalar::U8 (0 as u8 ), self.dims(), DType::U8 ) - self),
DType::S16 => (constant_t(Scalar::S16(0 as i16), self.dims(), DType::S16) - self),
DType::U16 => (constant_t(Scalar::U16(0 as u16), self.dims(), DType::U16) - self),
}
}
}
138 changes: 137 additions & 1 deletion src/data/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ extern crate num;

use array::Array;
use dim4::Dim4;
use defines::AfError;
use defines::{AfError, DType, Scalar};
use error::HANDLE_ERROR;
use self::libc::{uint8_t, c_int, c_uint, c_double};
use self::num::Complex;
Expand Down Expand Up @@ -622,3 +622,139 @@ pub fn replace_scalar(a: &mut Array, cond: &Array, b: f64) {
HANDLE_ERROR(AfError::from(err_val));
}
}

/// Create a range of values of given type([DType](./enum.DType.html))
///
/// Creates an array with [0, n] values along the `seq_dim` which is tiled across other dimensions.
///
/// # Parameters
///
/// - `dims` is the size of Array
/// - `seq_dim` is the dimension along which range values are populated, all values along other
/// dimensions are just repeated
/// - `dtype` indicates whats the type of the Array to be created
///
/// # Return Values
/// Array
#[allow(unused_mut)]
pub fn range_t(dims: Dim4, seq_dim: i32, dtype: DType) -> Array {
unsafe {
let mut temp: i64 = 0;
let err_val = af_range(&mut temp as MutAfArray,
dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT,
seq_dim as c_int, dtype as uint8_t);
HANDLE_ERROR(AfError::from(err_val));
Array::from(temp)
}
}

/// Create a range of values of given type([DType](./enum.DType.html))
///
/// Create an sequence [0, dims.elements() - 1] and modify to specified dimensions dims and then tile it according to tile_dims.
///
/// # Parameters
///
/// - `dims` is the dimensions of the sequence to be generated
/// - `tdims` is the number of repitions of the unit dimensions
/// - `dtype` indicates whats the type of the Array to be created
///
/// # Return Values
///
/// Array
#[allow(unused_mut)]
pub fn iota_t(dims: Dim4, tdims: Dim4, dtype: DType) -> Array {
unsafe {
let mut temp: i64 = 0;
let err_val =af_iota(&mut temp as MutAfArray,
dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT,
tdims.ndims() as c_uint, tdims.get().as_ptr() as *const DimT,
dtype as uint8_t);
HANDLE_ERROR(AfError::from(err_val));
Array::from(temp)
}
}

/// Create an identity array with 1's in diagonal of given type([DType](./enum.DType.html))
///
/// # Parameters
///
/// - `dims` is the output Array dimensions
/// - `dtype` indicates whats the type of the Array to be created
///
/// # Return Values
///
/// Identity matrix
#[allow(unused_mut)]
pub fn identity_t(dims: Dim4, dtype: DType) -> Array {
unsafe {
let mut temp: i64 = 0;
let err_val = af_identity(&mut temp as MutAfArray,
dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT,
dtype as uint8_t);
HANDLE_ERROR(AfError::from(err_val));
Array::from(temp)
}
}

/// Create a constant array of given type([DType](./enum.DType.html))
///
/// You can use this function to create arrays of type dictated by the enum
/// [DType](./enum.DType.html) using the scalar `value` that has the shape similar
/// to `dims`.
///
/// # Parameters
///
/// - `value` is the [Scalar](./enum.Scalar.html) to be filled into the array
/// - `dims` is the output Array dimensions
/// - `dtype` indicates the type of Array to be created and is the type of the scalar to be passed
/// via the paramter `value`.
///
/// # Return Values
///
/// Array of `dims` shape and filed with given constant `value`.
#[allow(unused_mut)]
pub fn constant_t(value: Scalar, dims: Dim4, dtype: DType) -> Array {
use Scalar::*;

// Below macro is only visible to this function
// and it is used to abbreviate the repetitive const calls
macro_rules! expand_const_call {
($ffi_name: ident, $temp: expr, $v: expr, $dims: expr, $dt: expr) => ({
$ffi_name(&mut $temp as MutAfArray, $v as c_double,
$dims.ndims() as c_uint, $dims.get().as_ptr() as *const DimT, $dt)
})
}

unsafe {
let dt = dtype as c_int;
let mut temp: i64 = 0;
let err_val = match value {
C32(v) => {
af_constant_complex(&mut temp as MutAfArray, v.re as c_double, v.im as c_double,
dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, dt)
},
C64(v) => {
af_constant_complex(&mut temp as MutAfArray, v.re as c_double, v.im as c_double,
dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, dt)
},
S64(v) => {
af_constant_long(&mut temp as MutAfArray, v as Intl,
dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT)
},
U64(v) => {
af_constant_ulong(&mut temp as MutAfArray, v as Uintl,
dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT)
},
F32(v) => expand_const_call!(af_constant, temp, v, dims, dt),
F64(v) => expand_const_call!(af_constant, temp, v, dims, dt),
B8(v) => expand_const_call!(af_constant, temp, v as i32, dims, dt),
S32(v) => expand_const_call!(af_constant, temp, v, dims, dt),
U32(v) => expand_const_call!(af_constant, temp, v, dims, dt),
U8(v) => expand_const_call!(af_constant, temp, v, dims, dt),
S16(v) => expand_const_call!(af_constant, temp, v, dims, dt),
U16(v) => expand_const_call!(af_constant, temp, v, dims, dt),
};
HANDLE_ERROR(AfError::from(err_val));
Array::from(temp)
}
}
32 changes: 32 additions & 0 deletions src/defines.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
extern crate num;

use std::error::Error;
use std::fmt::{Display, Formatter};
use std::fmt::Error as FmtError;
use self::num::Complex;

/// Error codes
#[repr(C)]
Expand Down Expand Up @@ -397,3 +400,32 @@ pub const PHILOX : RandomEngineType = RandomEngineType::PHILOX_4X32_10;
pub const THREEFRY : RandomEngineType = RandomEngineType::THREEFRY_2X32_16;
pub const MERSENNE : RandomEngineType = RandomEngineType::MERSENNE_GP11213;
pub const DEFAULT_RANDOM_ENGINE : RandomEngineType = PHILOX;

/// Scalar value types
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Scalar {
/// 32 bit float
F32(f32),
/// 32 bit complex float
C32(Complex<f32>),
/// 64 bit float
F64(f64),
/// 64 bit complex float
C64(Complex<f64>),
/// 8 bit boolean
B8(bool),
/// 32 bit signed integer
S32(i32),
/// 32 bit unsigned integer
U32(u32),
/// 8 bit unsigned integer
U8(u8),
/// 64 bit signed integer
S64(i64),
/// 64 bit unsigned integer
U64(u64),
/// 16 bit signed integer
S16(i16),
/// 16 bit unsigned integer
U16(u16),
}
Loading

0 comments on commit f75a858

Please sign in to comment.