Skip to content

Move tutorial pages into a mdbook #204

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 1, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Improve existing tutorials
  • Loading branch information
9prady9 committed Oct 1, 2019
commit f426ea2b49d7412b5b3fb80298e7a571bd1db5b9
1 change: 0 additions & 1 deletion src/arith/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -857,7 +857,6 @@ mod op_assign {
bit_assign_func!(BitAndAssign, bitand_assign, bitand);
bit_assign_func!(BitOrAssign, bitor_assign, bitor);
bit_assign_func!(BitXorAssign, bitxor_assign, bitxor);

}

///Implement negation trait for Array
Expand Down
29 changes: 29 additions & 0 deletions tutorials-book/src/array_and_matrix_manipulation.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,3 +269,32 @@ transpose(&a, False) //Second parameter to be used for conjugate transpose
3.0000 1.0000 2.0000
3.0000 3.0000 1.0000
```

### Combining functions to enumerate grid coordinates

By using a combination of the functions, one can quickly code complex manipulation patterns with
a few lines of code. For example, consider generating (x,y) coordinates for a grid where each axis
goes from 1 to n. Instead of using several loops to populate our arrays we can just use a small
combination of the above functions.

```rust,noplaypen
let a = iota::<u32>(Dim4::new(&[3, 1, 1, 1]),
Dim4::new(&[1, 3, 1, 1]));
let b = transpose(&a, false);
let coords = join(1, &flat(&a), &flat(&b));
print(&coords);
```

The output for a `[3 3 1 1]` matrix will be the following.
```rust,noplaypen
[9 2 1 1]
0 0
1 0
2 0
0 1
1 1
2 1
0 2
1 2
2 2
```
18 changes: 17 additions & 1 deletion tutorials-book/src/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,23 @@ get it using the [scalar()](\ref af::array::scalar) function:

In addition to supporting standard mathematical functions, Arrays
that contain integer data types also support bitwise operators including
and, or, and shift etc.
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]);
let a = randu::<bool>(dims);
let b = randu::<bool>(dims);

print(&a);
print(&b);

let c = &a | &b; //Borrowing to avoid move of a and b, a | b is also valid
let d = bitand(&a, &b, false);

print(&c);
print(&d);
```

## Where to go for help?

Expand Down
12 changes: 9 additions & 3 deletions tutorials-book/src/indexing.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
# 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.

[Indexer](../struct.Indexer.html) structure is the key element used in Rust
wrapper for ArrayFire for creating references to existing Arrays. Given
below are few of such functions and their corresponding example use cases.
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.

## Using Seq objects to index Array

Create a view of an existing Array using Sequences and [index](../fn.index.html).
Create a view of an existing Array using Sequences and the function [index](../fn.index.html).

```rust,noplaypen
let dims = Dim4::new(&[5, 5, 1, 1]);
Expand Down Expand Up @@ -55,6 +59,8 @@ print(&sub);
// 2.0 2.0 2.0
```

> **NOTE** Normally you want to avoid accessing individual elements of the array like this for performance reasons.

## Using Array and Seq combination to index Array

Create a view of an existing Array using another Array and Sequence.
Expand Down
111 changes: 12 additions & 99 deletions tutorials-book/src/vectorization.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
# Vectorization

<!--
Programmers and Data Scientists want to take advantage of fast and parallel
computational devices. Writing vectorized code is necessary to get
therust,noplayperust,noplaypen performance out of the current generation parallel hardware and
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 tutorial, we present several methods to vectorize 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
-->
## 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:

Expand All @@ -26,7 +24,7 @@ A small subset of such vectorized ArrayFire functions are given below for quick

| Operator Category | Functions |
|--------------------------------------------------------------|----------------------------|
| Arithmetic operations | +, -, *, /, %, >>, << |
| 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. |
Expand Down Expand Up @@ -69,103 +67,18 @@ 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 still execute in parallel on your hardware.
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.

<!--
# Batching
## GFOR

The batchFunc() function allows the broad application of existing ArrayFire
functions to multiple sets of data. Effectively, batchFunc() allows ArrayFire
functions to execute in "batch processing" mode. In this mode, functions will
find a dimension which contains "batches" of data to be processed and will
parallelize the procedure.
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.

Consider the following example. Here we create a filter which we would like
to apply to each of the weight vectors. The naive solution would be using a
for-loop as we have seen previously:
## batch\_func

```rust,noplaypen
// Create the filter and the weight vectors
af::array filter = randn(1, 5);
af::array weights = randu(5, 5);

// Apply the filter using a for-loop
af::array filtered_weights = constant(0, 5, 5);
for(int i=0; i<weights.dims(1); ++i){
filtered_weights.col(i) = filter * weights.col(i);
}
```

However, as we have discussed above, this solution will be very inefficient.
One may be tempted to implement a vectorized solution as follows:

```rust,noplaypen
// Create the filter and the weight vectors
af::array filter = randn(1, 5);
af::array weights = randu(5, 5);

af::array filtered_weights = filter * weights; // fails due to dimension mismatch
```

However, the dimensions of `filter` and `weights` do not match, thus ArrayFire
will generate a runtime error.

`batchfunc()` was created to solve this specific problem.
The signature of the function is as follows:

```
array batchFunc(const array &lhs, const array &rhs, batchFunc_t func);
```

where `__batchFunc_t__` is a function pointer of the form:

```
typedef array (*batchFunc_t) (const array &lhs, const array &rhs);
```

So, to use batchFunc(), we need to provide the function we wish to apply as a
batch operation. For illustration's sake, let's "implement" a multiplication
function following the format.

```
af::array my_mult (const af::array &lhs, const af::array &rhs){
return lhs * rhs;
}
```

Our final batch call is not much more difficult than the ideal
syntax we imagined.

```
// Create the filter and the weight vectors
af::array filter = randn(1, 5);
af::array weights = randu(5, 5);

// Apply the batch function
af::array filtered_weights = batchFunc( filter, weights, my_mult );
```

The batch function will work with many previously mentioned vectorized ArrayFire
functions. It can even work with a combination of those functions if they are
wrapped inside a helper function matching the `__batchFunc_t__` signature.
One limitation of `batchfunc()` is that it cannot be used from within a
`gfor()` loop at the present time.

# Advanced Vectorization

We have seen the different methods ArrayFire provides to vectorize our code. Tying
them all together is a slightly more involved process that needs to consider data
dimensionality and layout, memory usage, nesting order, etc. An excellent example
and discussion of these factors can be found on our blog:

http://arrayfire.com/how-to-write-vectorized-code/

It's worth noting that the content discussed in the blog has since been transformed
into a convenient af::nearestNeighbour() function. Before writing something from
scratch, check that ArrayFire doesn't already have an implementation. The default
vectorized nature of ArrayFire and an extensive collection of functions will
speed things up in addition to replacing dozens of lines of code!
-->
This another pending feature that is similar to our C++ API of
[batchFunc()](http://arrayfire.org/docs/namespaceaf.htm#aa0eb9e160f5be4b95234543e5c47934b)