Conversion from af:Array to scalar
shyams2 opened this issue · comments
Is there a Python command to convert an ArrayFire array to a scalar?
Suppose I define a = af.Array([1,2,3])
. Then, a[1] gives me an af.Array of dimensions [1 1 1 1] containing the value of 2. But how do I get the scalar value of it directly? I'm currently using af.algorithm.sum(a[1])
Is there a more direct way to do this?
@ShyamSS-95 I just realized that is the fastest way for now. The C++ API has array.scalar<T>()
but that is copying the entire array to the host and then returning one element.
Created an issue upstream to add the necessry functionality: arrayfire/arrayfire#1725
@ShyamSS-95 Actually in your case, since a[1]
is just one element, you could do a[1].to_array()
to get a host array of size [1]
or a[1].to_array()[0]
to get a number.
Can you also tell in what scenario you are using this ? Because if you are copying to host costantly, it is better off if you do the copy once and then index the host instead of copying each element individually.
I'm using it in a loop for the implementation of a collision algorithm. Shown below is the code snippet where I've had to convert an af.Array to a scalar.
for i in range(no_of_particles):
x_particle_considered = af.data.constant(af.algorithm.sum(x_coordinates[i]), (no_of_particles-1-i))
y_particle_considered = af.data.constant(af.algorithm.sum(y_coordinates[i]), (no_of_particles-1-i))
x_coordinates_others = x_coordinates[(i+1):no_of_particles]
y_coordinates_others = y_coordinates[(i+1):no_of_particles]
# Determining the components of the vector joining particle i to all other particles
x_coordinates_others = x_coordinates_others-x_particle_considered
y_coordinates_others = y_coordinates_others-y_particle_considered
@ShyamSS-95 try this:
@af.broadcast
def sub(lhs, rhs):
return lhs - rhhs
for i in range(no_of_particles):
x_coordinates_others = x_coordinates[(i+1):no_of_particles]
y_coordinates_others = y_coordinates[(i+1):no_of_particles]
# Determining the components of the vector joining particle i to all other particles
x_coordinates_others = sub(x_coordinates_others, x_coordinates[i])
y_coordinates_others = sub(y_coordinates_others, y_coordinates[i])
Thanks! It's much easier to write. I wrote the following code to check the effect on speed:
import numpy as np
import arrayfire as af
import time
no_of_particles = 1000
test_array = np.random.rand(no_of_particles)
x_coordinates = y_coordinates = af.Array(test_array.ctypes.data, test_array.shape, test_array.dtype.char)
@af.broadcast
def sub(lhs, rhs):
return lhs - rhs
sum_time_start = time.time()
for i in range(no_of_particles-1):
x_coordinates_others = x_coordinates[(i+1):no_of_particles]
y_coordinates_others = y_coordinates[(i+1):no_of_particles]
x_coordinates_others = x_coordinates_others - af.data.constant(af.algorithm.sum(x_coordinates[i]), (no_of_particles-1-i))
y_coordinates_others = y_coordinates_others - af.data.constant(af.algorithm.sum(y_coordinates[i]), (no_of_particles-1-i))
sum_time_end = time.time()
print("Time elapsed using sum = ", (sum_time_end- sum_time_start) )
sub_time_start = time.time()
for i in range(no_of_particles-1):
x_coordinates_others = x_coordinates[(i+1):no_of_particles]
y_coordinates_others = y_coordinates[(i+1):no_of_particles]
x_coordinates_others = sub(x_coordinates_others, x_coordinates[i])
y_coordinates_others = sub(y_coordinates_others, y_coordinates[i])
sub_time_end = time.time()
print("Time elapsed using sub = ", (sub_time_end- sub_time_start) )
It runs faster as well:
Time elapsed using sum = 0.628760576248169
Time elapsed using sub = 0.25028181076049805
@ShyamSS-95 excellent 👍
af.broadcast allows you to perform elemnt wise operations where the dimensions are not identical. But when you are benchmarking, you need to have af.eval(x_coordinates_others, y_coordinates_others)
at the end of the loop and an af.sync()
after the loop.