Skip to content

Commit

Permalink
Move things into detail and add exceptions for invalid access
Browse files Browse the repository at this point in the history
  • Loading branch information
tmadlener committed Apr 19, 2024
1 parent 71d4e77 commit 48d3c53
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 55 deletions.
2 changes: 1 addition & 1 deletion test/utils/test_covmatrix_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <stdexcept>

TEST_CASE("CovarianceMatrix indexing", "[cov_matrix_utils]") {
using namespace edm4hep::utils;
using namespace edm4hep::utils::detail;

STATIC_REQUIRE(get_cov_dim(21) == 6);
STATIC_REQUIRE(get_cov_dim(1) == 1);
Expand Down
114 changes: 60 additions & 54 deletions utils/include/edm4hep/utils/cov_matrix_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <array>
#include <stdexcept>
#include <string>
#include <type_traits>

namespace edm4hep {
Expand Down Expand Up @@ -33,87 +34,92 @@ namespace utils {
j = i;
i = tmp;
}
} // namespace detail

/**
* Get the dimension of the covariance matrix from the size of the 1D array in
* which it is stored
*
* **NOTE: to avoid having to do a square root operation and in order to keep
* this constexpr this is currently only implemented for storage sizes up to
* 21 (corresponding to covariance matrix dimensions of 6 x 6)**. This
* function is intended to be called in constexpr or immediate contexts in
* order to fail at compilation already for invalid values of N.
*
* @param N the size of the 1D storage
*
* @returns the dimension of the covariance matrix
*/
/**
* Get the dimension of the covariance matrix from the size of the 1D array in
* which it is stored
*
* **NOTE: to avoid having to do a square root operation and in order to keep
* this constexpr this is currently only implemented for storage sizes up to
* 21 (corresponding to covariance matrix dimensions of 6 x 6)**. This
* function is intended to be called in constexpr or immediate contexts in
* order to fail at compilation already for invalid values of N.
*
* @param N the size of the 1D storage
*
* @returns the dimension of the covariance matrix
*/
#if cpp_consteval
consteval std::size_t get_cov_dim(std::size_t N) {
consteval std::size_t get_cov_dim(std::size_t N) {
#else
constexpr std::size_t get_cov_dim(std::size_t N) {
constexpr std::size_t get_cov_dim(std::size_t N) {
#endif
switch (N) {
case 21:
return 6;
case 15:
return 5;
case 10:
return 4;
case 6:
return 3;
case 3:
return 2;
case 1:
return 1;
switch (N) {
case 21:
return 6;
case 15:
return 5;
case 10:
return 4;
case 6:
return 3;
case 3:
return 2;
case 1:
return 1;
}

// We simply use throwing an exception to make compilation fail in constexpr
// cases.
throw std::invalid_argument(
"Not a valid size for a covariance matrix stored in lower triangular form (N = " + std::to_string(N) + ")");
}

// We simply use throwing an exception to make compilation fail in constexpr
// cases.
throw std::invalid_argument("Not a valid size for a covariance matrix stored in lower triangular form");
}

/**
* Transform a 2D index to a 1D index in lower triangular storage.
*
* @param i row index
* @param j column index
*
* @returns the index into the 1D storage
*/
constexpr int to_lower_tri(int i, int j) {
if (i < j) {
detail::swap(i, j);
/**
* Transform a 2D index to a 1D index in lower triangular storage.
*
* @param i row index
* @param j column index
*
* @returns the index into the 1D storage
*/
constexpr int to_lower_tri(int i, int j) {
if (i < j) {
detail::swap(i, j);
}
return i * (i + 1) / 2 + j;
}
return i * (i + 1) / 2 + j;
}
} // namespace detail

template <typename DimEnum, typename Scalar, std::size_t N>
constexpr Scalar get_cov_value(const std::array<Scalar, N>& cov, DimEnum dimI, DimEnum dimJ) {
const auto i = detail::to_index(dimI);
const auto j = detail::to_index(dimJ);

constexpr auto dim = get_cov_dim(N);
constexpr auto dim = detail::get_cov_dim(N);
if (i < 0 || j < 0 || i >= dim || j >= dim) {
// TODO: error handling
throw std::invalid_argument("The covariance matrix dimensions (" + std::to_string(dim) +
") and the passed dimensions are not compatible (dimI = " + std::to_string(i) +
", dimJ = " + std::to_string(j) + ")");
}

return cov[to_lower_tri(i, j)];
return cov[detail::to_lower_tri(i, j)];
}

template <typename DimEnum, typename Scalar, std::size_t N>
constexpr void set_cov_value(Scalar value, std::array<Scalar, N>& cov, DimEnum dimI, DimEnum dimJ) {
auto i = detail::to_index(dimI);
auto j = detail::to_index(dimJ);

constexpr auto dim = get_cov_dim(N);
constexpr auto dim = detail::get_cov_dim(N);
if (i < 0 || j < 0 || i >= dim || j >= dim) {
// TODO: error handling
throw std::invalid_argument("The covariance matrix dimensions (" + std::to_string(dim) +
") and the passed dimensions are not compatible (dimI = " + std::to_string(i) +
", dimJ = " + std::to_string(j) + ")");
}

// Covariance is in lower triangle this brings us from 2D indices to 1D
cov[to_lower_tri(i, j)] = value;
cov[detail::to_lower_tri(i, j)] = value;
}
} // namespace utils

Expand Down

0 comments on commit 48d3c53

Please sign in to comment.