Program Listing for File inspect.hpp

Return to documentation for file (src/navtk/inspect.hpp)

#pragma once

#include <initializer_list>
#include <navtk/tensors.hpp>
#include <type_traits>
#include <xtensor/utils/xutils.hpp>

namespace navtk {

template <typename T>
bool has_zero_size(const T& expression) {
    return expression.begin() == expression.end();
}

bool is_symmetric(const Matrix& mat, double rtol = 1e-5, double atol = 1e-8);

bool is_diagonal(const Matrix& mat);

bool is_identity(const Matrix& mat);

std::vector<std::pair<Size, Size>> non_symmetric_elements(const Matrix& mat,
                                                          double rtol = 1e-5,
                                                          double atol = 1e-8);

template <typename T>
struct InitializerListDepth {
    using type = T;

    static constexpr size_t value = 0;
};

template <typename T>
struct InitializerListDepth<std::initializer_list<T>> {
    using type = typename InitializerListDepth<T>::type;

    static constexpr size_t value = 1 + InitializerListDepth<T>::value;
};

// don't document initializer helper stuff, but only the final result.
#ifndef NEED_DOXYGEN_EXHALE_WORKAROUND
template <size_t D, typename C>
struct InitializerListNested {
    using type =
        std::initializer_list<typename InitializerListNested<(D > 1) ? D - 1 : 1, C>::type>;
};
// Base case of 1 dimesional
template <typename C>
struct InitializerListNested<1, C> {
    using type = std::initializer_list<C>;
};
// Handle 0 dimensional case so tha compiler doesn't explode, but not intended for use.
template <typename C>
struct InitializerListNested<0, C> {
    using type = C;
};
#endif

template <size_t D, typename C>
using Initializer = typename InitializerListNested<D, C>::type;



template <typename T, class = void>
struct TensorMeta {
    static constexpr bool FIXED_DIMS = false;
};

template <typename T>
struct TensorMeta<T, std::enable_if_t<xt::is_xexpression<T>::value>> {
    static constexpr bool FIXED_DIMS = true;

    static constexpr auto DIM_COUNT =
        std::tuple_size<typename std::remove_reference<T>::type::shape_type>::value;
};


template <typename T>
struct TensorMeta<T, std::enable_if_t<std::is_arithmetic<std::remove_reference_t<T>>::value>> {
    static constexpr bool FIXED_DIMS = true;

    static constexpr size_t DIM_COUNT = 0;
};


template <typename T>
struct TensorMeta<
    T,
    std::enable_if_t<InitializerListDepth<T>::value != 0 &&
                     std::is_arithmetic<typename InitializerListDepth<T>::type>::value>> {
    static constexpr bool FIXED_DIMS = true;

    static constexpr size_t DIM_COUNT = InitializerListDepth<T>::value;
};

template <typename T>
inline constexpr bool IS_VALID = (TensorMeta<T>::FIXED_DIMS);

template <size_t Dim, typename... T>
inline constexpr bool TENSORS_ARE_DIM =
    ((IS_VALID<T> && requires { typename std::enable_if_t<TensorMeta<T>::DIM_COUNT == Dim>; }) &&
     ...);

template <size_t Dim, typename... T>
inline constexpr bool TENSORS_ARE_LESS_THAN_DIM =
    ((IS_VALID<T> && requires { typename std::enable_if_t<(TensorMeta<T>::DIM_COUNT < Dim)>; }) &&
     ...);

template <size_t Dim, typename... T>
inline constexpr bool TENSORS_HAVE_MAX_DIM =
    TENSORS_ARE_LESS_THAN_DIM<Dim + 1, T...> && !TENSORS_ARE_LESS_THAN_DIM<Dim, T...>;

template <bool Condition>
using IfCondition = std::enable_if_t<Condition>;

template <bool... Condition>
using IfAllConditions = IfCondition<(Condition && ...)>;

template <bool... Condition>
using IfAnyConditions = IfCondition<(Condition || ...)>;

template <typename T, std::size_t Dim>
using IfTensorOfDim = IfCondition<TENSORS_ARE_DIM<Dim, T>>;

template <typename A, typename B, std::size_t Dim>
using IfBothTensorsOfDim = IfCondition<TENSORS_ARE_DIM<Dim, A, B>>;

template <typename A, typename B, std::size_t Dim>
using IfFirstTensorOfDim = IfAllConditions<TENSORS_ARE_DIM<Dim, A>, !TENSORS_ARE_DIM<Dim, B>>;

template <typename A, typename B, std::size_t Dim>
using IfSecondTensorOfDim = IfAllConditions<TENSORS_ARE_DIM<Dim, B>, !TENSORS_ARE_DIM<Dim, A>>;

template <std::size_t Dim, typename... T>
using IfAnyTensorOfDim = IfAnyConditions<TENSORS_ARE_DIM<Dim, T>...>;

template <std::size_t Dim, typename... T>
using IfAllTensorsOfDim = IfCondition<TENSORS_ARE_DIM<Dim, T...>>;

template <std::size_t Dim, typename... T>
using IfNoTensorsOfDim = IfAllConditions<!TENSORS_ARE_DIM<Dim, T>...>;

template <std::size_t Dim, typename... T>
using IfTensorsMaxDim = IfAllConditions<TENSORS_ARE_LESS_THAN_DIM<Dim + 1, T...>,
                                        !TENSORS_ARE_LESS_THAN_DIM<Dim, T...>>;

template <typename T>
using IfEigenInterface =
    IfAllConditions<std::is_member_function_pointer<decltype(&T::rows)>::value,
                    std::is_member_function_pointer<decltype(&T::cols)>::value>;

Size num_rows(const Matrix& m);

Size num_rows(const Vector& c);

Size num_cols(const Matrix& m);

Size num_cols(const Vector& r);

}  // namespace navtk