collenchyma_blas/frameworks/
native.rs1use ::operation::*;
4use ::plugin::*;
5use ::transpose::*;
6use collenchyma::backend::Backend;
7use collenchyma::memory::MemoryType;
8use collenchyma::frameworks::native::Native;
9use collenchyma::plugin::Error;
10use rblas::math::mat::Mat;
11use rblas::matrix::Matrix;
12use rblas;
13
14macro_rules! impl_asum_for {
15 ($t:ident, $b:ty) => (
16 impl IOperationAsum<$t> for $b {
17 fn compute(&self, x: &MemoryType, result: &mut MemoryType) -> Result<(), Error> {
18 let x_slice = try!(x.as_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `x`."))).as_slice::<$t>();
19 let mut r_slice = try!(result.as_mut_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `result`."))).as_mut_slice::<$t>();
20 r_slice[0] = rblas::Asum::asum(x_slice);
21 Ok(())
22 }
23 }
24 );
25}
26
27macro_rules! impl_axpy_for {
28 ($t:ident, $b:ty) => (
29 impl IOperationAxpy<$t> for $b {
30 fn compute(&self, a: &MemoryType, x: &MemoryType, y: &mut MemoryType) -> Result<(), Error> {
31 let a_slice = try!(a.as_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `a`."))).as_slice::<$t>();
32 let x_slice = try!(x.as_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `x`."))).as_slice::<$t>();
33 let y_slice = try!(y.as_mut_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `y`."))).as_mut_slice::<$t>();
34 rblas::Axpy::axpy(&a_slice[0], x_slice, y_slice);
35 Ok(())
36 }
37 }
38 );
39}
40
41macro_rules! impl_copy_for {
42 ($t:ident, $b:ty) => (
43 impl IOperationCopy<$t> for $b {
44 fn compute(&self, x: &MemoryType, y: &mut MemoryType) -> Result<(), Error> {
45 let x_slice = try!(x.as_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `x`."))).as_slice::<$t>();
46 let y_slice = try!(y.as_mut_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `y`."))).as_mut_slice::<$t>();
47 rblas::Copy::copy(x_slice, y_slice);
48 Ok(())
49 }
50 }
51 );
52}
53
54macro_rules! impl_dot_for {
55 ($t:ident, $b:ty) => (
56 impl IOperationDot<$t> for $b {
57 fn compute(&self, x: &MemoryType, y: &MemoryType, result: &mut MemoryType) -> Result<(), Error> {
58 let x_slice = try!(x.as_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `x`."))).as_slice::<$t>();
59 let y_slice = try!(y.as_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `y`."))).as_slice::<$t>();
60 let mut r_slice = try!(result.as_mut_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `result`."))).as_mut_slice::<$t>();
61 r_slice[0] = rblas::Dot::dot(x_slice, y_slice);
62 Ok(())
63 }
64 }
65 );
66}
67
68macro_rules! impl_nrm2_for {
69 ($t:ident, $b:ty) => (
70 impl IOperationNrm2<$t> for $b {
71 fn compute(&self, x: &MemoryType, result: &mut MemoryType) -> Result<(), Error> {
72 let x_slice = try!(x.as_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `x`."))).as_slice::<$t>();
73 let mut r_slice = try!(result.as_mut_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `result`."))).as_mut_slice::<$t>();
74 r_slice[0] = rblas::Nrm2::nrm2(x_slice);
75 Ok(())
76 }
77 }
78 );
79}
80
81macro_rules! impl_scale_for {
82 ($t:ident, $b:ty) => (
83 impl IOperationScale<$t> for $b {
84 fn compute(&self, a: &MemoryType, x: &mut MemoryType) -> Result<(), Error> {
85 let a_slice = try!(a.as_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `a`."))).as_slice::<$t>();
86 let mut x_slice = try!(x.as_mut_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `x`."))).as_mut_slice::<$t>();
87 rblas::Scal::scal(&a_slice[0], x_slice);
88 Ok(())
89 }
90 }
91 );
92}
93
94macro_rules! impl_swap_for {
95 ($t:ident, $b:ty) => (
96 impl IOperationSwap<$t> for $b {
97 fn compute(&self, x: &mut MemoryType, y: &mut MemoryType) -> Result<(), Error> {
98 let mut x_slice = try!(x.as_mut_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `x`."))).as_mut_slice::<$t>();
99 let mut y_slice = try!(y.as_mut_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `y`."))).as_mut_slice::<$t>();
100 rblas::Swap::swap(x_slice, y_slice);
101 Ok(())
102 }
103 }
104 );
105}
106
107macro_rules! impl_gemm_for {
108 ($t:ident, $b:ty) => (
109 impl IOperationGemm<$t> for $b {
110 fn compute(&self, alpha: &MemoryType, at: Transpose, a_dims: &[usize], a: &MemoryType, bt: Transpose, b_dims: &[usize], b: &MemoryType, beta: &MemoryType, c_dims: &[usize], c: &mut MemoryType) -> Result<(), ::collenchyma::error::Error> {
111 let alpha_slice = try!(alpha.as_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `alpha`."))).as_slice::<$t>();
112 let a_slice = try!(a.as_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `a`."))).as_slice::<$t>();
113 let beta_slice = try!(beta.as_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `beta`."))).as_slice::<$t>();
114 let b_slice = try!(b.as_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `b`."))).as_slice::<$t>();
115 let mut c_slice = try!(c.as_mut_native().ok_or(Error::MissingMemoryForDevice("Unable to receive native memory for `c`."))).as_mut_slice::<$t>();
116
117 let a_matrix = as_matrix(a_slice, a_dims);
118 let b_matrix = as_matrix(b_slice, b_dims);
119 let mut c_matrix = as_matrix(c_slice, c_dims);
120 rblas::Gemm::gemm(&alpha_slice[0], at.to_rblas(), &a_matrix, bt.to_rblas(), &b_matrix, &beta_slice[0], &mut c_matrix);
121 read_from_matrix(&c_matrix, c_slice);
122 Ok(())
123 }
124 }
125 );
126}
127
128macro_rules! impl_iblas_for {
129 ($t:ident, $b:ty) => (
130 impl_asum_for!($t, $b);
131 impl_axpy_for!($t, $b);
132 impl_copy_for!($t, $b);
133 impl_dot_for!($t, $b);
134 impl_nrm2_for!($t, $b);
135 impl_scale_for!($t, $b);
136 impl_swap_for!($t, $b);
137
138 impl_gemm_for!($t, $b);
139
140 impl IBlas<$t> for $b { }
141
142 impl Asum<$t> for $b {
145 iblas_asum_for!($t, $b);
146 }
147
148 impl Axpy<$t> for $b {
149 iblas_axpy_for!($t, $b);
150 }
151
152 impl Copy<$t> for $b {
153 iblas_copy_for!($t, $b);
154 }
155
156 impl Dot<$t> for $b {
157 iblas_dot_for!($t, $b);
158 }
159
160 impl Nrm2<$t> for $b {
161 iblas_nrm2_for!($t, $b);
162 }
163
164 impl Scal<$t> for $b {
165 iblas_scale_for!($t, $b);
166 }
167
168 impl Swap<$t> for $b {
169 iblas_swap_for!($t, $b);
170 }
171
172 impl Gemm<$t> for $b {
173 iblas_gemm_for!($t, $b);
174 }
175 );
176}
177
178impl_iblas_for!(f32, Backend<Native>);
179impl_iblas_for!(f64, Backend<Native>);
180
181fn as_matrix<T: Clone + ::std::fmt::Debug>(slice: &[T], dims: &[usize]) -> Mat<T> {
183 let n = dims[0];
184 let m = dims.iter().skip(1).fold(1, |prod, i| prod * i);
185 let mut mat: Mat<T> = Mat::new(n, m);
186 for i in 0..n {
187 for j in 0..m {
188 let index = m * i + j;
189 unsafe {
190 *mat.as_mut_ptr().offset(index as isize) = slice[index].clone();
191 }
192 }
193 }
194
195 mat
196}
197
198fn read_from_matrix<T: Clone>(mat: &Mat<T>, slice: &mut [T]) {
199 let n = mat.rows();
200 let m = mat.cols();
201 for i in 0..n {
202 for j in 0..m {
203 let index = m * i + j;
204 slice[index] = mat[i][j].clone();
205 }
206 }
207}
208
209#[cfg(test)]
210mod test {
211 use collenchyma::backend::{Backend, BackendConfig};
212 use collenchyma::framework::IFramework;
213 use collenchyma::frameworks::Native;
214 use collenchyma::tensor::SharedTensor;
215 use collenchyma::memory::MemoryType;
216 use super::as_matrix;
217
218 fn get_native_backend() -> Backend<Native> {
219 let framework = Native::new();
220 let hardwares = framework.hardwares().to_vec();
221 let backend_config = BackendConfig::new(framework, &hardwares);
222 Backend::new(backend_config).unwrap()
223 }
224
225 pub fn write_to_memory<T: Copy>(mem: &mut MemoryType, data: &[T]) {
226 match mem {
227 &mut MemoryType::Native(ref mut mem) => {
228 let mut mem_buffer = mem.as_mut_slice::<T>();
229 for (index, datum) in data.iter().enumerate() {
230 mem_buffer[index] = *datum;
231 }
232 },
233 #[cfg(any(feature = "cuda", feature = "opencl"))]
234 _ => assert!(false)
235 }
236 }
237
238 #[test]
240 fn it_converts_correctly_to_and_from_matrix() {
241 let backend = get_native_backend();
242 let mut a = SharedTensor::<f32>::new(backend.device(), &vec![3, 2]).unwrap();
243 write_to_memory(a.get_mut(backend.device()).unwrap(),
244 &[2f32, 5f32,
245 2f32, 5f32,
246 2f32, 5f32]);
247
248 {
249 let a_slice_in = a.get(backend.device()).unwrap().as_native().unwrap().as_slice::<f32>();
250 let a_mat = as_matrix(a_slice_in, &[3, 2]);
251 assert_eq!(a_mat[0][0], 2f32);
253 assert_eq!(a_mat[0][1], 5f32);
254 assert_eq!(a_mat[1][0], 2f32);
255 assert_eq!(a_mat[1][1], 5f32);
256 assert_eq!(a_mat[2][0], 2f32);
257 assert_eq!(a_mat[2][1], 5f32);
258 }
259 }
260}