181 lines
6.7 KiB
C++
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
|