arrayfire/core/macros.rs
1/// Macro to print the current stats of ArrayFire's memory manager.
2///
3/// `mem_info!` print 4 values:
4///
5/// Name | Description
6/// -------------------------|-------------------------
7/// Allocated Bytes | Total number of bytes allocated by the memory manager
8/// Allocated Buffers | Total number of buffers allocated
9/// Locked (In Use) Bytes | Number of bytes that are in use by active arrays
10/// Locked (In Use) Buffers | Number of buffers that are in use by active arrays
11///
12/// The `Allocated Bytes` is always a multiple of the memory step size. The
13/// default step size is 1024 bytes. This means when a buffer is to be
14/// allocated, the size is always rounded up to a multiple of the step size.
15/// You can use [get_mem_step_size](./fn.get_mem_step_size.html) to check the
16/// current step size and [set_mem_step_size](./fn.set_mem_step_size.html) to
17/// set a custom resolution size.
18///
19/// The `Allocated Buffers` is the number of buffers that use up the allocated
20/// bytes. This includes buffers currently in scope, as well as buffers marked
21/// as free, ie, from arrays gone out of scope. The free buffers are available
22/// for use by new arrays that might be created.
23///
24/// The `Locked Bytes` is the number of bytes in use that cannot be
25/// reallocated at the moment. The difference of Allocated Bytes and Locked
26/// Bytes is the total bytes available for reallocation.
27///
28/// The `Locked Buffers` is the number of buffer in use that cannot be
29/// reallocated at the moment. The difference of Allocated Buffers and Locked
30/// Buffers is the number of buffers available for reallocation.
31///
32/// # Parameters
33///
34/// - `msg` is the message that is printed to screen before printing stats
35///
36/// # Examples
37///
38/// ```rust
39/// use arrayfire::{Dim4, device_mem_info, print, randu, mem_info};
40///
41/// let dims = Dim4::new(&[5, 5, 1, 1]);
42/// let a = randu::<f32>(dims);
43/// print(&a);
44/// mem_info!("Hello!");
45/// ```
46///
47/// Sample Output:
48///
49/// ```text
50/// AF Memory: Here
51/// Allocated [ Bytes | Buffers ] = [ 4096 | 4 ]
52/// In Use [ Bytes | Buffers ] = [ 2048 | 2 ]
53/// ```
54#[macro_export]
55macro_rules! mem_info {
56 [$msg: expr] => {
57 {
58 let (abytes, abuffs, lbytes, lbuffs) = $crate::device_mem_info();
59 println!("AF Memory: {:?}", $msg);
60 println!("Allocated [Bytes | Buffers] = [ {} | {} ]", abytes, abuffs);
61 println!("In Use [Bytes | Buffers] = [ {} | {} ]", lbytes, lbuffs);
62 }
63 };
64}
65
66/// Join multiple Arrays along a given dimension
67///
68/// All the Arrays provided to this macro should be of type `&Array`
69///
70/// # Examples
71///
72/// ```rust
73/// use arrayfire::{Dim4, join_many, print, randu};
74///
75/// let a = &randu::<f32>(Dim4::new(&[5, 3, 1, 1]));
76/// let b = &randu::<f32>(Dim4::new(&[5, 3, 1, 1]));
77/// let c = &randu::<f32>(Dim4::new(&[5, 3, 1, 1]));
78/// let d = join_many![2; a, b, c];
79/// print(&d);
80/// ```
81///
82/// # Panics
83///
84/// This macro just calls [join_many](./fn.join_many.html) function after collecting all
85/// the input arrays into a vector.
86// Using macro to implement join many wrapper
87#[macro_export]
88macro_rules! join_many {
89 [$dim: expr; $($x:expr),+] => {
90 {
91 let mut temp_vec = Vec::new();
92 $(
93 temp_vec.push($x);
94 )*
95 $crate::join_many($dim, temp_vec)
96 }
97 };
98}
99
100/// Print given message before printing out the Array to standard output
101///
102/// # Examples
103///
104/// ```rust
105/// use arrayfire::{Dim4, print_gen, randu, af_print};
106/// let dims = Dim4::new(&[3, 1, 1, 1]);
107/// let a = randu::<f32>(dims);
108/// af_print!("Create a 5-by-3 matrix of random floats on the GPU", a);
109/// ```
110///
111#[macro_export]
112macro_rules! af_print {
113 [$msg: expr, $x: expr] => {
114 {
115 $crate::print_gen(String::from($msg), &$x, Some(4));
116 }
117 };
118}
119
120/// Create a dim4 object from provided dimensions
121///
122/// The user can pass 1 or more sizes and the left over values will default to 1.
123#[macro_export]
124macro_rules! dim4 {
125 ($dim0:expr) => {
126 $crate::Dim4::new(&[$dim0, 1, 1, 1])
127 };
128 ($dim0:expr, $dim1:expr) => {
129 $crate::Dim4::new(&[$dim0, $dim1, 1, 1])
130 };
131 ($dim0:expr, $dim1:expr, $dim2:expr) => {
132 $crate::Dim4::new(&[$dim0, $dim1, $dim2, 1])
133 };
134 ($dim0:expr, $dim1:expr, $dim2:expr, $dim3:expr) => {
135 $crate::Dim4::new(&[$dim0, $dim1, $dim2, $dim3])
136 };
137}
138
139/// Create a sequence object
140///
141/// If type is not provided, then the Seq will default to i32 type
142#[macro_export]
143macro_rules! seq {
144 () => {
145 $crate::Seq::<i32>::default()
146 };
147 ($sty:ty; $start:literal : $end:literal : $step:literal) => {
148 $crate::Seq::<$sty>::new($start, $end, $step)
149 };
150 ($start:literal : $end:literal : $step:literal) => {
151 $crate::Seq::<i32>::new($start, $end, $step)
152 };
153 ($sty:ty; $start:expr , $end:expr , $step:expr) => {
154 $crate::Seq::<$sty>::new($start, $end, $step)
155 };
156 ($start:expr , $end:expr , $step:expr) => {
157 $crate::Seq::<i32>::new($start, $end, $step)
158 };
159}
160
161/// Indexing into an existing Array
162///
163/// This macro call with return an Array that has a view of another Array. The Array returned due to
164/// the indexing operation will follow copy-on-write semantics. The Array identifier taken by this
165/// macro is passed to the relevant internal functions as a borrowed reference. Thus, this identifier
166/// will be still available for futher use after the macro call.
167///
168/// The following types of inputs are matched by this macro.
169///
170/// - A simple Array identifier.
171/// - An Array with slicing info for indexing.
172/// - An Array with slicing info and other arrays used for indexing.
173///
174/// Examples on how to use this macro are provided in the [tutorials book][1]
175///
176/// [1]: http://arrayfire.org/arrayfire-rust/book/indexing.html
177#[macro_export]
178macro_rules! view {
179 (@af_max_dims) => {
180 4
181 };
182 ( $array_ident:ident ) => {
183 $array_ident.clone()
184 };
185 ( $array_ident:ident [ $($start:literal : $end:literal : $step:literal),+ ] ) => {
186 {
187 #[allow(non_snake_case)]
188 let AF_MAX_DIMS: usize = view!(@af_max_dims);
189 let mut seq_vec = Vec::<$crate::Seq<i32>>::with_capacity(AF_MAX_DIMS);
190 $(
191 seq_vec.push($crate::seq!($start:$end:$step));
192 )*
193 $crate::index(&$array_ident, &seq_vec)
194 }
195 };
196 (@set_indexer $idim:expr, $idxr:ident, $lterm:expr) => {
197 {
198 $idxr.set_index(&$lterm, $idim, None);
199 }
200 };
201 (@set_indexer $idim:expr, $idxr:ident, $hterm:expr, $($tterm:expr),*) => {
202 {
203 $idxr.set_index(&$hterm, $idim, None);
204 view!(@set_indexer $idim + 1, $idxr, $($tterm),*);
205 }
206 };
207 ($array_ident:ident [ $($_e:expr),+ ]) => {
208 {
209 let mut idxrs = $crate::Indexer::default();
210 view!(@set_indexer 0, idxrs, $($_e),*);
211 $crate::index_gen(&$array_ident, idxrs)
212 }
213 };
214}
215
216/// Macro to evaluate individual Arrays or assignment operations
217///
218/// - Evaluate on one or more Array identifiers: essentially calls [Array::eval][4] on each of those
219/// Array objects individually.
220///
221/// ```rust
222/// use arrayfire::{dim4, eval, randu};
223/// let dims = dim4!(5, 5);
224/// let a = randu::<f32>(dims);
225/// let b = a.clone();
226/// let c = a.clone();
227/// let d = a.clone();
228/// let x = a - b;
229/// let y = c * d;
230/// eval!(&x, &y);
231/// ```
232///
233/// - Evaluate assignment operations: This is essentially syntactic sugar for modifying portions of
234/// Array with another Array using a combination of [Sequences][1] and/or [Array][2] objects.
235/// Full examples for this use case are provided in the [tutorials book][3]
236///
237/// [1]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Seq.html
238/// [2]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html
239/// [3]: http://arrayfire.org/arrayfire-rust/book/indexing.html
240/// [4]: http://arrayfire.org/arrayfire-rust/arrayfire/struct.Array.html#method.eval
241#[macro_export]
242macro_rules! eval {
243 ( $l:ident [ $($lb:literal : $le:literal : $ls:literal),+ ] =
244 $r:ident [ $($rb:literal : $re:literal : $rs:literal),+ ]) => {
245 {
246 #[allow(non_snake_case)]
247 let AF_MAX_DIMS: usize = view!(@af_max_dims);
248 let mut seq_vec = Vec::<$crate::Seq<i32>>::with_capacity(AF_MAX_DIMS);
249 $(
250 seq_vec.push($crate::seq!($lb:$le:$ls));
251 )*
252 let mut idxrs = $crate::Indexer::default();
253 for i in 0..seq_vec.len() {
254 idxrs.set_index(&seq_vec[i], i as u32, None);
255 }
256 let eq_rterm = $crate::view!($r[ $($rb:$re:$rs),+ ]);
257 $crate::assign_gen(&mut $l, &idxrs, &eq_rterm);
258 }
259 };
260 ( $l:ident [ $($lb:literal : $le:literal : $ls:literal),+ ] = $r:expr ) => {
261 {
262 #[allow(non_snake_case)]
263 let AF_MAX_DIMS: usize = view!(@af_max_dims);
264 let mut seq_vec = Vec::<$crate::Seq<i32>>::with_capacity(AF_MAX_DIMS);
265 $(
266 seq_vec.push($crate::seq!($lb:$le:$ls));
267 )*
268 let mut idxrs = $crate::Indexer::default();
269 for i in 0..seq_vec.len() {
270 idxrs.set_index(&seq_vec[i], i as u32, None);
271 }
272 $crate::assign_gen(&mut $l, &idxrs, &$r);
273 }
274 };
275 ($lhs:ident [ $($lhs_e:expr),+ ] = $rhs:ident [ $($rhs_e:expr),+ ]) => {
276 {
277 let eq_rterm = $crate::view!($rhs[ $($rhs_e),+ ]);
278 let mut idxrs = $crate::Indexer::default();
279 view!(@set_indexer 0, idxrs, $($lhs_e),*);
280 $crate::assign_gen(&mut $lhs, &idxrs, &eq_rterm);
281 }
282 };
283 ($lhs:ident [ $($lhs_e:expr),+ ] = $rhs:expr) => {
284 {
285 let mut idxrs = $crate::Indexer::default();
286 view!(@set_indexer 0, idxrs, $($lhs_e),*);
287 $crate::assign_gen(&mut $lhs, &idxrs, &$rhs);
288 }
289 };
290 [$($x:expr),+] => {
291 {
292 let mut temp_vec = Vec::new();
293 $(
294 temp_vec.push($x);
295 )*
296 $crate::eval_multiple(temp_vec)
297 }
298 };
299}
300
301/// Create an array of given shape filled with a single value a.k.a constant array
302///
303/// # Examples
304///
305/// ```rust
306/// # use arrayfire::{constant};
307/// let _zeros_1d = constant!(0.0f32; 10);
308/// let _ones_3d = constant!(1u32; 3, 3, 3);
309///
310/// let dim = 10;
311/// let mix_shape = constant!(42.0f32; dim, 10);
312/// ```
313#[macro_export]
314macro_rules! constant {
315 ($value:expr; $($dim:expr),+) => {
316 $crate::constant($value, $crate::dim4!($($dim),*))
317 };
318}
319
320/// Create an array of given shape sampled from uniform distribution
321///
322/// If no type argument is specified, the data type defaults to 32 bit floats.
323///
324/// # Examples
325///
326/// ```rust
327/// # use arrayfire::{randu};
328/// let mat10x10 = randu!(10, 10);
329/// ```
330#[macro_export]
331macro_rules! randu {
332 ($($dim:expr),+) => { $crate::randu::<f32>($crate::dim4!($($dim),*)) };
333 ($type:ty; $($dim:expr),+) => { $crate::randu::<$type>($crate::dim4!($($dim),*)) };
334}
335
336/// Create an array of given shape sampled from normal distribution
337///
338/// If no type argument is specified, the data type defaults to 32 bit floats.
339///
340/// # Examples
341///
342/// ```rust
343/// # use arrayfire::{randn};
344/// let mat10x10 = randn!(10, 10);
345/// ```
346#[macro_export]
347macro_rules! randn {
348 ($($dim:expr),+) => { $crate::randn::<f32>($crate::dim4!($($dim),*)) };
349 ($type:ty; $($dim:expr),+) => { $crate::randn::<$type>($crate::dim4!($($dim),*)) };
350}
351
352#[cfg(test)]
353mod tests {
354 use super::super::array::Array;
355 use super::super::data::constant;
356 use super::super::device::set_device;
357 use super::super::index::index;
358 use super::super::random::randu;
359
360 #[test]
361 fn dim4_construction() {
362 let dim1d = dim4!(2);
363 let dim2d = dim4!(2, 3);
364 let dim3d = dim4!(2, 3, 4);
365 let dim4d = dim4!(2, 3, 4, 2);
366 let _dimn = dim4!(dim1d[0], dim2d[1], dim3d[2], dim4d[3]);
367 }
368
369 #[test]
370 fn seq_construction() {
371 let default_seq = seq!();
372 let _range_1_to_10_step_1 = seq!(0:9:1);
373 let _range_1_to_10_step_1_2 = seq!(f32; 0.0:9.0:1.5);
374 let _range_from_exprs = seq!(default_seq.begin(), default_seq.end(), default_seq.step());
375 let _range_from_exprs2 = seq!(f32; default_seq.begin() as f32,
376 default_seq.end() as f32, default_seq.step() as f32);
377 }
378
379 #[test]
380 fn seq_view() {
381 set_device(0);
382 let mut dim4d = dim4!(5, 3, 2, 1);
383 dim4d[2] = 1;
384
385 let a = randu::<f32>(dim4d);
386 let seqs = &[seq!(1:3:1), seq!()];
387 let _sub = index(&a, seqs);
388 }
389
390 #[test]
391 fn seq_view2() {
392 set_device(0);
393 // ANCHOR: seq_view2
394 let a = randu::<f32>(dim4!(5, 5));
395 let _sub = view!(a[1:3:1, 1:1:0]); // 1:1:0 means all elements along axis
396
397 // ANCHOR_END: seq_view2
398 }
399
400 #[test]
401 fn view_macro() {
402 set_device(0);
403 let dims = dim4!(5, 5, 2, 1);
404 let a = randu::<f32>(dims);
405 let b = a.clone();
406 let c = a.clone();
407 let d = a.clone();
408 let e = a.clone();
409
410 let _v = view!(a);
411
412 let _m = view!(c[1:3:1, 1:3:2]);
413
414 let x = seq!(1:3:1);
415 let y = seq!(1:3:2);
416 let _u = view!(b[x, y]);
417
418 let values: [u32; 3] = [1, 2, 3];
419 let indices = Array::new(&values, dim4!(3, 1, 1, 1));
420 let indices2 = Array::new(&values, dim4!(3, 1, 1, 1));
421
422 let _w = view!(d[indices, indices2]);
423
424 let _z = view!(e[indices, y]);
425 }
426
427 #[test]
428 fn eval_assign_seq_indexed_array() {
429 set_device(0);
430 let dims = dim4!(5, 5);
431 let mut a = randu::<f32>(dims);
432 //print(&a);
433 //[5 5 1 1]
434 // 0.6010 0.5497 0.1583 0.3636 0.6755
435 // 0.0278 0.2864 0.3712 0.4165 0.6105
436 // 0.9806 0.3410 0.3543 0.5814 0.5232
437 // 0.2126 0.7509 0.6450 0.8962 0.5567
438 // 0.0655 0.4105 0.9675 0.3712 0.7896
439
440 let b = randu::<f32>(dims);
441 //print(&b);
442 //[5 5 1 1]
443 // 0.8966 0.5143 0.0123 0.7917 0.2522
444 // 0.0536 0.3670 0.3988 0.1654 0.9644
445 // 0.5775 0.3336 0.9787 0.8657 0.4711
446 // 0.2908 0.0363 0.2308 0.3766 0.3637
447 // 0.9941 0.5349 0.6244 0.7331 0.9643
448
449 let d0 = seq!(1:2:1);
450 let d1 = seq!(1:2:1);
451 let s0 = seq!(1:2:1);
452 let s1 = seq!(1:2:1);
453 eval!(a[d0, d1] = b[s0, s1]);
454 //print(&a);
455 //[5 5 1 1]
456 // 0.6010 0.5497 0.1583 0.3636 0.6755
457 // 0.0278 0.3670 0.3988 0.4165 0.6105
458 // 0.9806 0.3336 0.9787 0.5814 0.5232
459 // 0.2126 0.7509 0.6450 0.8962 0.5567
460 // 0.0655 0.4105 0.9675 0.3712 0.7896
461 }
462
463 #[test]
464 fn eval_assign_array_to_seqd_array() {
465 set_device(0);
466 // ANCHOR: macro_seq_assign
467 let mut a = randu::<f32>(dim4!(5, 5));
468 let b = randu::<f32>(dim4!(2, 2));
469 eval!(a[1:2:1, 1:2:1] = b);
470 // ANCHOR_END: macro_seq_assign
471 }
472
473 #[test]
474 fn macro_seq_array_assign() {
475 set_device(0);
476 // ANCHOR: macro_seq_array_assign
477 let values: [f32; 3] = [1.0, 2.0, 3.0];
478 let indices = Array::new(&values, dim4!(3));
479 let seq4gen = seq!(0:2:1);
480 let mut a = randu::<f32>(dim4!(5, 3));
481
482 let b = constant(2.0 as f32, dim4!(3, 3));
483
484 eval!(a[indices, seq4gen] = b);
485 // ANCHOR_END: macro_seq_array_assign
486 }
487
488 #[test]
489 fn constant_macro() {
490 set_device(0);
491 let _zeros_1d = constant!(0.0f32; 10);
492 let _zeros_2d = constant!(0.0f64; 5, 5);
493 let _ones_3d = constant!(1u32; 3, 3, 3);
494 let _twos_4d = constant!(2u16; 2, 2, 2, 2);
495
496 let dim = 10;
497 let _mix_shape = constant!(42.0f32; dim, 10);
498 }
499
500 #[test]
501 fn rand_macro() {
502 set_device(0);
503 let _ru5x5 = randu!(5, 5);
504 let _rn5x5 = randn!(5, 5);
505 let _ruu32_5x5 = randu!(u32; 5, 5);
506 let _ruu8_5x5 = randu!(u8; 5, 5);
507 }
508}