← 返回首页
broadcasting in af_arith for binary operations by syurkevi · Pull Request #2871 · arrayfire/arrayfire · GitHub
Skip to content

Navigation Menu

Toggle navigation
Sign in
Appearance settings
Search or jump to...

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Resetting focus
89 changes: 72 additions & 17 deletions src/api/c/binary.cpp
Show comments View file Edit file Delete file Open in desktop
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <backend.hpp>
#include <common/ArrayInfo.hpp>
#include <common/err_common.hpp>
#include <common/moddims.hpp>
#include <common/tile.hpp>
#include <handle.hpp>
#include <implicit.hpp>
#include <optypes.hpp>
Expand All @@ -29,8 +31,11 @@
using af::dim4;
using af::dtype;
using common::half;
using common::modDims;
using common::tile;
using detail::arithOp;
using detail::arithOpD;
using detail::Array;
using detail::cdouble;
using detail::cfloat;
using detail::intl;
Expand All @@ -55,6 +60,36 @@ static inline af_array arithOp(const af_array lhs, const af_array rhs,
return getHandle(arithOp<T, op>(l, r, odims));
}

template<typename T, af_op_t op>
static inline af_array arithOpBroadcast(const af_array lhs,
const af_array rhs) {
const ArrayInfo &linfo = getInfo(lhs);
const ArrayInfo &rinfo = getInfo(rhs);

dim4 odims(1), ltile(1), rtile(1);
dim4 lshape = linfo.dims();
dim4 rshape = rinfo.dims();

for (int d = 0; d < AF_MAX_DIMS; ++d) {
DIM_ASSERT(
1, ((lshape[d] == rshape[d]) || (lshape[d] == 1 && rshape[d] > 1) ||
(lshape[d] > 1 && rshape[d] == 1)));
odims[d] = std::max(lshape[d], rshape[d]);
if (lshape[d] == rshape[d]) {
ltile[d] = rtile[d] = 1;
} else if (lshape[d] == 1 && rshape[d] > 1) {
ltile[d] = odims[d];
} else if (lshape[d] > 1 && rshape[d] == 1) {
rtile[d] = odims[d];
}
}

Array<T> lhst = common::tile<T>(modDims(getArray<T>(lhs), lshape), ltile);
Array<T> rhst = common::tile<T>(modDims(getArray<T>(rhs), rshape), rtile);

return getHandle(arithOp<T, op>(lhst, rhst, odims));
}

template<typename T, af_op_t op>
static inline af_array sparseArithOp(const af_array lhs, const af_array rhs) {
auto res = arithOp<T, op>(getSparseArray<T>(lhs), getSparseArray<T>(rhs));
Expand Down Expand Up @@ -82,25 +117,45 @@ static af_err af_arith(af_array *out, const af_array lhs, const af_array rhs,
const ArrayInfo &linfo = getInfo(lhs);
const ArrayInfo &rinfo = getInfo(rhs);

dim4 odims = getOutDims(linfo.dims(), rinfo.dims(), batchMode);

const af_dtype otype = implicit(linfo.getType(), rinfo.getType());
af_array res;
switch (otype) {
case f32: res = arithOp<float, op>(lhs, rhs, odims); break;
case f64: res = arithOp<double, op>(lhs, rhs, odims); break;
case c32: res = arithOp<cfloat, op>(lhs, rhs, odims); break;
case c64: res = arithOp<cdouble, op>(lhs, rhs, odims); break;
case s32: res = arithOp<int, op>(lhs, rhs, odims); break;
case u32: res = arithOp<uint, op>(lhs, rhs, odims); break;
case u8: res = arithOp<uchar, op>(lhs, rhs, odims); break;
case b8: res = arithOp<char, op>(lhs, rhs, odims); break;
case s64: res = arithOp<intl, op>(lhs, rhs, odims); break;
case u64: res = arithOp<uintl, op>(lhs, rhs, odims); break;
case s16: res = arithOp<short, op>(lhs, rhs, odims); break;
case u16: res = arithOp<ushort, op>(lhs, rhs, odims); break;
case f16: res = arithOp<half, op>(lhs, rhs, odims); break;
default: TYPE_ERROR(0, otype);

if (batchMode || linfo.dims() == rinfo.dims()) {
dim4 odims = getOutDims(linfo.dims(), rinfo.dims(), batchMode);

switch (otype) {
case f32: res = arithOp<float, op>(lhs, rhs, odims); break;
case f64: res = arithOp<double, op>(lhs, rhs, odims); break;
case c32: res = arithOp<cfloat, op>(lhs, rhs, odims); break;
case c64: res = arithOp<cdouble, op>(lhs, rhs, odims); break;
case s32: res = arithOp<int, op>(lhs, rhs, odims); break;
case u32: res = arithOp<uint, op>(lhs, rhs, odims); break;
case u8: res = arithOp<uchar, op>(lhs, rhs, odims); break;
case b8: res = arithOp<char, op>(lhs, rhs, odims); break;
case s64: res = arithOp<intl, op>(lhs, rhs, odims); break;
case u64: res = arithOp<uintl, op>(lhs, rhs, odims); break;
case s16: res = arithOp<short, op>(lhs, rhs, odims); break;
case u16: res = arithOp<ushort, op>(lhs, rhs, odims); break;
case f16: res = arithOp<half, op>(lhs, rhs, odims); break;
default: TYPE_ERROR(0, otype);
}
} else {
switch (otype) {
case f32: res = arithOpBroadcast<float, op>(lhs, rhs); break;
case f64: res = arithOpBroadcast<double, op>(lhs, rhs); break;
case c32: res = arithOpBroadcast<cfloat, op>(lhs, rhs); break;
case c64: res = arithOpBroadcast<cdouble, op>(lhs, rhs); break;
case s32: res = arithOpBroadcast<int, op>(lhs, rhs); break;
case u32: res = arithOpBroadcast<uint, op>(lhs, rhs); break;
case u8: res = arithOpBroadcast<uchar, op>(lhs, rhs); break;
case b8: res = arithOpBroadcast<char, op>(lhs, rhs); break;
case s64: res = arithOpBroadcast<intl, op>(lhs, rhs); break;
case u64: res = arithOpBroadcast<uintl, op>(lhs, rhs); break;
case s16: res = arithOpBroadcast<short, op>(lhs, rhs); break;
case u16: res = arithOpBroadcast<ushort, op>(lhs, rhs); break;
case f16: res = arithOpBroadcast<half, op>(lhs, rhs); break;
default: TYPE_ERROR(0, otype);
}
}

std::swap(*out, res);
Expand Down
20 changes: 10 additions & 10 deletions test/array.cpp
Show comments View file Edit file Delete file Open in desktop
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -641,23 +641,23 @@ TEST(Array, ReferenceCount2) {
}
}

// This tests situations where the compiler incorrectly assumes the initializer
// list constructor instead of the regular constructor when using the uniform
// initilization syntax
// This tests situations where the compiler incorrectly assumes the
// initializer list constructor instead of the regular constructor when
// using the uniform initilization syntax
TEST(Array, InitializerListFixAFArray) {
array a = randu(1);
array b{a};
af::array a = randu(1);
af::array b{a};

ASSERT_ARRAYS_EQ(a, b);
}

// This tests situations where the compiler incorrectly assumes the initializer
// list constructor instead of the regular constructor when using the uniform
// initilization syntax
// This tests situations where the compiler incorrectly assumes the
// initializer list constructor instead of the regular constructor when
// using the uniform initilization syntax
TEST(Array, InitializerListFixDim4) {
array a = randu(1);
af::array a = randu(1);
vector<float> data = {3.14f, 3.14f, 3.14f, 3.14f, 3.14f,
3.14f, 3.14f, 3.14f, 3.14f};
array b{dim4(3, 3), data.data()};
af::array b{dim4(3, 3), data.data()};
ASSERT_ARRAYS_EQ(constant(3.14, 3, 3), b);
}
Loading
Toggle all file notes Toggle all file annotations

Footer

© 2026 GitHub, Inc.