Files
opencv/hal/riscv-rvv/src/core/qr.cpp
T

181 lines
6.7 KiB
C++

// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include <cfloat>
#include <cmath>
#include <typeinfo>
#include <vector>
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
// the algorithm is copied from core/src/matrix_decomp.cpp,
// in the function template static int cv::QRImpl
template<typename RVV_T, typename T = typename RVV_T::ElemType>
inline int QR(T* src1, size_t src1_step, int m, int n, int k, T* src2, size_t src2_step, T* dst, int* info)
{
T eps;
if (typeid(T) == typeid(float))
eps = FLT_EPSILON*10;
else if (typeid(T) == typeid(double))
eps = DBL_EPSILON*400;
else
return CV_HAL_ERROR_NOT_IMPLEMENTED;
src1_step /= sizeof(T);
src2_step /= sizeof(T);
size_t buf_size = m ? m + n : dst != NULL;
std::vector<T> buffer(buf_size);
T* val = buffer.data();
if (dst == NULL)
dst = val + m;
int vlmax = RVV_T::setvlmax(), vl;
for (int l = 0; l < n; l++)
{
//generate val
int vlSize = m - l;
auto vec_sum = RVV_T::vmv(0, vlmax);
for (int i = 0; i < vlSize; i += vl)
{
vl = RVV_T::setvl(vlSize - i);
auto vec_src = RVV_T::vload_stride(src1 + (l + i) * src1_step + l, sizeof(T) * src1_step, vl);
RVV_T::vstore(val + i, vec_src, vl);
vec_sum = __riscv_vfmacc_tu(vec_sum, vec_src, vec_src, vl);
}
T vlNorm = __riscv_vfmv_f(__riscv_vfredosum(vec_sum, RVV_BaseType<RVV_T>::vmv_s(0, vlmax), vlmax));
T tmpV = val[0];
val[0] = val[0] + (val[0] >= 0 ? 1 : -1) * std::sqrt(vlNorm);
vlNorm = std::sqrt(vlNorm + val[0] * val[0] - tmpV*tmpV);
for (int i = 0; i < vlSize; i += vl)
{
vl = RVV_T::setvl(vlSize - i);
auto vec_src = RVV_T::vload(val + i, vl);
vec_src = __riscv_vfdiv(vec_src, vlNorm, vl);
RVV_T::vstore(val + i, vec_src, vl);
}
//multiply A_l*val
for (int j = l; j < n; j++)
{
vec_sum = RVV_T::vmv(0, vlmax);
for (int i = l; i < m; i += vl)
{
vl = RVV_T::setvl(m - i);
auto vec_src1 = RVV_T::vload(val + i - l, vl);
auto vec_src2 = RVV_T::vload_stride(src1 + i * src1_step + j, sizeof(T) * src1_step, vl);
vec_sum = __riscv_vfmacc_tu(vec_sum, vec_src1, vec_src2, vl);
}
T v_lA = 2 * __riscv_vfmv_f(__riscv_vfredosum(vec_sum, RVV_BaseType<RVV_T>::vmv_s(0, vlmax), vlmax));
for (int i = l; i < m; i += vl)
{
vl = RVV_T::setvl(m - i);
auto vec_src1 = RVV_T::vload(val + i - l, vl);
auto vec_src2 = RVV_T::vload_stride(src1 + i * src1_step + j, sizeof(T) * src1_step, vl);
vec_src2 = __riscv_vfnmsac(vec_src2, v_lA, vec_src1, vl);
RVV_T::vstore_stride(src1 + i * src1_step + j, sizeof(T) * src1_step, vec_src2, vl);
}
}
//save val and factors
dst[l] = val[0] * val[0];
for (int i = 1; i < vlSize; i += vl)
{
vl = RVV_T::setvl(vlSize - i);
auto vec_src = RVV_T::vload(val + i, vl);
vec_src = __riscv_vfdiv(vec_src, val[0], vl);
RVV_T::vstore_stride(src1 + (l + i) * src1_step + l, sizeof(T) * src1_step, vec_src, vl);
}
}
if (src2)
{
//generate new rhs
for (int l = 0; l < n; l++)
{
//unpack val
val[0] = (T)1;
for (int j = 1; j < m - l; j += vl)
{
vl = RVV_T::setvl(m - l - j);
auto vec_src = RVV_T::vload_stride(src1 + (j + l) * src1_step + l, sizeof(T) * src1_step, vl);
RVV_T::vstore(val + j, vec_src, vl);
}
//h_l*x
for (int j = 0; j < k; j++)
{
auto vec_sum = RVV_T::vmv(0, vlmax);
for (int i = l; i < m; i += vl)
{
vl = RVV_T::setvl(m - i);
auto vec_src1 = RVV_T::vload(val + i - l, vl);
auto vec_src2 = RVV_T::vload_stride(src2 + i * src2_step + j, sizeof(T) * src2_step, vl);
vec_sum = __riscv_vfmacc_tu(vec_sum, vec_src1, vec_src2, vl);
}
T v_lB = 2 * dst[l] * __riscv_vfmv_f(__riscv_vfredosum(vec_sum, RVV_BaseType<RVV_T>::vmv_s(0, vlmax), vlmax));
for (int i = l; i < m; i += vl)
{
vl = RVV_T::setvl(m - i);
auto vec_src1 = RVV_T::vload(val + i - l, vl);
auto vec_src2 = RVV_T::vload_stride(src2 + i * src2_step + j, sizeof(T) * src2_step, vl);
vec_src2 = __riscv_vfnmsac(vec_src2, v_lB, vec_src1, vl);
RVV_T::vstore_stride(src2 + i * src2_step + j, sizeof(T) * src2_step, vec_src2, vl);
}
}
}
//do back substitution
for (int i = n - 1; i >= 0; i--)
{
for (int j = n - 1; j > i; j--)
{
for (int p = 0; p < k; p += vl)
{
vl = RVV_T::setvl(k - p);
auto vec_src1 = RVV_T::vload(src2 + i * src2_step + p, vl);
auto vec_src2 = RVV_T::vload(src2 + j * src2_step + p, vl);
vec_src1 = __riscv_vfnmsac(vec_src1, src1[i*src1_step + j], vec_src2, vl);
RVV_T::vstore(src2 + i * src2_step + p, vec_src1, vl);
}
}
if (std::abs(src1[i*src1_step + i]) < eps)
{
*info = 0;
return CV_HAL_ERROR_OK;
}
for (int p = 0; p < k; p += vl)
{
vl = RVV_T::setvl(k - p);
auto vec_src = RVV_T::vload(src2 + i * src2_step + p, vl);
vec_src = __riscv_vfdiv(vec_src, src1[i*src1_step + i], vl);
RVV_T::vstore(src2 + i * src2_step + p, vec_src, vl);
}
}
}
*info = 1;
return CV_HAL_ERROR_OK;
}
} // anonymous
int QR32f(float* src1, size_t src1_step, int m, int n, int k, float* src2, size_t src2_step, float* dst, int* info) {
return QR<RVV_F32M4>(src1, src1_step, m, n, k, src2, src2_step, dst, info);
}
int QR64f(double* src1, size_t src1_step, int m, int n, int k, double* src2, size_t src2_step, double* dst, int* info) {
return QR<RVV_F64M4>(src1, src1_step, m, n, k, src2, src2_step, dst, info);
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core