Implement fixed size options for rotgen containers

See merge request oss/rotgen!11
This commit is contained in:
Joel Falcou 2025-07-20 20:23:51 +02:00
parent 8e545dd51a
commit 2084874b1b
39 changed files with 1247 additions and 323 deletions

View file

@ -0,0 +1,18 @@
//==================================================================================================
/*
ROTGEN - Runtime Overlay for Eigen
Copyright : CODE RECKONS
SPDX-License-Identifier: BSL-1.0
*/
//==================================================================================================
#pragma once
namespace rotgen::concepts
{
template<typename T>
concept entity = requires(T const&)
{
typename T::rotgen_tag;
typename T::parent;
};
}

62
include/rotgen/config.hpp Normal file
View file

@ -0,0 +1,62 @@
//==================================================================================================
/*
ROTGEN - Runtime Overlay for Eigen
Copyright : CODE RECKONS
SPDX-License-Identifier: BSL-1.0
*/
//==================================================================================================
#pragma once
#include <cstddef>
#include <iosfwd>
namespace rotgen
{
using Index = std::ptrdiff_t;
}
#if defined(ROTGEN_DISABLE_EXPRESSION_TEMPLATES)
#define ROTGEN_MAX_SIZE 0
#endif
#if !defined(ROTGEN_FORCE_DYNAMIC)
#if !defined(ROTGEN_MAX_SIZE)
#define ROTGEN_FORCE_DYNAMIC
#endif
#endif
#if defined(ROTGEN_FORCE_DYNAMIC)
#define ROTGEN_HAS_STATIC_LIMIT false
#else
#define ROTGEN_HAS_STATIC_LIMIT true
#endif
namespace rotgen
{
inline constexpr bool has_static_limit = ROTGEN_HAS_STATIC_LIMIT;
inline constexpr bool is_forcing_dynamic_status = !has_static_limit;
std::ostream& setup_summary(std::ostream& os);
}
#if defined(ROTGEN_FORCE_DYNAMIC)
namespace rotgen
{
inline constexpr Index max_static_size = -1;
template<int Rows, int Cols>
inline constexpr bool storage_status = false;
}
#else
namespace rotgen
{
inline constexpr Index max_static_size = ROTGEN_MAX_SIZE;
template<int Rows, int Cols>
inline constexpr bool storage_status = (Rows > 0 && Cols > 0) && ((Rows*Cols) <= max_static_size);
}
#endif
namespace rotgen
{
inline constexpr bool use_expression_templates = max_static_size > 0;
}

View file

@ -23,5 +23,5 @@ namespace rotgen
inline constexpr int AutoAlign = 0;
inline constexpr int ColMajor = 0;
inline constexpr int RowMajor = 1;
inline constexpr int DotnAlgin = 2;
inline constexpr int DontAlign = 2;
}

View file

@ -7,8 +7,9 @@
//==================================================================================================
#pragma once
#include <rotgen/concepts.hpp>
#include <rotgen/impl/block.hpp>
#include <rotgen/matrix.hpp>
#include <rotgen/dynamic/matrix.hpp>
#include <initializer_list>
#include <cassert>
@ -17,8 +18,13 @@ namespace rotgen
template<typename Ref, int Rows = Dynamic, int Cols = Dynamic, bool Inner = false, int ForceStorageOrder = -1>
class block : public find_block<Ref>
{
using parent = find_block<Ref>;
public:
static_assert ( concepts::entity<Ref>
, "[ROTGEN][CRITICAL] - Block of non-rotgen type instanciated"
);
using parent = find_block<Ref>;
using rotgen_tag = void;
using scalar_type = typename Ref::scalar_type;
static constexpr int storage_order = (ForceStorageOrder == -1) ? Ref::storage_order : ForceStorageOrder;
using concrete_type = matrix<scalar_type,Rows,Cols,storage_order>;

View file

@ -20,12 +20,16 @@ namespace rotgen
>
class matrix : public find_matrix<Scalar,Options>
{
using parent = find_matrix<Scalar,Options>;
public:
using scalar_type = Scalar;
using parent = find_matrix<Scalar,Options>;
using rotgen_tag = void;
using concrete_type = matrix;
using scalar_type = Scalar;
static constexpr auto storage_order = Options & 1;
static constexpr int RowsAtCompileTime = Rows;
static constexpr int ColsAtCompileTime = Cols;
matrix() : parent(Rows==-1?0:Rows,Cols==-1?0:Cols) {}
matrix(int r, int c) : parent(r, c)
@ -36,7 +40,7 @@ namespace rotgen
matrix(parent const& base) : parent(base) {}
matrix(std::initializer_list<std::initializer_list<Scalar>> init) : parent(init)
explicit matrix(std::initializer_list<std::initializer_list<Scalar>> init) : parent(init)
{
if constexpr(Rows != -1) assert(init.size() == Rows && "Mismatched between dynamic and static row size");
if constexpr(Cols != -1)
@ -48,7 +52,7 @@ namespace rotgen
}
template<std::convertible_to<Scalar>... S>
matrix(Scalar s0,S... init)
explicit matrix(Scalar s0,S... init)
requires((Rows == 1 && Cols == (1+sizeof...(S))) || (Cols == 1 && Rows == (1+sizeof...(S))))
: parent(Rows, Cols, {s0,static_cast<Scalar>(init)...})
{}
@ -170,7 +174,7 @@ namespace rotgen
}
template<int P>
Scalar lp_norm() const
Scalar lpNorm() const
{
static_assert(P == 1 || P == 2 || P == Infinity);
return parent::lp_norm(P);

View file

@ -7,9 +7,6 @@
//==================================================================================================
#pragma once
#include <rotgen/matrix.hpp>
#include <rotgen/block.hpp>
namespace rotgen
{
template< typename S, int R , int C

View file

@ -0,0 +1,224 @@
//==================================================================================================
/*
ROTGEN - Runtime Overlay for Eigen
Copyright : CODE RECKONS
SPDX-License-Identifier: BSL-1.0
*/
//==================================================================================================
#pragma once
#include <rotgen/detail/static_info.hpp>
#include <rotgen/fixed/common.hpp>
#include <Eigen/Dense>
#include <iostream>
namespace rotgen
{
namespace detail
{
template<typename Ref, int Rows, int Cols, bool Inner>
using block_type = std::conditional_t < storage_status<Rows,Cols>
, Eigen::Block<typename Ref::parent, Rows, Cols, Inner>
, Eigen::Block<typename Ref::parent, Eigen::Dynamic, Eigen::Dynamic, Inner>
>;
}
template< typename Ref
, int Rows = Dynamic, int Cols = Dynamic
, bool Inner = false, int ForceStorageOrder = -1
>
class block : private detail::block_type<Ref, Rows, Cols, Inner>
{
static_assert ( concepts::entity<Ref>
, "[ROTGEN][CRITICAL] - Block of non-rotgen type instanciated"
);
public:
using rotgen_tag = void;
using parent = detail::block_type<Ref, Rows, Cols, Inner>;
using value_type = typename parent::value_type;
using scalar_type = typename parent::value_type;
using Index = typename parent::Index;
static constexpr int storage_order = (ForceStorageOrder == -1) ? Ref::storage_order : ForceStorageOrder;
using concrete_type = matrix<scalar_type,Rows,Cols,storage_order>;
using concrete_dynamic_type = matrix<scalar_type>;
template<typename ET>
using as_concrete_type = as_concrete_t<ET, matrix>;
static constexpr int RowsAtCompileTime = Rows;
static constexpr int ColsAtCompileTime = Cols;
private:
static constexpr bool has_static_storage = storage_status<Rows,Cols>;
public:
block(const block& other) = default;
block(block&& other) = default;
block& operator=(const block&) = default;
block& operator=(block&&) = default;
block(Ref& r, std::size_t i0, std::size_t j0, std::size_t ni, std::size_t nj) : parent(r.base(),i0,j0,ni,nj)
{}
block(Ref& r, std::size_t i0, std::size_t j0) requires(Rows != -1 && Cols != -1)
: parent(r.base(),i0,j0,Rows,Cols)
{}
template<typename OtherDerived>
block(const Eigen::MatrixBase<OtherDerived>& other) : parent(other) {}
template<typename OtherDerived>
block(const Eigen::EigenBase<OtherDerived>& other) : parent(other) {}
template<typename OtherDerived>
block& operator=(const Eigen::MatrixBase<OtherDerived>& other)
{
parent::operator=(other);
return *this;
}
template<typename OtherDerived>
block& operator=(const Eigen::EigenBase<OtherDerived>& other)
{
parent::operator=(other);
return *this;
}
parent& base() { return static_cast<parent&>(*this); }
parent const& base() const { return static_cast<const parent&>(*this); }
concrete_type transpose() const
{
return concrete_type(static_cast<parent const &>(*this).transpose());
}
concrete_type conjugate() const
{
return concrete_type(static_cast<parent const &>(*this).conjugate());
}
concrete_type adjoint() const
{
return concrete_type(static_cast<parent const &>(*this).adjoint());
}
void transposeInPlace() { parent::transposeInPlace(); }
void adjointInPlace() { parent::adjointInPlace(); }
static concrete_type Constant(scalar_type value) requires (Rows != -1 && Cols != -1)
{
return parent::Constant(Rows, Cols, static_cast<scalar_type>(value));
}
static concrete_type Constant(int rows, int cols, scalar_type value)
{
if constexpr(Rows != -1) assert(rows == Rows && "Mismatched between dynamic and static row size");
if constexpr(Cols != -1) assert(cols == Cols && "Mismatched between dynamic and static column size");
return parent::Constant(rows, cols, static_cast<scalar_type>(value));
}
static concrete_type Identity() requires (Rows != -1 && Cols != -1)
{
return parent::Identity(Rows, Cols);
}
static concrete_type Identity(int rows, int cols)
{
if constexpr(Rows != -1) assert(rows == Rows && "Mismatched between dynamic and static row size");
if constexpr(Cols != -1) assert(cols == Cols && "Mismatched between dynamic and static column size");
return parent::Identity(rows, cols);
}
static concrete_type Zero() requires (Rows != -1 && Cols != -1)
{
return parent::Zero(Rows, Cols);
}
static concrete_type Zero(int rows, int cols)
{
if constexpr(Rows != -1) assert(rows == Rows && "Mismatched between dynamic and static row size");
if constexpr(Cols != -1) assert(cols == Cols && "Mismatched between dynamic and static column size");
return parent::Zero(rows, cols);
}
static concrete_type Random() requires (Rows != -1 && Cols != -1)
{
return parent::Random(Rows, Cols);
}
static concrete_type Random(int rows, int cols)
{
if constexpr(Rows != -1) assert(rows == Rows && "Mismatched between dynamic and static row size");
if constexpr(Cols != -1) assert(cols == Cols && "Mismatched between dynamic and static column size");
return parent::Random(rows, cols);
}
template<int P>
scalar_type lpNorm() const
{
static_assert(P == 1 || P == 2 || P == Infinity);
return parent::template lpNorm<P>();
}
using parent::operator();
using parent::rows;
using parent::cols;
using parent::size;
using parent::prod;
using parent::mean;
using parent::trace;
using parent::maxCoeff;
using parent::minCoeff;
using parent::squaredNorm;
using parent::norm;
using parent::sum;
using parent::data;
block& operator+=(block const& rhs)
{
static_cast<parent&>(*this) += static_cast<parent const&>(rhs);
return *this;
}
block& operator-=(block const& rhs)
{
static_cast<parent&>(*this) -= static_cast<parent const&>(rhs);
return *this;
}
concrete_type operator-() const
{
return concrete_type(static_cast<parent const&>(*this).operator-());
}
block& operator*=(block const& rhs)
{
static_cast<parent&>(*this) *= static_cast<parent const&>(rhs);
return *this;
}
block& operator*=(scalar_type rhs)
{
static_cast<parent&>(*this) *= rhs;
return *this;
}
block& operator/=(scalar_type rhs)
{
static_cast<parent&>(*this) /= rhs;
return *this;
}
static void print_storage_info()
{
std::cout << "Block " << Rows << "x" << Cols
<< " - Storage: " << (has_static_storage ? "Static" : "Dynamic")
<< " (from: ";
Ref::print_storage_info();
std::cout << ")" << std::endl;
}
};
}

View file

@ -0,0 +1,86 @@
//==================================================================================================
/*
ROTGEN - Runtime Overlay for Eigen
Copyright : CODE RECKONS
SPDX-License-Identifier: BSL-1.0
*/
//==================================================================================================
#pragma once
#include <rotgen/concepts.hpp>
#include <concepts>
#include <iosfwd>
namespace rotgen
{
template<typename EigenType
, template<typename,int,int,int,int,int> typename Wrapper
>
struct as_concrete
{
using type = Wrapper< typename EigenType::value_type
, EigenType::RowsAtCompileTime, EigenType::ColsAtCompileTime
, EigenType::Flags
, EigenType::MaxRowsAtCompileTime, EigenType::MaxColsAtCompileTime
>;
};
template<typename EigenType
, template<typename,int,int,int,int,int> typename Wrapper
>
using as_concrete_t = typename as_concrete<EigenType,Wrapper>::type;
template<concepts::entity E1, concepts::entity E2>
bool operator==(E1 const& lhs, E2 const& rhs)
{
return lhs.base() == rhs.base();
}
template<concepts::entity E>
std::ostream& operator<<(std::ostream& os, E const& arg)
{
return os << arg.base();
}
template<concepts::entity E1, concepts::entity E2>
auto operator+(E1 const& lhs, E2 const& rhs)
{
using type = E1::template as_concrete_type<decltype(lhs.base() + rhs.base())>;
return type(lhs.base() + rhs.base());
}
template<concepts::entity E1, concepts::entity E2>
auto operator-(E1 const& lhs, E2 const& rhs)
{
using type = E1::template as_concrete_type<decltype(lhs.base() - rhs.base())>;
return type(lhs.base() - rhs.base());
}
template<concepts::entity E1, concepts::entity E2>
auto operator*(E1 const& lhs, E2 const& rhs)
{
using type = typename E1::concrete_dynamic_type;
return type(lhs.base() * rhs.base());
}
template<concepts::entity E, std::convertible_to<typename E::scalar_type> S>
auto operator*(E const& lhs, S rhs)
{
using type = E::template as_concrete_type<decltype(lhs.base() * rhs)>;
return type(lhs.base() * rhs);
}
template<concepts::entity E, std::convertible_to<typename E::scalar_type> S>
auto operator*(S lhs, E const& rhs )
{
using type = E::template as_concrete_type<decltype(lhs * rhs.base())>;
return type(lhs * rhs.base());
}
template<concepts::entity E, std::convertible_to<typename E::scalar_type> S>
auto operator/(E const& lhs, S rhs)
{
using type = E::template as_concrete_type<decltype(lhs.base() / rhs)>;
return type(lhs.base() / rhs);
}
}

View file

@ -0,0 +1,246 @@
//==================================================================================================
/*
ROTGEN - Runtime Overlay for Eigen
Copyright : CODE RECKONS
SPDX-License-Identifier: BSL-1.0
*/
//==================================================================================================
#pragma once
#include <rotgen/detail/static_info.hpp>
#include <rotgen/fixed/common.hpp>
#include <Eigen/Dense>
#include <iostream>
namespace rotgen
{
namespace detail
{
template<typename Scalar, int Rows, int Cols, int Opts,int MaxRows, int MaxCols>
using storage_type = std::conditional_t < storage_status<Rows,Cols>
, Eigen::Matrix<Scalar, Rows, Cols, Opts, MaxRows, MaxCols>
, Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Opts>
>;
}
template< typename Scalar
, int Rows = Dynamic , int Cols = Dynamic
, int Options = ColMajor
, int MaxRows = Rows , int MaxCols = Cols
>
class matrix : private detail::storage_type<Scalar, Rows, Cols, Options, MaxRows, MaxCols>
{
public:
using rotgen_tag = void;
using parent = detail::storage_type<Scalar, Rows, Cols, Options, MaxRows, MaxCols>;
using value_type = Scalar;
using scalar_type = Scalar;
using Index = typename parent::Index;
static constexpr auto storage_order = Options & 1;
using concrete_type = matrix;
using concrete_dynamic_type = matrix<scalar_type>;
template<typename ET>
using as_concrete_type = as_concrete_t<ET, matrix>;
private:
static constexpr bool has_static_storage = storage_status<Rows,Cols>;
public:
matrix() requires(has_static_storage) {}
matrix() requires(!has_static_storage) : parent(Rows > 0 ? Rows : 0, Cols > 0 ? Cols : 0){}
matrix(Index r, Index c) requires(!has_static_storage) : parent(r, c) {}
matrix(const matrix& other) = default;
matrix(matrix&& other) = default;
matrix& operator=(const matrix&) = default;
matrix& operator=(matrix&&) = default;
matrix(std::initializer_list<std::initializer_list<Scalar>> init) : parent(init)
{}
template<std::convertible_to<Scalar>... S>
requires((Rows == 1 && Cols == (1+sizeof...(S))) || (Cols == 1 && Rows == (1+sizeof...(S))))
matrix(Scalar s0,S... init)
: parent ( [&]()
{
if constexpr(has_static_storage)
return parent{static_cast<Scalar>(s0),static_cast<Scalar>(init)...};
else return parent{Rows,Cols};
}()
)
{
if constexpr(!has_static_storage)
{
auto raw = {static_cast<Scalar>(s0),static_cast<Scalar>(init)...};
auto first = raw.begin();
for(rotgen::Index i=0; i < parent::size(); i++)
(*this)(i) = first[i];
}
}
template<typename OtherDerived>
matrix(const Eigen::MatrixBase<OtherDerived>& other) : parent(other)
{}
template<typename OtherDerived>
matrix& operator=(const Eigen::MatrixBase<OtherDerived>& other)
{
parent::operator=(other);
return *this;
}
template<typename OtherDerived>
matrix& operator=(const Eigen::EigenBase<OtherDerived>& other)
{
parent::operator=(other);
return *this;
}
parent& base() { return static_cast<parent&>(*this); }
parent const& base() const { return static_cast<const parent&>(*this); }
concrete_type transpose() const
{
return concrete_type(static_cast<parent const &>(*this).transpose());
}
concrete_type conjugate() const
{
return concrete_type(static_cast<parent const &>(*this).conjugate());
}
concrete_type adjoint() const
{
return concrete_type(static_cast<parent const &>(*this).adjoint());
}
void transposeInPlace() { parent::transposeInPlace(); }
void adjointInPlace() { parent::adjointInPlace(); }
void resize(int new_rows, int new_cols) requires(Rows == -1 && Cols == -1)
{
parent::resize(new_rows, new_cols);
}
void conservativeResize(int new_rows, int new_cols) requires(Rows == -1 && Cols == -1)
{
parent::conservativeResize(new_rows, new_cols);
}
static matrix Constant(Scalar value) requires (Rows != -1 && Cols != -1)
{
return parent::Constant(Rows, Cols, static_cast<Scalar>(value));
}
static matrix Constant(int rows, int cols, Scalar value)
{
if constexpr(Rows != -1) assert(rows == Rows && "Mismatched between dynamic and static row size");
if constexpr(Cols != -1) assert(cols == Cols && "Mismatched between dynamic and static column size");
return parent::Constant(rows, cols, static_cast<Scalar>(value));
}
static matrix Identity() requires (Rows != -1 && Cols != -1)
{
return parent::Identity(Rows, Cols);
}
static matrix Identity(int rows, int cols)
{
if constexpr(Rows != -1) assert(rows == Rows && "Mismatched between dynamic and static row size");
if constexpr(Cols != -1) assert(cols == Cols && "Mismatched between dynamic and static column size");
return parent::Identity(rows, cols);
}
static matrix Zero() requires (Rows != -1 && Cols != -1)
{
return parent::Zero(Rows, Cols);
}
static matrix Zero(int rows, int cols)
{
if constexpr(Rows != -1) assert(rows == Rows && "Mismatched between dynamic and static row size");
if constexpr(Cols != -1) assert(cols == Cols && "Mismatched between dynamic and static column size");
return parent::Zero(rows, cols);
}
static matrix Random() requires (Rows != -1 && Cols != -1)
{
return parent::Random(Rows, Cols);
}
static matrix Random(int rows, int cols)
{
if constexpr(Rows != -1) assert(rows == Rows && "Mismatched between dynamic and static row size");
if constexpr(Cols != -1) assert(cols == Cols && "Mismatched between dynamic and static column size");
return parent::Random(rows, cols);
}
template<int P>
scalar_type lpNorm() const
{
static_assert(P == 1 || P == 2 || P == Infinity);
return parent::template lpNorm<P>();
}
using parent::operator();
using parent::rows;
using parent::cols;
using parent::size;
using parent::prod;
using parent::mean;
using parent::trace;
using parent::maxCoeff;
using parent::minCoeff;
using parent::squaredNorm;
using parent::norm;
using parent::sum;
using parent::data;
matrix& operator+=(matrix const& rhs)
{
static_cast<parent&>(*this) += static_cast<parent const&>(rhs);
return *this;
}
matrix& operator-=(matrix const& rhs)
{
static_cast<parent&>(*this) -= static_cast<parent const&>(rhs);
return *this;
}
matrix operator-() const
{
return matrix(static_cast<parent const&>(*this).operator-());
}
matrix& operator*=(matrix const& rhs)
{
static_cast<parent&>(*this) *= static_cast<parent const&>(rhs);
return *this;
}
matrix& operator*=(Scalar rhs)
{
static_cast<parent&>(*this) *= rhs;
return *this;
}
matrix& operator/=(Scalar rhs)
{
static_cast<parent&>(*this) /= rhs;
return *this;
}
static void print_storage_info()
{
std::cout << "Matrix " << Rows << "x" << Cols
<< " - Storage: " << (has_static_storage ? "Static" : "Dynamic")
<< " (Max. size=" << max_static_size << ")"
<< std::endl;
}
};
}

View file

@ -6,7 +6,6 @@
*/
//==================================================================================================
#pragma once
#include <rotgen/matrix.hpp>
namespace rotgen
{
@ -88,7 +87,8 @@ namespace rotgen
double lpNorm(const rotgen::matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> &matrix)
{
static_assert(P == 1 || P == 2 || P == Infinity);
return matrix.template lp_norm<P>();
return matrix.template lpNorm<P>();
}
template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols >

View file

@ -24,9 +24,9 @@ class CLASSNAME
~CLASSNAME();
std::size_t rows() const;
std::size_t cols() const;
std::size_t size() const;
Index rows() const;
Index cols() const;
Index size() const;
SOURCENAME transpose() const;
SOURCENAME conjugate() const;

View file

@ -9,6 +9,7 @@
#include <rotgen/detail/generators.hpp>
#include <rotgen/detail/static_info.hpp>
#include <rotgen/config.hpp>
#include <initializer_list>
#include <cstddef>
#include <memory>

View file

@ -27,10 +27,10 @@ class CLASSNAME
~CLASSNAME();
std::size_t rows() const;
std::size_t cols() const;
Index rows() const;
Index cols() const;
Index size() const;
std::size_t size() const;
void resize(std::size_t new_rows, std::size_t new_cols);
void conservativeResize(std::size_t new_rows, std::size_t new_cols);

View file

@ -7,6 +7,16 @@
//==================================================================================================
#pragma once
#include <rotgen/matrix.hpp>
#include <rotgen/block.hpp>
#include <rotgen/config.hpp>
#include <rotgen/concepts.hpp>
#if defined(ROTGEN_FORCE_DYNAMIC)
#include <rotgen/dynamic/matrix.hpp>
#include <rotgen/dynamic/block.hpp>
#else
#include <rotgen/fixed/matrix.hpp>
#include <rotgen/fixed/block.hpp>
#endif
#include <rotgen/extract.hpp>
#include <rotgen/functions.hpp>