Skip to content
Prev Previous commit
Next Next commit
Added tests for norm and modulus. Made consistent modulus for ints in…
… cpu backend according to other backends
  • Loading branch information
edwinsolisf committed Feb 4, 2025
commit 821df19889a20eede17586d0bf067b76a0ff2122
6 changes: 3 additions & 3 deletions src/api/c/norm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include <af/traits.hpp>

using af::dim4;
using common::cast;
using arrayfire::common::cast;
using detail::arithOp;
using detail::Array;
using detail::cdouble;
Expand All @@ -39,7 +39,7 @@ using detail::scalar;

template<typename T>
using normReductionResult =
typename std::conditional<std::is_same<T, common::half>::value, float,
typename std::conditional<std::is_same<T, arrayfire::common::half>::value, float,
T>::type;

template<typename T>
Expand Down Expand Up @@ -141,7 +141,7 @@ af_err af_norm(double *out, const af_array in, const af_norm_type type,
case f64: *out = norm<double>(in, type, p, q); break;
case c32: *out = norm<cfloat>(in, type, p, q); break;
case c64: *out = norm<cdouble>(in, type, p, q); break;
case f16: *out = norm<common::half>(in, type, p, q); break;
case f16: *out = norm<arrayfire::common::half>(in, type, p, q); break;
default: TYPE_ERROR(1, i_type);
}
}
Expand Down
7 changes: 5 additions & 2 deletions src/backend/cpu/binary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,11 @@ LOGIC_CPLX_FN(double, af_or_t, ||)

template<typename T>
static T __mod(T lhs, T rhs) {
T res = lhs % rhs;
Comment thread
christophe-murphy marked this conversation as resolved.
return (res < 0) ? abs(rhs - res) : res;
T res = lhs % rhs; // Same as other backends

// Does this break compatibility?
// return (res < 0) ? abs(rhs - res) : res;
return res;
}

template<typename T>
Expand Down
6 changes: 6 additions & 0 deletions test/math.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,14 @@ TEST(Math, Modulus) {
auto rem = a % b;
auto diff = rem - a;

auto neg_rem = -a % b;
auto neg_diff = neg_rem + a;

ASSERT_ARRAYS_EQ(af::constant(1, shape, s64), rem);
ASSERT_ARRAYS_EQ(af::constant(0, shape, s64), diff);

ASSERT_ARRAYS_EQ(af::constant(-1, shape, s64), neg_rem);
ASSERT_ARRAYS_EQ(af::constant(0, shape, s64), neg_diff);
}

Comment thread
christophe-murphy marked this conversation as resolved.
TEST(Math, ModulusHalf) {
Expand Down
104 changes: 103 additions & 1 deletion test/norm.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************
* Copyright (c) 2014, ArrayFire
* Copyright (c) 2025, ArrayFire
* All rights reserved.
*
* This file is distributed under 3-clause BSD license.
Expand Down Expand Up @@ -48,6 +48,25 @@ double cpu_norm1_impl(af::dim4 &dims, std::vector<T> &value) {
return norm1;
}

template<typename T>
double cpu_norm_pq_impl(af::dim4 &dims, std::vector<T> &value, double p, double q) {
int N = dims[0];
int M = dims[1];

double norm = 0;
for (int n = 0; n < N; n++) {
T *columnN = value.data() + n * M;
double sum = 0;

for (int m = 0; m < M; m++) { sum += std::pow(std::abs(columnN[m]), p); }

norm += std::pow(sum, q / p);
}
norm = std::pow(norm, 1.0 / q);

return norm;
}

double cpu_norm1(af::array &value) {
double norm1;
af::dim4 dims = value.dims();
Expand All @@ -67,6 +86,25 @@ double cpu_norm1(af::array &value) {
return norm1;
}

double cpu_norm_pq(af::array &value, double p, double q) {
double norm2;
af::dim4 dims = value.dims();
if (value.type() == f16) {
vector<half_float::half> values(value.elements());
value.host(values.data());
norm2 = cpu_norm_pq_impl<half_float::half>(dims, values, p, q);
} else if (value.type() == c32 || value.type() == c64) {
vector<complex<double> > values(value.elements());
value.as(c64).host(values.data());
norm2 = cpu_norm_pq_impl<complex<double> >(dims, values, p, q);
} else {
vector<double> values(value.elements());
value.as(f64).host(values.data());
norm2 = cpu_norm_pq_impl<double>(dims, values, p, q);
}
return norm2;
}

template<typename T>
double cpu_norm_inf_impl(af::dim4 &dims, std::vector<T> &value) {
int M = dims[0];
Expand Down Expand Up @@ -142,6 +180,70 @@ TEST_P(Norm, Random_AF_NORM_MATRIX_1) {
ASSERT_NEAR(norm1, result, 2e-4);
}

TEST_P(Norm, Random_AF_NORM_VECTOR_1) {
using std::get;
norm_params param = GetParam();
if (get<1>(param) == f16) SUPPORTED_TYPE_CHECK(half_float::half);
if (get<1>(param) == f64) SUPPORTED_TYPE_CHECK(double);

af::dim4 dims = get<0>(param);
dims[1] = 1; // Test a vector

array in = af::randu(dims, get<1>(param)) - 0.5f;
double result = norm(in, AF_NORM_VECTOR_1);
double norm1 = cpu_norm_pq(in, 1, 1);

ASSERT_NEAR(norm1, result, 2e-4);
}

TEST_P(Norm, Random_AF_NORM_VECTOR_INF) {
using std::get;
norm_params param = GetParam();
if (get<1>(param) == f16) SUPPORTED_TYPE_CHECK(half_float::half);
if (get<1>(param) == f64) SUPPORTED_TYPE_CHECK(double);

af::dim4 dims = get<0>(param);
dims[1] = 1; // Test a vector

array in = af::randu(dims, get<1>(param)) - 0.5f;
double result = norm(in, AF_NORM_VECTOR_INF);
double norm_inf = cpu_norm_inf(in);

ASSERT_NEAR(norm_inf, result, 2e-4);
}

TEST_P(Norm, Random_AF_NORM_VECTOR_2) {
using std::get;
norm_params param = GetParam();
if (get<1>(param) == f16) SUPPORTED_TYPE_CHECK(half_float::half);
if (get<1>(param) == f64) SUPPORTED_TYPE_CHECK(double);

af::dim4 dims = get<0>(param);
dims[1] = 1; // Test a vector

array in = af::randu(dims, get<1>(param)) - 0.5f;
double result = norm(in, AF_NORM_VECTOR_2);
double norm2 = cpu_norm_pq(in, 1, 2); // vectors lie in first dims so swap p and q

ASSERT_NEAR(norm2, result, 3e-4);
}

TEST_P(Norm, Random_AF_NORM_VECTOR_P_P_EQUAL_3_POINT_5) {
using std::get;
norm_params param = GetParam();
if (get<1>(param) == f16) SUPPORTED_TYPE_CHECK(half_float::half);
if (get<1>(param) == f64) SUPPORTED_TYPE_CHECK(double);

af::dim4 dims = get<0>(param);
dims[1] = 1; // Test a vector

array in = af::randu(dims, get<1>(param)) - 0.5f;
double result = norm(in, AF_NORM_VECTOR_P, 3.5);
double normp = cpu_norm_pq(in, 1, 3.5); // vectors lie in first dims so swap p and q

ASSERT_NEAR(normp, result, 3e-4);
}

TEST_P(Norm, Identity_AF_NORM_MATRIX_2_NOT_SUPPORTED) {
using std::get;
norm_params param = GetParam();
Expand Down