1

I'm getting an error while trying to multiply a vector component with an array (element-wise multiplication or broadcast). The docs show that this overloaded case for * should be fine:

AFAPI array operator* (const float &lhs, const array &rhs)
Multiplies two arrays or an array and a value. (const array&, const array&)

But according to the error message below, perhaps vect(0) needs to be further flattened or reduced so that the sizes are consistent?

The error statement is clear:

Invalid dimension for argument 1 Expected: ldims == rides


Below is the code:

#include <arrayfire.h>

int main(int argc, char *argv[])
{
    int device = argc > 1 ? atoi(argv[1]) : 0;
    af::setDevice(device);
    af::info();

    int n = 3;
    int N = 5;

    // Create the arrays:
    af::array matrix = af::constant(0,n,n,f32); // 3 x 3 float array of zeros
    af::array vect = af::seq(1,N); // A col vector of floats: {1.0, ... ,5.0}

    // Show the arrays:
    af_print(matrix);
    af_print(vect);

    // Print a single component of the vector:
    af_print(vect(0));

    // This line produces the error (see below):
    af_print(vect(0) * matrix); // Why doesn't this work?

    // But somthing like this is fine:
    af_print(1.0 * matrix);

    return 0;
}

Producing the output:

ArrayFire v3.3.2
ATI Radeon HD 6750M

matrix
[3 3 1 1]
0.0000 0.0000 0.0000
0.0000 0.0000 0.0000
0.0000 0.0000 0.0000

vect
[5 1 1 1]
1.0000
2.0000
3.0000
4.0000
5.0000

vect(0)
[1 1 1 1]
1.0000

The dims() output of af_print() for the matrix = [3 3 1 1], and vect(0) = [1 1 1 1], make me suspicious, but I'm not sure how to flatten further. One would think this example to be a common way of using the ArrayFire API.

The error exception that is thrown is:

libc++abi.dylib: terminating with uncaught exception of type af::exception: ArrayFire Exception (Invalid input size:203): In function getOutDims In file src/backend/ArrayInfo.cpp:173
Invalid dimension for argument 1 Expected: ldims == rides
In function af::array af::operator*(const af::array &, const af::array &)


Adding a use-case to clarify: In practice I am constructing a final array by summation of coeff(k) * (a 2-d slice of a 3-d array Z):

for (int j = 0; j<indx.dims(0); ++j)
  final += coeff(indx(j)) * Z(af::span,af::span,indx(j));

I'll look into using a gfor but initially just wanted to get the correct numerical output. Note also that the vector: index is predefined, e.g., say index = {1, 2, 4, 7, ...} and the elements are not necessarily in sequence; this allows the selection of specific terms.

Bruce Dean
  • 2,798
  • 2
  • 18
  • 30

2 Answers2

2

ArrayFire does not implicitly do vector array-scalar array element-wise operation (the case you say is failing). Only vector array-value ones are supported implicitly. To do what you are doing, you will need to use the tile() function as shown below.

af_print(tile(vect(0), matrix.dims()) * matrix);

Since the dimension being tiled is 1, tile will be used as a JIT function. There is no extra memory used here. The entire computation is done in a single kernel. Hence no performance hit either.

shehzan
  • 331
  • 1
  • 5
  • Is there further documentation on this, so that I can read up on it? I would like to make sure I understand what you are saying. It seems surprising that to multiply an array by a single element of another array, would require such an approach. I was assuming that `vect(i)` for the i-th element of the vector would translate into a "vector array-value" - but I guess that is wrong? Thanks again. – Bruce Dean Sep 30 '16 at 18:23
  • Just added a use-case to my question to help clarify what I am doing, thanks for your thoughts and feedback! – Bruce Dean Sep 30 '16 at 18:38
  • @BruceDean Because of the Just In time compiler inside arrayfire, the tile function does not actually allocate the necessary memory. It just changes the metadata internally and the arrayfire kernel will just read the same data over and over again when performing the multiplication. – Pavan Yalamanchili Sep 30 '16 at 19:54
1

Since OP added a usecase since the last answer, this is how you write a fully vectorized version in arrayfire.

array coeffs = moddims(coeff(indx), 1, 1, coeff.elements());
array final = sum(Z(span, span, indx) * tile(coeffs, Z.dims(0), Z.dims(1)), 2);
Pavan Yalamanchili
  • 12,021
  • 2
  • 35
  • 55
  • Wow, very nice. I didn't get your 1st line to work as is, the count of: `coeff.elments()`, doesn't match the count of `coeff(index).` I needed to do this: `array vect = coeff(index)`; then this worked: `array coeffs = moddims(vect, 1, 1, vect.elements(), 1);` – Bruce Dean Oct 01 '16 at 04:18