diff --git a/.bazelrc b/.bazelrc index 732859d..f93facf 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1 +1 @@ -build --cxxopt=-std=c++14 \ No newline at end of file +build --cxxopt=-std=c++14 diff --git a/.gitignore b/.gitignore index 9d15d5c..e288983 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,17 @@ .DS_Store .vscode -build tmp docs/* !docs/Doxyfile !docs/DoxygenLayout.xml !docs/index.html +build/ +bazel-*/ venv .venv __pycache__ .eggs .pytest_cache lin.cpp -bazel-* \ No newline at end of file +bazel-* +compile_commands.json \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 33e4c9b..94648ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,3 +27,20 @@ matrix: - pip install -vvv . script: - pytest -v test_lin.py + - sudo: false + branches: + only: + - master + addons: + apt: + packages: + - doxygen + script: + - cd docs && doxygen && cd .. + deploy: + provider: pages + skip_cleanup: true + local_dir: docs/html + github_token: $GH_REPO_TOKEN + on: + branch: master diff --git a/LICENSE b/LICENSE index e28bbfe..9abe403 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ MIT License -Copyright (c) 2020 kkrol27 +Copyright (c) 2020 kylekrol +Copyright (c) 2020 Pathfinder for Autonomous Navigation (PAN) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/README.md b/README.md index 82d0a9f..666ba27 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # lin -[![Build Status](https://travis-ci.com/kkrol27/lin.svg?branch=master)](https://travis-ci.com/kkrol27/lin) +[![Build Status](https://travis-ci.com/pathfinder-for-autonomous-navigation/lin.svg?branch=master)](https://travis-ci.com/pathfinder-for-autonomous-navigation/lin) Linear algebra library solely using static memory alocation. It's been developed primarily for the [PAN](https://github.com/pathfinder-for-autonomous-navigation) mission. @@ -32,6 +32,8 @@ Documentation can be built with doxygen by running: and then opening `docs/html/index.html`. Starting at the modules page will be most helpful. +The documentation is also hosted online at https://pathfinder-for-autonomous-navigation.github.io/lin/modules.html + ## Python Bindings There is a small python module wrapping a few basic types from `lin` that have `double` elements. All of the core module is implemented with a handful of helpful additions. The source code for the it is generated at install time by the `setup.py` file. @@ -47,3 +49,4 @@ For running tests locally using a virtual environment may be useful: pip install -r requirements.txt pip install . -vvv pytest -v test_lin.py + diff --git a/WORKSPACE.bazel b/WORKSPACE similarity index 100% rename from WORKSPACE.bazel rename to WORKSPACE diff --git a/docs/Doxyfile b/docs/Doxyfile index fb03e02..33d4285 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -852,6 +852,18 @@ INPUT = \ ../include/lin/views/tensor_view.hpp \ ../include/lin/views/matrix_view.hpp \ ../include/lin/views/vector_view.hpp \ + ../include/lin/views/const_tensor_view.hpp \ + ../include/lin/views/const_matrix_view.hpp \ + ../include/lin/views/const_vector_view.hpp \ + ../include/lin/references.hpp \ + ../include/lin/references/tensor_mapping_reference.hpp \ + ../include/lin/references/matrix_mapping_reference.hpp \ + ../include/lin/references/vector_mapping_reference.hpp \ + ../include/lin/references/diagonal_mapping_reference.hpp \ + ../include/lin/references/tensor_stream_reference.hpp \ + ../include/lin/references/matrix_stream_reference.hpp \ + ../include/lin/references/vector_stream_reference.hpp \ + ../include/lin/references/diagonal_stream_reference.hpp \ ../include # This tag can be used to specify the character encoding of the source files diff --git a/include/lin/core/operations/mapping_transpose.hpp b/include/lin/core/operations/mapping_transpose.hpp new file mode 100644 index 0000000..aede6ee --- /dev/null +++ b/include/lin/core/operations/mapping_transpose.hpp @@ -0,0 +1,107 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +/** @file lin/core/operations/mapping_transpose.hpp + * @author Kyle Krol + */ + +#ifndef LIN_CORE_OPERATIONS_MAPPING_TRANSPOSE_HPP_ +#define LIN_CORE_OPERATIONS_MAPPING_TRANSPOSE_HPP_ + +namespace lin { +namespace internal { + +/** @brief Proxy to a lazily evalutated transpose operation. + * + * @tparam Cs %Tensor type. + * + * Details to come... + * + * @ingroup COREOPERATIONS + */ +template +class MappingTranspose : public Mapping> { + private: + /** @brief Mapping reference. + */ + Mapping &c; + + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits> Traits; + + protected: + using Mapping>::derived; + + public: + using Mapping>::size; + using Mapping>::eval; + using Mapping>::operator(); + using Mapping>::operator=; + + constexpr MappingTranspose() = delete; + constexpr MappingTranspose(MappingTranspose const &) = default; + constexpr MappingTranspose(MappingTranspose &&) = default; + constexpr MappingTranspose &operator=(MappingTranspose const &) = default; + constexpr MappingTranspose &operator=(MappingTranspose &&) = default; + + /** @brief Constructs a proxy to a tensor transpose operation. + * + * @param c %Tensor mapping. + */ + constexpr MappingTranspose(Mapping &c) + : c(c) { } + + /** @return Number of rows in the tensor. + */ + constexpr size_t rows() const { + return c.cols(); + } + + /** @return Number of columns in the tensor. + */ + constexpr size_t cols() const { + return c.rows(); + } + + /** @brief Read write access to the requested tensor element. + * + * @param i Row index. + * @param j Column index. + * + * @return Reference to the tensor element. + */ + constexpr typename Traits::elem_t &operator()(size_t i, size_t j) { + return c(j, i); + } + + /** @brief Read write access to the requested tensor element. + * + * @param i Index. + * + * @return Reference to the tensor element. + * + * Element access proceeds as if all the elements of the tensor stream were + * flattened into an array in row major order. + */ + constexpr typename Traits::elem_t &operator()(size_t i) { + return (*this)(i / cols(), i % cols()); + } +}; + +template +struct _elem> : _elem { }; + +template +struct _dims> { + static constexpr size_t rows = _dims::cols; + static constexpr size_t cols = _dims::rows; + static constexpr size_t max_rows = _dims::max_cols; + static constexpr size_t max_cols = _dims::max_rows; +}; +} // namespace internal +} // namespace lin + +#endif diff --git a/include/lin/core/operations/tensor_operations.hpp b/include/lin/core/operations/tensor_operations.hpp index 4f8a7ad..dc7ecdb 100644 --- a/include/lin/core/operations/tensor_operations.hpp +++ b/include/lin/core/operations/tensor_operations.hpp @@ -11,6 +11,7 @@ #include "../traits.hpp" #include "../types.hpp" #include "functors.hpp" +#include "mapping_transpose.hpp" #include "stream_element_wise_operator.hpp" #include "stream_transpose.hpp" @@ -316,6 +317,12 @@ constexpr auto sum(internal::Stream const &c) { return x; } +template ::value, size_t> = 0> +constexpr auto transpose(internal::Mapping &c) { + return internal::MappingTranspose(c); +} + template ::value, size_t> = 0> constexpr auto transpose(internal::Stream const &c) { diff --git a/include/lin/core/types.hpp b/include/lin/core/types.hpp index fe04135..34932cd 100644 --- a/include/lin/core/types.hpp +++ b/include/lin/core/types.hpp @@ -16,6 +16,7 @@ #define LIN_CORE_TYPES_HPP_ #include "types/base.hpp" +#include "types/const_base.hpp" #include "types/dimensions.hpp" #include "types/mapping.hpp" #include "types/matrix.hpp" diff --git a/include/lin/core/types/base.hpp b/include/lin/core/types/base.hpp index a3c663f..9787ab0 100644 --- a/include/lin/core/types/base.hpp +++ b/include/lin/core/types/base.hpp @@ -15,7 +15,7 @@ namespace lin { namespace internal { -/** @brief %Value backed tensor interface with resizing support. +/** @brief Value backed tensor interface with resizing support. * * @tparam D Derived type. * @@ -26,8 +26,8 @@ namespace internal { * added. A getter to retrive a pointer to the element backing array is also * included. * - * The main purpose is to provide an interface that supports value backed types - - * i.e. those directly storing tensor elements in a member array or and a + * The main purpose is to provide an interface that supports value backed types + * - i.e. those directly storing tensor elements in a member array or and a * pointer. * * @sa internal::Stream @@ -72,7 +72,7 @@ class Base : public Mapping, public Dimensions { * @returns Pointer to the backing array. * * The elements of the tensor are layed out in row major order in the backing - * array. They are stored continguously in memory. + * array. They are stored contiguously in memory. */ inline constexpr typename Traits::elem_t *data() { return derived().data(); @@ -83,7 +83,7 @@ class Base : public Mapping, public Dimensions { * @returns Constant pointer to the backing array. * * The elements of the tensor are layed out in row major order in the backing - * array. They are stored continguously in memory. + * array. They are stored contiguously in memory. */ inline constexpr typename Traits::elem_t const *data() const { return const_cast(derived()).data(); diff --git a/include/lin/core/types/const_base.hpp b/include/lin/core/types/const_base.hpp new file mode 100644 index 0000000..5b16c6d --- /dev/null +++ b/include/lin/core/types/const_base.hpp @@ -0,0 +1,118 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +/** @file lin/core/types/const_base.hpp + * @author Kyle Krol + */ + +#ifndef LIN_CORE_TYPES_CONST_BASE_HPP_ +#define LIN_CORE_TYPES_CONST_BASE_HPP_ + +#include "../config.hpp" +#include "../traits.hpp" +#include "dimensions.hpp" +#include "stream.hpp" + +namespace lin { +namespace internal { + +/** @brief Value backed, read only tensor interface. + * + * @tparam D Derived type. + * + * This is the third of the three main entry points on the lin inheritance tree + * after internal::Mapping. + * + * Here, direct tracking of runtime dimensions and the ability to resize is + * added. A getter to retrive a pointer to the element backing array is also + * included. + * + * The main purpose is to provide an interface that supports value backed types - + * i.e. those directly storing tensor elements in a member array or and a + * pointer. + * + * @sa internal::Stream + * @sa internal::Mapping + * @sa internal::Tensor + * + * @ingroup CORETYPES + */ +template +class ConstBase : public Stream, public Dimensions { + static_assert(has_valid_traits::value, + "Derived types to ConstBase<...> must have valid traits"); + + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits Traits; + + protected: + using Stream::derived; + + public: + using Stream::size; + using Stream::eval; + using Stream::operator(); + + using Dimensions::rows; + using Dimensions::cols; + using Dimensions::resize; + + constexpr ConstBase() = default; + constexpr ConstBase(ConstBase const &) = default; + constexpr ConstBase(ConstBase &&) = default; + constexpr ConstBase &operator=(ConstBase const &) = default; + constexpr ConstBase &operator=(ConstBase &&) = default; + + /** @brief Retrives a constant pointer to the element backing array. + * + * @returns Constant pointer to the backing array. + * + * The elements of the tensor are layed out in row major order in the backing + * array. They are stored contiguously in memory. + */ + inline constexpr typename Traits::elem_t const *data() const { + return derived().data(); + } + + /** @brief Provides read only access to tensor elements. + * + * @param i Row index. + * @param j Column index. + * + * @return Value of the tensor element. + * + * If the indices are out of bounds as defined by the tensor's current + * dimensions, lin assertion errors will be triggered. + */ + constexpr typename Traits::elem_t const &operator()(size_t i, size_t j) const { + LIN_ASSERT(0 <= i && i < rows()); + LIN_ASSERT(0 <= j && j < cols()); + + return data()[i * cols() + j]; + } + + /** @brief Provides read only access to tensor elements. + * + * @param i Index + * + * @return Value of the tensor element. + * + * Element access proceeds as if all the elements of the tensor stream were + * flattened into an array in row major order. + * + * If the index is out of bounds as defined by the tensor's current size, lin + * lin assertion errors will be triggered. + */ + constexpr typename Traits::elem_t const &operator()(size_t i) { + LIN_ASSERT(0 <= i && i < size()); + + return data()[i]; + } +}; +} // namespace internal +} // namespace lin + +#endif diff --git a/include/lin/core/types/mapping.hpp b/include/lin/core/types/mapping.hpp index b2b5f20..4355b99 100644 --- a/include/lin/core/types/mapping.hpp +++ b/include/lin/core/types/mapping.hpp @@ -119,6 +119,32 @@ class Mapping : public Stream { return const_cast(derived())(i); } + /** @brief Provides read and write access to tensor elements. + * + * @param i Index + * + * @return Reference to the tensor element. + * + * Element access proceeds as if all the elements of the tensor stream were + * flattened into an array in row major order. + */ + inline constexpr typename Traits::elem_t &operator[](size_t i) { + return derived()(i); + } + + /** @brief Provides read only access to tensor elements. + * + * @param i Index. + * + * @return Value of the tensor elements. + * + * Element access proceeds as if all the elements of the tensor stream were + * flattened into an array in row major order. + */ + inline constexpr typename Traits::elem_t operator[](size_t i) const { + return const_cast(derived())(i); + } + /** @brief Copy an initializer list's elements into the tensor's elements. * * @param list Initializer list. diff --git a/include/lin/core/types/stream.hpp b/include/lin/core/types/stream.hpp index 286c8df..70d87a9 100644 --- a/include/lin/core/types/stream.hpp +++ b/include/lin/core/types/stream.hpp @@ -125,6 +125,24 @@ class Stream { return derived()(i); } + /** @brief Provides read only access to tensor elements. + * + * @param i Index. + * + * @return Value of the tensor elements. + * + * Element access proceeds as if all the elements of the tensor stream were + * flattened into an array in row major order. + * + * If accessing data from a lazily evaluation tensor operation, you may want to + * consider for the creation of a value backed type to reduce overhead. + * + * @sa internal::Stream::eval + */ + inline constexpr typename Traits::elem_t operator[](size_t i) const { + return derived()(i); + } + /** @brief Forces evaluation of this stream to a value backed type. * * @returns Resulting value. diff --git a/include/lin/factorizations/inl/chol.inl b/include/lin/factorizations/inl/chol.inl index ab26b2f..8d83aba 100644 --- a/include/lin/factorizations/inl/chol.inl +++ b/include/lin/factorizations/inl/chol.inl @@ -14,6 +14,7 @@ constexpr int chol(internal::Mapping &L) { // Useful traits information constexpr size_t C_max_cols = C::Traits::max_cols; + typedef typename C::Traits::elem_t Elem; // Set above the main diagonal to zeros for (size_t i = 0; i < L.rows(); i++) @@ -31,11 +32,11 @@ constexpr int chol(internal::Mapping &L) { for (size_t j = 1; j < i; j++) // L(i, j) L(i, j) = ( L(i, j) - - dot(ref<1, 0, 1, C_max_cols>(L, j, 0, 1, j), ref<1, 0, 1, C_max_cols>(L, i, 0, 1, j)) + dot(ref>(L, j, 0, j), ref>(L, i, 0, j)) ) / L(j, j); // L(i, i) - L(i, i) = std::sqrt(L(i, i) - fro(ref<1, 0, 1, C_max_cols>(L, i, 0, 1, i))); + L(i, i) = std::sqrt(L(i, i) - fro(ref>(L, i, 0, i))); } return 0; diff --git a/include/lin/factorizations/inl/qr.inl b/include/lin/factorizations/inl/qr.inl index 6cc8e92..b166e68 100644 --- a/include/lin/factorizations/inl/qr.inl +++ b/include/lin/factorizations/inl/qr.inl @@ -19,7 +19,7 @@ constexpr int qr(internal::Stream const &M, internal::Mapping &Q, internal Q = M; for (size_t j = 0; j < M.cols(); j++) { - auto qj = ref_col(Q, j); + auto qj = col(Q, j); // Normalize this column R(j, j) = norm(qj); @@ -27,7 +27,7 @@ constexpr int qr(internal::Stream const &M, internal::Mapping &Q, internal // Remove parallel components from subsequent columns for (size_t k = j + 1; k < M.cols(); k++) { - auto qk = ref_col(Q, k); + auto qk = col(Q, k); R(j, k) = dot(qj, qk); qk = qk - qj * R(j, k); } diff --git a/include/lin/generators.hpp b/include/lin/generators.hpp index d86dcf8..c2ca37e 100644 --- a/include/lin/generators.hpp +++ b/include/lin/generators.hpp @@ -16,6 +16,7 @@ #define LIN_GENERATORS_HPP_ #include "generators/constants.hpp" +#include "generators/diagonal.hpp" #include "generators/identity.hpp" #include "generators/randoms.hpp" #include "generators/stream_constants.hpp" diff --git a/include/lin/generators/diagonal.hpp b/include/lin/generators/diagonal.hpp new file mode 100644 index 0000000..c29c298 --- /dev/null +++ b/include/lin/generators/diagonal.hpp @@ -0,0 +1,34 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +/** @file lin/generators/diagonal.hpp + * @author Kyle Krol + */ + +#ifndef LIN_GENERATORS_DIAGONAL_HPP_ +#define LIN_GENERATORS_DIAGONAL_HPP_ + +#include "stream_diagonal.hpp" +#include "../core.hpp" + +#include +#include + +namespace lin { + +/** @brief Creates a diagonal stream from a vector stream. + * + * @tparam D Underlying type. + * + * @param stream Underlying vector stream. + * + * @return Instance of an internal::StreamDiagonal + * + * @sa internal::is_vector + */ +template ::value, size_t> = 0> +constexpr auto diag(internal::Stream const &stream) { + return internal::StreamDiagonal(stream); +} +} // namespace lin + +#endif diff --git a/include/lin/generators/randoms.hpp b/include/lin/generators/randoms.hpp index 9e66f17..732c5cd 100644 --- a/include/lin/generators/randoms.hpp +++ b/include/lin/generators/randoms.hpp @@ -2,6 +2,7 @@ /** @file lin/generators/randoms.hpp * @author Kyle Krol + * @author Shihao Cao */ #ifndef LIN_GENERATORS_RANDOMS_HPP_ @@ -28,6 +29,18 @@ class RandomsGenerator { */ unsigned long long seed; + /** + * @brief Value of a cached standard normal gassauisan random. + * + */ + double cached_rand; + + /** + * @brief has_cached is true if there's a cached standard normal available. + * + */ + bool has_cached; + public: constexpr RandomsGenerator(RandomsGenerator const &) = default; constexpr RandomsGenerator(RandomsGenerator &&) = default; @@ -38,23 +51,46 @@ class RandomsGenerator { * * @param[in] seed */ - constexpr RandomsGenerator(unsigned long long seed = 0) : seed(seed ^ 4101842887655102017LL) { } + constexpr RandomsGenerator(unsigned long long seed = 0) : + seed(seed ^ 4101842887655102017LL), + cached_rand(0.0), + has_cached(false) { } - /** @brief Generates a random number in the range zero to one. + /** @brief Generates a uniform random number in the range zero to one. * * @return Random number between zero and one. */ - constexpr double next() { + constexpr double rand() { seed ^= (seed >> 21); seed ^= (seed << 35); seed ^= (seed >> 4); return 5.42101086242752217E-20 * (seed * 2685821657736338717ULL); } + + /** + * @brief Return a gaussian random number with mean 0 and std 1. + * Uses Box-Mueller transform with caching. + * + * @return constexpr double + */ + constexpr double gaussian() { + if(has_cached) { + has_cached = false; + return cached_rand; + } + else{ + double R = std::sqrt(-2.0*std::log(rand())); + double T = 2.0*M_PI*rand(); + cached_rand = R*std::sin(T); + has_cached = true; + return R*std::cos(T); + } + } }; } // namespace internal -/** @brief Generates a Matrix or Vector populated with random values between +/** @brief Generates a Matrix or Vector populated with uniform random values between 0 and 1 * * @tparam C Tensor type whose traits the returned stream will mimic. * @@ -71,7 +107,29 @@ class RandomsGenerator { template ::value, size_t> = 0> constexpr auto rands(internal::RandomsGenerator &rand, size_t r = C::Traits::max_rows, size_t c = C::Traits::max_cols) { typename C::Traits::eval_t t(r, c); - for (lin::size_t i = 0; i < t.size(); i++) t(i) = typename C::Traits::elem_t(rand.next()); + for (lin::size_t i = 0; i < t.size(); i++) t(i) = typename C::Traits::elem_t(rand.rand()); + return t; +} + +/** @brief Generates a Matrix or Vector populated with independent gaussian random variables + * with a mean of 0 and standard deviation of 1. Uses Box–Muller transform. + * + * @tparam C Tensor type whose traits the returned stream will mimic. + * + * @param[inout] rand Random number generator. + * @param[in] r Row count. + * @param[in] c Column count. + * + * @return Tensor with randomly populated values. + * + * @sa internal::RandomsGenerator + * + * @ingroup GENERATORS + */ +template ::value, size_t> = 0> +constexpr auto gaussians(internal::RandomsGenerator &rand, size_t r = C::Traits::max_rows, size_t c = C::Traits::max_cols) { + typename C::Traits::eval_t t(r, c); + for (lin::size_t i = 0; i < t.size(); i++) t(i) = typename C::Traits::elem_t(rand.gaussian()); return t; } } // namespace lin diff --git a/include/lin/generators/stream_diagonal.hpp b/include/lin/generators/stream_diagonal.hpp new file mode 100644 index 0000000..e91f5b3 --- /dev/null +++ b/include/lin/generators/stream_diagonal.hpp @@ -0,0 +1,149 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +/** @file lin/generators/stream_diagonal.hpp + * @author Kyle Krol + */ + +#ifndef LIN_GENERATORS_STREAM_DIAGONAL_HPP_ +#define LIN_GENERATORS_STREAM_DIAGONAL_HPP_ + +#include "../core.hpp" + +namespace lin { +namespace internal { + +/** @brief Tensor stream where all elements are zeros expects the elements on + * on the diagonal specified by an underlying stream. + * + * @tparam E Underlying vector stream. + * + * This allows a user to sparesly define a square matrix stream where all + * elements evaluate to zero except for the those along the diagonal, which are + * specified by the elements of an underlying vector. + * + * Note the if the underlying vector goes out of scope the diagonal stream is + * invalidated. + * + * @sa internal::is_matrix + * @sa internal::is_square + * + * @ingroup GENERATORS + */ +template +class StreamDiagonal : public Stream> { + static_assert(conjunction>, is_square>>::value, + "StreamDiagonal must have square, matrix traits"); + static_assert(is_vector::value, + "Backing type for a StreamDiagonal must have vector traits"); + + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits> Traits; + + private: + Stream const &_stream; + + protected: + using Stream>::derived; + + public: + using Stream>::size; + using Stream>::eval; + + constexpr StreamDiagonal() = delete; + constexpr StreamDiagonal(StreamDiagonal const &) = default; + constexpr StreamDiagonal(StreamDiagonal &&) = default; + constexpr StreamDiagonal &operator=(StreamDiagonal const &) = default; + constexpr StreamDiagonal &operator=(StreamDiagonal &&) = default; + + /** @brief Constructs a new diagonal stream from the provided vector stream. + * + * @param stream Underlying vector stream + * + * The provided vector streams length will determine the runtime dimensions + * of the diagonal stream. + * + * Changes in element values and dimensions of the underlying vector stream + * will be reflected in the stream itself. The underlying stream must be in + * scope for the stream to be valid. + */ + constexpr StreamDiagonal(Stream const &stream) + : _stream(stream) { } + + /** @return Number of rows. + * + * Equals the size of the underlying vector. + */ + constexpr size_t rows() const { + return _stream.size(); + } + + /** @return Number of rows. + * + * Equals the size of the underlying vector. + */ + constexpr size_t cols() const { + return _stream.size(); + } + + /** @brief Provides read only access to tensor elements. + * + * @param i Row index. + * @param j Column index. + * + * @return Value of the tensor element. + * + * Zero if off the main diagonal and specified by the underlying vector + * stream otherwise. + * + * If the indices are out of bounds as defined by the stream's current + * dimensions, lin assertion errors will be triggered. + */ + constexpr typename Traits::elem_t operator()(size_t i, size_t j) const { + LIN_ASSERT(0 <= i && i <= rows()); + LIN_ASSERT(0 <= j && j <= cols()); + + return i == j ? _stream(i) : typename Traits::elem_t(0); + } + + /** @brief Provides read only access to tensor elements. + * + * @param i Index. + * + * @return Value of the tensor element. + * + * Element access proceeds as if all the elements of the tensor stream were + * flattened into an array in row major order. + * + * Zero if off the main diagonal and specified by the underlying vector + * stream otherwise. + * + * If the index is out of bounds as defined by the stream's current size, lin + * assertion errors will be triggered. + */ + constexpr typename Traits::elem_t operator()(size_t i) const { + LIN_ASSERT(0 <= i && i <= size()); + + return (*this)(i / cols(), i % cols()); + } +}; + +template +struct _elem> { + typedef _elem_t type; +}; + +template +struct _dims> { + static constexpr size_t rows = _vector_dims::length; + static constexpr size_t cols = _vector_dims::length; + static constexpr size_t max_rows = _vector_dims::max_length; + static constexpr size_t max_cols = _vector_dims::max_length; +}; +} // namespace internal +} // namespace lin + +#endif diff --git a/include/lin/references.hpp b/include/lin/references.hpp index 98305cc..a8242bb 100644 --- a/include/lin/references.hpp +++ b/include/lin/references.hpp @@ -1,11 +1,523 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +// +// MIT License +// +// Copyright (c) 2020 kylekrol +// Copyright (c) 2020 Pathfinder for Autonomous Navigation (PAN) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + /** @file lin/references.hpp * @author Kyle Krol - * Collection of header files composing the references module. */ + */ + +/** @defgroup REFERENCES References + * + * @brief Allows interpretting portions of larger tensor as other tensor types. + * + * This can be extremely helpful if, for example, you'd like to normalize all + * the columns of a matrix without copying elements in and out of the matrix + * itself. We'll use this an example demonstrating how to use the refernces + * module. + * + * First, be sure to include the appropriate headers (that being the + * `%lin/core.hpp` and `%lin/references.hpp` headers). From there, we can + * implement the following function which will normalize the columns in a three + * by three matrix: + * + * ~~~{.cpp} + * #include + * #include + * + * template + * void normalize(lin::Matrix &M) { + * for (lin::size_t j = 0; j < M.cols(); j++) { + * auto m = lin::ref>(M, 0, j); + * m = m / lin::norm(m); + * } + * } + * ~~~ + * + * where line of interest here is clearly the call to + * `%lin::ref<%lin::Vector>` which essentially asks for a reference to be + * created that acts like a `%lin::Vector` and whose first element + * matches up with `M(0, j)`. + * + * There are a couple things to note here: + * + * - The reference itself is invalid when the backing object (in this case + * `M`) goes out of scope. + * - This particular reference serves as a read and write interface. However, + * read only references can also be generated in the same fashion if the + * underlying type is `const` or read only. + * + * Lastly, there are also convenience functions `lin::col`, `lin::row`, and + * `lin::diag` to more easily reference the entire column, row, or diagonal of + * a tensor. In fact, if you don't mind using the `lin::internal` namespace a + * little, a simple function normalizing the columns of any matrix can be + * implemented as shown below: + * + * ~~~{.cpp} + * #include + * #include + * + * #include + * + * template , lin::internal::is_col_vector>::value>> + * void normalize(lin::internal::Mapping &M) { + * for (lin::size_t j = 0; j < M.cols(); j++) { + * auto m = lin::col(M, j); + * m = m / lin::norm(m); + * } + * } + * ~~~ + */ #ifndef LIN_REFERENCES_HPP_ #define LIN_REFERENCES_HPP_ -#include "references/mapping_reference.hpp" -#include "references/stream_reference.hpp" +#include "core.hpp" +#include "references/diagonal_mapping_reference.hpp" +#include "references/diagonal_stream_reference.hpp" +#include "references/matrix_mapping_reference.hpp" +#include "references/matrix_stream_reference.hpp" +#include "references/vector_mapping_reference.hpp" +#include "references/vector_stream_reference.hpp" + +#include + +namespace lin { +namespace internal { + +/** @internal + * + * @brief Provides a specific tensor type's corresponding mapping reference + * type. + * + * @tparam C %Tensor type whose traits are replicated. + * @tparam D Underlying referenced type. + * + * @sa internal::stream_reference + * + * @ingroup REFERENCES + */ +template +struct mapping_reference; + +template +using mapping_reference_t = typename mapping_reference::type; + +template +struct mapping_reference, have_same_elements>::value>> { + typedef MatrixMappingReference type; +}; + +template +struct mapping_reference, have_same_elements>::value>> { + typedef VectorMappingReference type; +}; + +template +struct mapping_reference, have_same_elements>::value>> { + typedef RowVectorMappingReference type; +}; + +/** @internal + * + * @brief Provides a specific tensor type's corresponding stream reference + * type. + * + * @tparam C %Tensor type whose traits are replicated. + * @tparam D Underlying referenced type. + * + * @sa internal::mapping_reference + * + * @ingroup REFERENCES + */ +template +struct stream_reference; + +template +using stream_reference_t = typename stream_reference::type; + +template +struct stream_reference, have_same_elements>::value>> { + typedef MatrixStreamReference type; +}; + +template +struct stream_reference, have_same_elements>::value>> { + typedef VectorStreamReference type; +}; + +template +struct stream_reference, have_same_elements>::value>> { + typedef RowVectorStreamReference type; +}; +} // namespace internal + +/** @brief Creates a mapping reference with default dimensions. + * + * @tparam C %Tensor type whose traits are replicated. + * @tparam D Underlying referenced type. + * + * @param mapping Underlying mapping. + * @param i Anchor point row index. + * @param j Anchor point column index. + * + * @return Instace of an internal::MatrixMappingReference, + * internal::RowVectorMappingReference, or + * internal::VectorMappingReference + * + * This serves essentially as a wrapper around the reference constructors + * using default dimensions. + * + * The anchor points specifies where the top left corner of the reference maps + * to in the underlying mapping. + * + * @ingroup REFERENCES + */ +template ::value>> +constexpr auto ref(internal::Mapping &mapping, size_t i, size_t j) { + return internal::mapping_reference_t(mapping, i, j); +} + +/** @brief Creates a vector mapping reference with the provided length. + * + * @tparam C %Vector type whose traits are replicated. + * @tparam D Underlying referenced type. + * + * @param mapping Underlying mapping. + * @param i Anchor point row index. + * @param j Anchor point column index. + * @param n Provided length. + * + * @return Instance of an internal::RowVectorMappingReference or + * internal::VectorMappingReference + * + * This serves essentially as a wrapper around the vector reference + * constructors requesting a length. + * + * The anchor points specifies where the top left corner of the reference maps + * to in the underlying mapping. + * + * Lin assertions errors will be triggered if the requested dimensions aren't + * possible given the reference's traits. + * + * @sa internal::traits + * + * @ingroup REFERENCES + */ +template , internal::is_vector>::value>> +constexpr auto ref(internal::Mapping &mapping, size_t i, size_t j, size_t n) { + return internal::mapping_reference_t(mapping, i, j, n); +} + +/** @brief Creates a mapping reference with the provided dimensions. + * + * @tparam C %Tensor type whose traits are replicated. + * @tparam D Underlying referenced type. + * + * @param mapping Underlying mapping. + * @param i Anchor point row index. + * @param j Anchor point column index. + * @param r Provided row dimension. + * @param c Provided column dimension. + * + * @return Instance of an internal::MatrixMappingReference, + * internal::RowVectorMappingReference, or + * internal::VectorMappingReference + * + * This serves essentially as a wrapper around the reference constructors + * using default dimensions. + * + * The anchor points specifies where the top left corner of the reference maps + * to in the underlying mapping. + * + * Lin assertions errors will be triggered if the requested dimensions aren't + * possible given the reference's traits. + * + * @sa internal::traits + * + * @ingroup REFERENCES + */ +template ::value>> +constexpr auto ref(internal::Mapping &mapping, size_t i, size_t j, size_t r, size_t c) { + return internal::mapping_reference_t(mapping, i, j, r, c); +} + +/** @brief Creates a mapping reference of a particular column of a given tensor. + * + * @tparam D Underlying referened type. + * + * @param mapping Underlying mapping. + * @param j Index of the referenced column. + * + * @return Instance of an internal::VectorMappingReference. + * + * This is a convenience function and the same result can be obtained with a + * call to another reference function. + * + * The dimensions of a variably sized column are set depending on the provided + * mapping's row dimension at run time. + * + * @ingroup REFERENCES + */ +template +constexpr auto col(internal::Mapping &mapping, size_t j) { + typedef typename D::Traits::elem_t Elem; + constexpr size_t Rows = D::Traits::rows; + constexpr size_t MaxRows = D::Traits::max_rows; + + return ref>(mapping, 0, j, mapping.rows()); +} + +/** @brief Creates a mapping reference of a particular row of a given tensor. + * + * @tparam D Underlying referened type. + * + * @param mapping Underlying mapping. + * @param j Index of the referenced row. + * + * @return Instance of an internal::RowVectorMappingReference. + * + * This is a convenience function and the same result can be obtained with a + * call to another reference function. + * + * The dimensions of a variably sized row are set depending on the provided + * mapping's column dimension at run time. + * + * @ingroup REFERENCES + */ +template +constexpr auto row(internal::Mapping &mapping, size_t i) { + typedef typename D::Traits::elem_t Elem; + constexpr size_t Cols = D::Traits::cols; + constexpr size_t MaxCols = D::Traits::max_cols; + + return ref>(mapping, i, 0, mapping.cols()); +} + +/** @brief Creates a diagonal mapping reference from the given mapping. + * + * @tparam D Underlying referenced type. + * + * @param mapping Underlying mapping. + * + * @return Instance of an internal::DiagonalMappingReference. + * + * The underlying mapping must have the traits of a square matrix and lin + * assertion errors will be thrown if the underlying mapping isn't square at + * runtime. + * + * @sa internal::is_matrix + * @sa internal::is_square + * @sa internal::traits + * + * @ingroup REFERENCES + */ +template , internal::is_square>::value>> +constexpr auto diag(internal::Mapping &mapping) { + return internal::DiagonalMappingReference(mapping); +} + +/** @brief Creates a mapping stream with default dimensions. + * + * @tparam C %Tensor type whose traits are replicated. + * @tparam D Underlying referenced type. + * + * @param stream Underlying stream. + * @param i Anchor point row index. + * @param j Anchor point column index. + * + * @return Instace of an internal::MatrixStreamReference, + * internal::RowVectorStreamReference, or + * internal::VectorStreamReference + * + * This serves essentially as a wrapper around the reference constructors + * using default dimensions. + * + * The anchor points specifies where the top left corner of the reference maps + * to in the underlying stream. + * + * @ingroup REFERENCES + */ +template ::value>> +constexpr auto ref(internal::Stream const &stream, size_t i, size_t j) { + return internal::stream_reference_t(stream, i, j); +} + +/** @brief Creates a vector stream reference with the provided length. + * + * @tparam C %Vector type whose traits are replicated. + * @tparam D Underlying referenced type. + * + * @param stream Underlying stream. + * @param i Anchor point row index. + * @param j Anchor point column index. + * @param n Provided length. + * + * @return Instance of an internal::RowVectorStreamReference or + * internal::VectorStreamReference + * + * This serves essentially as a wrapper around the vector reference + * constructors requesting a length. + * + * The anchor points specifies where the top left corner of the reference maps + * to in the underlying stream. + * + * Lin assertions errors will be triggered if the requested dimensions aren't + * possible given the reference's traits. + * + * @sa internal::traits + * + * @ingroup REFERENCES + */ +template , internal::is_vector>::value>> +constexpr auto ref(internal::Stream const &stream, size_t i, size_t j, size_t n) { + return internal::stream_reference_t(stream, i, j, n); +} + +/** @brief Creates a stream reference with the provided dimensions. + * + * @tparam C %Tensor type whose traits are replicated. + * @tparam D Underlying referenced type. + * + * @param stream Underlying stream. + * @param i Anchor point row index. + * @param j Anchor point column index. + * @param r Provided row dimension. + * @param c Provided column dimension. + * + * @return Instance of an internal::MatrixStreamReference, + * internal::RowVectorStreamReference, or + * internal::VectorStreamReference + * + * This serves essentially as a wrapper around the reference constructors + * using default dimensions. + * + * The anchor points specifies where the top left corner of the reference maps + * to in the underlying mapping. + * + * Lin assertions errors will be triggered if the requested dimensions aren't + * possible given the reference's traits. + * + * @sa internal::traits + * + * @ingroup REFERENCES + */ +template ::value>> +constexpr auto ref(internal::Stream const &stream, size_t i, size_t j, size_t r, size_t c) { + return internal::stream_reference_t(stream, i, j, r, c); +} + +/** @brief Creates a stream reference of a particular column of a given tensor. + * + * @tparam D Underlying referened type. + * + * @param stream Underlying stream. + * @param j Index of the referenced column. + * + * @return Instance of an internal::VectorStreamReference. + * + * This is a convenience function and the same result can be obtained with a + * call to another reference function. + * + * The dimensions of a variably sized column are set depending on the provided + * mapping's row dimension at run time. + * + * @ingroup REFERENCES + */ +template +constexpr auto col(internal::Stream const &stream, size_t j) { + typedef typename D::Traits::elem_t Elem; + constexpr size_t Rows = D::Traits::rows; + constexpr size_t MaxRows = D::Traits::max_rows; + + return ref>(stream, 0, j, stream.rows()); +} + +/** @brief Creates a stream reference of a particular row of a given tensor. + * + * @tparam D Underlying referened type. + * + * @param stream Underlying stream. + * @param j Index of the referenced row. + * + * @return Instance of an internal::RowVectorStreamReference. + * + * This is a convenience function and the same result can be obtained with a + * call to another reference function. + * + * The dimensions of a variably sized row are set depending on the provided + * mapping's column dimension at run time. + * + * @ingroup REFERENCES + */ +template +constexpr auto row(internal::Stream const &stream, size_t i) { + typedef typename D::Traits::elem_t Elem; + constexpr size_t Cols = D::Traits::cols; + constexpr size_t MaxCols = D::Traits::max_cols; + + return ref>(stream, i, 0, stream.cols()); +} + +/** @brief Creates a diagonal stream reference from the given stream. + * + * @tparam D Underlying referenced type. + * + * @param stream Underlying stream. + * + * @return Instance of an internal::DiagonalMappingReference. + * + * The underlying mapping must have the traits of a square matrix and lin + * assertion errors will be thrown if the underlying mapping isn't square at + * runtime. + * + * @sa internal::is_matrix + * @sa internal::is_square + * @sa internal::traits + * + * @ingroup REFERENCES + */ +template , internal::is_square>::value>> +constexpr auto diag(internal::Stream const &stream) { + return internal::DiagonalStreamReference(stream); +} +} // namespace lin #endif diff --git a/include/lin/references/diagonal_mapping_reference.hpp b/include/lin/references/diagonal_mapping_reference.hpp new file mode 100644 index 0000000..67476da --- /dev/null +++ b/include/lin/references/diagonal_mapping_reference.hpp @@ -0,0 +1,153 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +/** @file lin/references/diagonal_mapping_reference.hpp + * @author Kyle Krol + */ + +#ifndef LIN_REFERENCES_DIAGONAL_MAPPING_REFERENCE_HPP_ +#define LIN_REFERENCES_DIAGONAL_MAPPING_REFERENCE_HPP_ + +#include "../core.hpp" + +namespace lin { +namespace internal { + +/** @brief Generic diagonal reference with read and write access. + * + * @tparam E Underlying referenced type. + * + * This allows users to treat the diagonal elements of a mapping as a column + * vector. The underlying mapping must have traits making is a square matrix. + * + * It's important to note, if the underlying mapping goes out of scope the + * reference is invalidated. + * + * @sa internal::DiagonalMappingReference + * @sa internal::is_matrix + * @sa internal::is_square + */ +template +class DiagonalMappingReference : public Mapping> { + static_assert(is_vector>::value, + "DiagonalMappingReference<...> types must have vector traits."); + static_assert(conjunction, is_square>::value, + "Underlying mapping for a diagonal reference must be a square matrix."); + + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits> Traits; + + /** @brief %Vector traits information for this type. + * + * @sa internal::vector_traits + */ + typedef vector_traits> VectorTraits; + + private: + Mapping &_mapping; + + protected: + using Mapping>::derived; + + public: + using Mapping>::size; + using Mapping>::eval; + using Mapping>::operator(); + using Mapping>::operator=; + + constexpr DiagonalMappingReference() = delete; + constexpr DiagonalMappingReference(DiagonalMappingReference const &) = default; + constexpr DiagonalMappingReference(DiagonalMappingReference &&) = default; + constexpr DiagonalMappingReference &operator=(DiagonalMappingReference const &) = default; + constexpr DiagonalMappingReference &operator=(DiagonalMappingReference &&) = default; + + /** @brief Constructs a new diagonal reference with the provided mapping. + * + * @param mapping Underlying mapping. + * + * The provided mapping must be square at runtime or lin assertion errors + * will be triggered. + * + * Resizing the mapping to be something other than square after construction + * invalidates the reference. + */ + constexpr DiagonalMappingReference(Mapping &mapping) + : _mapping(mapping) { + LIN_ASSERT(mapping.rows() == mapping.cols()); + } + + /** @return Number of rows. + * + * This value is determined based on the size of the underlying mapping. If + * the mapping is resized, the returned row count may changed. If the resized + * mapping is no longer square, the diagonal reference is invalidated. + */ + constexpr size_t rows() const { + return _mapping.rows(); + } + + /** @return Number of columns. + * + * This always returns one. + */ + constexpr size_t cols() const { + return size_t(1); + } + + /** @brief Provides read and write access to tensor elements. + * + * @param i Row index. + * @param j Column index. + * + * @return Reference to the tensor element. + * + * The diagonal of the underlying stream is exposed as a column vector. + * + * If the indices are out of bounds as defined by the reference's current + * dimensions, lin assertion errors will be triggered. + */ + constexpr typename Traits::elem_t &operator()(size_t i, size_t j) { + LIN_ASSERT(i >= 0 && i < rows()); + LIN_ASSERT(j >= 0 && j < rows()); + + return _mapping(i, i); + } + + /** @brief Provides read and write access to tensor elements. + * + * @param i Index. + * + * @return Reference to the tensor element. + * + * Element access proceeds as if all the elements of the tensor stream were + * flattened into an array in row major order. + * + * If the index is out of bounds as defined by the reference's current size, + * lin assertion errors will be triggered. + */ + constexpr typename Traits::elem_t &operator()(size_t i) { + LIN_ASSERT(i >= 0 && i < size()); + + return _mapping(i, i); + } +}; + +template +struct _elem> { + typedef _elem_t type; +}; + +template +struct _dims> { + constexpr static size_t rows = E::Traits::rows; + constexpr static size_t cols = 1; + constexpr static size_t max_rows = E::Traits::max_rows; + constexpr static size_t max_cols = 1; +}; +} // namespace internal +} // namespace lin + +#endif diff --git a/include/lin/references/diagonal_stream_reference.hpp b/include/lin/references/diagonal_stream_reference.hpp new file mode 100644 index 0000000..21e1de1 --- /dev/null +++ b/include/lin/references/diagonal_stream_reference.hpp @@ -0,0 +1,151 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +/** @file lin/references/diagonal_stream_reference.hpp + * @author Kyle Krol + */ + +#ifndef LIN_REFERENCES_DIAGONAL_STREAM_REFERENCE_HPP_ +#define LIN_REFERENCES_DIAGONAL_STREAM_REFERENCE_HPP_ + +#include "../core.hpp" + +namespace lin { +namespace internal { + +/** @brief Generic diagonal reference with read only access. + * + * @tparam E Underlying referenced type. + * + * This allows users to treat the diagonal elements of a stream as a column + * vector. The underlying stream must have traits making is a square matrix. + * + * It's important to note, if the underlying stream goes out of scope the + * reference is invalidated. + * + * @sa internal::DiagonalMappingReference + * @sa internal::is_matrix + * @sa internal::is_square + */ +template +class DiagonalStreamReference : public Stream> { + static_assert(is_vector>::value, + "DiagonalStreamReference<...> types must have vector traits."); + static_assert(conjunction, is_square>::value, + "Underlying mapping for a diagonal reference must be a square matrix."); + + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits> Traits; + + /** @brief %Vector traits information for this type. + * + * @sa internal::vector_traits + */ + typedef vector_traits> VectorTraits; + + private: + Stream const &_stream; + + protected: + using Stream>::derived; + + public: + using Stream>::size; + using Stream>::eval; + + constexpr DiagonalStreamReference() = delete; + constexpr DiagonalStreamReference(DiagonalStreamReference const &) = default; + constexpr DiagonalStreamReference(DiagonalStreamReference &&) = default; + constexpr DiagonalStreamReference &operator=(DiagonalStreamReference const &) = default; + constexpr DiagonalStreamReference &operator=(DiagonalStreamReference &&) = default; + + /** @brief Constructs a new diagonal reference with the provided stream. + * + * @param stream Underlying stream. + * + * The provided stream must be square at runtime or lin assertion errors will + * be triggered. + * + * Resizing the stream to be something other than square after construction + * invalidates the reference. + */ + constexpr DiagonalStreamReference(Stream const &stream) + : _stream(stream) { + LIN_ASSERT(stream.rows() == stream.cols()); + } + + /** @return Number of rows. + * + * This value is determined based on the size of the underlying stream. If + * the stream is resized, the returned row count may changed. If the resized + * stream is no longer square, the diagonal reference is invalidated. + */ + constexpr size_t rows() const { + return _stream.rows(); + } + + /** @return Number of columns. + * + * This always returns one. + */ + constexpr size_t cols() const { + return size_t(1); + } + + /** @brief Provides read only access to tensor elements. + * + * @param i Row index. + * @param j Column index. + * + * @return Value of the tensor element. + * + * The diagonal of the underlying stream is exposed as a column vector. + * + * If the indices are out of bounds as defined by the reference's current + * dimensions, lin assertion errors will be triggered. + */ + constexpr typename Traits::elem_t operator()(size_t i, size_t j) const { + LIN_ASSERT(i >= 0 && i < rows()); + LIN_ASSERT(j >= 0 && j < cols()); + + return _stream(i, i); + } + + /** @brief Provides read only access to tensor elements. + * + * @param i Index. + * + * @return Value of the tensor element. + * + * Element access proceeds as if all the elements of the tensor stream were + * flattened into an array in row major order. + * + * If the index is out of bounds as defined by the reference's current size, + * lin assertion errors will be triggered. + */ + constexpr typename Traits::elem_t operator()(size_t i) const { + LIN_ASSERT(i >= 0 && i < size()); + + return _stream(i, i); + } +}; + +template +struct _elem> { + typedef _elem_t type; +}; + +template +struct _dims> { + constexpr static size_t rows = E::Traits::rows; + constexpr static size_t cols = 1; + constexpr static size_t max_rows = E::Traits::max_rows; + constexpr static size_t max_cols = 1; +}; +} // namespace internal +} // namespace lin + +#endif diff --git a/include/lin/references/inl/mapping_reference.inl b/include/lin/references/inl/mapping_reference.inl deleted file mode 100644 index f89ab38..0000000 --- a/include/lin/references/inl/mapping_reference.inl +++ /dev/null @@ -1,108 +0,0 @@ -/** @file lin/references/inl/mapping_reference.inl - * @author Kyle Krol - * See %lin/references/mapping_reference.hpp for more information. */ - -#include "../mapping_reference.hpp" - -namespace lin { -namespace internal { - -template -class MappingReference : public Mapping>, - public Dimensions> { - template - friend constexpr MappingReference lin::ref(lin::internal::Mapping &, - lin::size_t, lin::size_t, lin::size_t , lin::size_t); - - public: - /* Import elements from Mapping>. */ - using Mapping>::size; - using Mapping>::eval; - using Mapping>::operator=; - using Mapping>::operator(); - /* Import elements from Dimensions>. */ - using Dimensions>::rows; - using Dimensions>::cols; - /* Include traits information. */ - typedef traits> Traits; - /* Defaulted/deleted constructors and assignment operators. */ - constexpr MappingReference() = default; - constexpr MappingReference(MappingReference const &) = default; - constexpr MappingReference(MappingReference &&) = default; - constexpr MappingReference &operator=(MappingReference const &) = default; - constexpr MappingReference &operator=(MappingReference &&) = default; - /* Element access/evaluation functions. */ - constexpr typename Traits::elem_t &operator()(size_t i, size_t j); - constexpr typename Traits::elem_t &operator()(size_t i); - - protected: - /* Import elements from Mapping>. */ - using Mapping>::derived; - - private: - Mapping &d; - size_t const i, j; - /* Import elements from Dimensions>. */ - using Dimensions>::resize; - /* MappingReference constructor(s). */ - constexpr MappingReference(Mapping &d, size_t i, size_t j, size_t r, size_t c); -}; - -template -struct _elem> { - typedef _elem_t type; -}; - -template -struct _dims> { - static constexpr size_t rows = R; - static constexpr size_t cols = C; - static constexpr size_t max_rows = MR; - static constexpr size_t max_cols = MC; -}; - -template -constexpr traits_elem_t> & -MappingReference::operator()(size_t i, size_t j) { - LIN_ASSERT(i < rows() /* Invalid argument passed to MappingReference<...>::operator() */); - LIN_ASSERT(j < cols() /* Invalid argument passed to MappingReference<...>::operator() */); - return d(i + this->i, j + this->j); -} - -template -constexpr traits_elem_t> & -MappingReference::operator()(size_t i) { - return operator()(i / cols(), i % cols()); -} - -template -constexpr MappingReference::MappingReference(Mapping &d, size_t i, size_t j, size_t r, size_t c) -: d(d), i(i), j(j) { - LIN_ASSERT(i + r <= d.rows() /* Invalid argument passed to MappingReference<...>::MappingReference */); - LIN_ASSERT(j + c <= d.cols() /* Invalid argument passed to MappingReference<...>::MappingReference */); - resize(r, c); -} -} // namespace internal - -template -constexpr internal::MappingReference ref(internal::Mapping &d, - size_t i, size_t j, size_t r, size_t c) { - return internal::MappingReference(d, i, j, r, c); -} - -template -constexpr internal::MappingReference ref(internal::Mapping &d, - size_t i, size_t j) { - return ref(d, i, j); -} - -template -constexpr auto ref_row(internal::Mapping &d, size_t i) { - return ref<1, D::Traits::cols, 1, D::Traits::max_cols>(d, i, 0, 1, d.cols()); -} - -template -constexpr auto ref_col(internal::Mapping &d, size_t j) { - return ref(d, 0, j, d.rows(), 1); -} -} // namespace lin diff --git a/include/lin/references/inl/stream_reference.inl b/include/lin/references/inl/stream_reference.inl deleted file mode 100644 index eb36b84..0000000 --- a/include/lin/references/inl/stream_reference.inl +++ /dev/null @@ -1,106 +0,0 @@ -/** @file lin/references/inl/stream_reference.inl - * @author Kyle Krol - * See %lin/references/stream_reference.hpp for more information. */ - -#include "../stream_reference.hpp" - -namespace lin { -namespace internal { - -template -class StreamReference : public Stream>, - public Dimensions> { - template - friend constexpr StreamReference lin::ref(lin::internal::Stream const &, - lin::size_t, lin::size_t, lin::size_t , lin::size_t); - - public: - /* Import elements from Stream>. */ - using Stream>::size; - using Stream>::eval; - /* Import elements from Dimensions>. */ - using Dimensions>::rows; - using Dimensions>::cols; - /* Include traits information. */ - typedef traits> Traits; - /* Defaulted/deleted constructors and assignment operators. */ - constexpr StreamReference() = default; - constexpr StreamReference(StreamReference const &) = default; - constexpr StreamReference(StreamReference &&) = default; - constexpr StreamReference &operator=(StreamReference const &) = default; - constexpr StreamReference &operator=(StreamReference &&) = default; - /* Element access/evaluation functions. */ - constexpr typename Traits::elem_t operator()(size_t i, size_t j) const; - constexpr typename Traits::elem_t operator()(size_t i) const; - - protected: - /* Import elements from Stream>. */ - using Stream>::derived; - - private: - Stream const &d; - size_t const i, j; - /* Import elements from Dimensions>. */ - using Dimensions>::resize; - /* StreamReference constructor(s). */ - constexpr StreamReference(Stream const &d, size_t i, size_t j, size_t r, size_t c); -}; - -template -struct _elem> { - typedef _elem_t type; -}; - -template -struct _dims> { - static constexpr size_t rows = R; - static constexpr size_t cols = C; - static constexpr size_t max_rows = MR; - static constexpr size_t max_cols = MC; -}; - -template -constexpr traits_elem_t> -StreamReference::operator()(size_t i, size_t j) const { - LIN_ASSERT(i < rows() /* Invalid argument passed to StreamReference<...>::operator() */); - LIN_ASSERT(j < cols() /* Invalid argument passed to StreamReference<...>::operator() */); - return d(i + this->i, j + this->j); -} - -template -constexpr traits_elem_t> -StreamReference::operator()(size_t i) const { - return operator()(i / cols(), i % cols()); -} - -template -constexpr StreamReference::StreamReference(Stream const &d, size_t i, size_t j, size_t r, size_t c) -: d(d), i(i), j(j) { - LIN_ASSERT(i + r <= d.rows() /* Invalid argument passed to StreamReference<...>::StreamReference */); - LIN_ASSERT(j + c <= d.cols() /* Invalid argument passed to StreamReference<...>::StreamReference */); - resize(r, c); -} -} // namespace internal - -template -constexpr internal::StreamReference ref(internal::Stream const &d, - size_t i, size_t j, size_t r, size_t c) { - return internal::StreamReference(d, i, j, r, c); -} - -template -constexpr internal::StreamReference ref(internal::Stream const &d, - size_t i, size_t j) { - return ref(d, i, j); -} - -template -constexpr auto ref_row(internal::Stream const &d, size_t i) { - return ref<1, D::Traits::cols, 1, D::Traits::max_cols>(d, i, 0, 1, d.cols()); -} - -template -constexpr auto ref_col(internal::Stream const &d, size_t j) { - return ref(d, 0, j, d.rows(), 1); -} -} // namespace lin diff --git a/include/lin/references/mapping_reference.hpp b/include/lin/references/mapping_reference.hpp deleted file mode 100644 index 49ce528..0000000 --- a/include/lin/references/mapping_reference.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/** @file lin/references/mapping_reference.hpp - * @author Kyle Krol - * Defines the base reference type which is a read-write reference interface. - */ - -// TODO : Documenation for this whole file - -#ifndef LIN_REFERENCE_MAPPING_REFERENCE_HPP_ -#define LIN_REFERENCE_MAPPING_REFERENCE_HPP_ - -#include "../core.hpp" - -namespace lin { -namespace internal { - -/** @class MappingReference */ -template -class MappingReference; - -} // namespace internal - -/** @fn ref */ -template -constexpr internal::MappingReference ref(internal::Mapping &d, size_t i, size_t j, - size_t r = MR, size_t c = MC); - -/** @fn ref */ -template -constexpr internal::MappingReference ref(internal::Mapping &d, size_t i, size_t j); - -/** @fn ref_row */ -template -constexpr auto ref_row(internal::Mapping &d, size_t i); - -/** @fn ref_col */ -template -constexpr auto ref_col(internal::Mapping &d, size_t j); - -} // namespace lin - -#include "inl/mapping_reference.inl" - -#endif diff --git a/include/lin/references/matrix_mapping_reference.hpp b/include/lin/references/matrix_mapping_reference.hpp new file mode 100644 index 0000000..1ed0917 --- /dev/null +++ b/include/lin/references/matrix_mapping_reference.hpp @@ -0,0 +1,83 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +/** @file lin/references/matrix_mapping_reference.hpp + * @author Kyle Krol + */ + +#ifndef LIN_REFERENCES_MATRIX_MAPPING_REFERENCE_HPP_ +#define LIN_REFERENCES_MATRIX_MAPPING_REFERENCE_HPP_ + +#include "../core.hpp" +#include "tensor_mapping_reference.hpp" + +namespace lin { +namespace internal { + +/** @brief Generic matrix reference with read and write access. + * + * @tparam E Underlying referenced type. + * @tparam R Rows at compile time. + * @tparam C Columns at compile time. + * @tparam MR Maximum rows at compile time. + * @tparam MC Maximum columns at compile time. + * + * The template parameters specify the reference's traits. The traits must + * qualify the type as a matrix. + * + * It's important to note, if the underlying type goes out of scope the + * reference is invalidated. + * + * @sa internal::TensorMappingReference + * @sa internal::traits + * @sa internal::is_matrix + * + * @ingroup REFERENCES + */ +template +class MatrixMappingReference : public TensorMappingReference, E> { + static_assert(is_matrix>::value, + "Derived types to MatrixMappingReference<...> must have matrix traits"); + + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits> Traits; + + protected: + using TensorMappingReference, E>::derived; + using TensorMappingReference, E>::resize; + + public: + using TensorMappingReference, E>::TensorMappingReference; + using TensorMappingReference, E>::rows; + using TensorMappingReference, E>::cols; + using TensorMappingReference, E>::size; + using TensorMappingReference, E>::operator=; + using TensorMappingReference, E>::operator(); + using TensorMappingReference, E>::eval; + + constexpr MatrixMappingReference() = delete; + constexpr MatrixMappingReference(MatrixMappingReference const &) = default; + constexpr MatrixMappingReference(MatrixMappingReference &&) = default; + constexpr MatrixMappingReference &operator=(MatrixMappingReference const &) = default; + constexpr MatrixMappingReference &operator=(MatrixMappingReference &&) = default; +}; + +template +struct _elem> { + typedef _elem_t type; +}; + +template +struct _dims> { + static constexpr size_t rows = R; + static constexpr size_t cols = C; + static constexpr size_t max_rows = MR; + static constexpr size_t max_cols = MC; +}; +} // namespace internal +} // namespace lin + +#endif diff --git a/include/lin/references/matrix_stream_reference.hpp b/include/lin/references/matrix_stream_reference.hpp new file mode 100644 index 0000000..48197c6 --- /dev/null +++ b/include/lin/references/matrix_stream_reference.hpp @@ -0,0 +1,83 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +/** @file lin/references/matrix_stream_reference.hpp + * @author Kyle Krol + */ + +#ifndef LIN_REFERENCES_MATRIX_STREAM_REFERENCE_HPP_ +#define LIN_REFERENCES_MATRIX_STREAM_REFERENCE_HPP_ + +#include "../core.hpp" +#include "tensor_stream_reference.hpp" + +namespace lin { +namespace internal { + +/** @brief Generic matrix reference with read-only access. + * + * @tparam E Underlying referenced type. + * @tparam R Rows at compile time. + * @tparam C Columns at compile time. + * @tparam MR Maximum rows at compile time. + * @tparam MC Maximum columns at compile time. + * + * The template parameters specify the reference's traits. The traits must + * qualify the type as a matrix. + * + * It's important to note, if the underlying type goes out of scope the + * reference is invalidated. + * + * @sa internal::TensorStreamReference + * @sa internal::traits + * @sa internal::is_matrix + * + * @ingroup REFERENCES + */ +template +class MatrixStreamReference : public TensorStreamReference, E> { + static_assert(is_matrix>::value, + "Derived types to MatrixStreamReference<...> must have matrix traits"); + + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits> Traits; + + protected: + using TensorStreamReference, E>::derived; + using TensorStreamReference, E>::resize; + + public: + using TensorStreamReference, E>::TensorStreamReference; + using TensorStreamReference, E>::rows; + using TensorStreamReference, E>::cols; + using TensorStreamReference, E>::size; + using TensorStreamReference, E>::operator=; + using TensorStreamReference, E>::operator(); + using TensorStreamReference, E>::eval; + + constexpr MatrixStreamReference() = delete; + constexpr MatrixStreamReference(MatrixStreamReference const &) = default; + constexpr MatrixStreamReference(MatrixStreamReference &&) = default; + constexpr MatrixStreamReference &operator=(MatrixStreamReference const &) = default; + constexpr MatrixStreamReference &operator=(MatrixStreamReference &&) = default; +}; + +template +struct _elem> { + typedef _elem_t type; +}; + +template +struct _dims> { + static constexpr size_t rows = R; + static constexpr size_t cols = C; + static constexpr size_t max_rows = MR; + static constexpr size_t max_cols = MC; +}; +} // namespace internal +} // namespace lin + +#endif diff --git a/include/lin/references/stream_reference.hpp b/include/lin/references/stream_reference.hpp deleted file mode 100644 index 82ea9dd..0000000 --- a/include/lin/references/stream_reference.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/** @file lin/references/stream_reference.hpp - * @author Kyle Krol - * Defines the stream reference type which is a read-only reference interface. - * */ - -// TODO : Documenation for this whole fil - -#ifndef LIN_REFERENCE_STREAM_REFERENCE_HPP_ -#define LIN_REFERENCE_STREAM_REFERENCE_HPP_ - -#include "../core.hpp" - -namespace lin { -namespace internal { - -/** @class StreamReference */ -template -class StreamReference; - -} // namespace internal - -/** @fn ref */ -template -constexpr internal::StreamReference ref(internal::Stream const &d, - size_t i, size_t j, size_t r = MR, size_t c = MC); - -/** @fn ref */ -template -constexpr internal::StreamReference ref(internal::Stream const &d, - size_t i, size_t j); - -/** @fn ref_row */ -template -constexpr auto ref_row(internal::Stream const &d, size_t i); - -/** @fn ref_col */ -template -constexpr auto ref_col(internal::Stream const &d, size_t j); - -} // namespace lin - -#include "inl/stream_reference.inl" - -#endif diff --git a/include/lin/references/tensor_mapping_reference.hpp b/include/lin/references/tensor_mapping_reference.hpp new file mode 100644 index 0000000..fcb8d8c --- /dev/null +++ b/include/lin/references/tensor_mapping_reference.hpp @@ -0,0 +1,167 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +/** @file lin/references/tensor_mapping_reference.hpp + * @author Kyle Krol + */ + +#ifndef LIN_REFERENCES_TENSOR_MAPPING_REFERENCE_HPP_ +#define LIN_REFERENCES_TENSOR_MAPPING_REFERENCE_HPP_ + +#include "../core.hpp" + +namespace lin { +namespace internal { + +/** @brief Generic tensor reference with read and write access. + * + * @tparam D Derived type. + * @tparam E Underlying referenced type. + * + * This allows users to interpret a portion of a larger internal::Mapping as an + * independent tensor type with user specified traits. A common use may be to + * treat block diagonal elements of a larger matrix independently or perform + * vector operations on the columns of a matrix. + * + * It's important to note, if the underlying mapping goes out of scope the + * reference is invalidated. + * + * @sa internal::Mapping + * @sa internal::MatrixMappingReference + * @sa internal::VectorMappingReference + * @sa internal::RowVectorMappingReference + * + * @ingroup REFERENCES + */ +template +class TensorMappingReference : public Mapping, public Dimensions { + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits Traits; + + private: + Mapping &_mapping; + size_t const _i; + size_t const _j; + + protected: + using Mapping::derived; + + using Dimensions::resize; + + public: + using Mapping::size; + using Mapping::operator=; + using Mapping::operator(); + using Mapping::eval; + + using Dimensions::rows; + using Dimensions::cols; + + constexpr TensorMappingReference() = delete; + constexpr TensorMappingReference(TensorMappingReference const &) = default; + constexpr TensorMappingReference(TensorMappingReference &&) = default; + constexpr TensorMappingReference &operator=(TensorMappingReference const &) = default; + constexpr TensorMappingReference &operator=(TensorMappingReference &&) = default; + + /** @brief Constructs a new reference with the provided mapping and anchor + * point. + * + * @param mapping Underlying mapping. + * @param i Anchor point row index. + * @param j Anchor point column index. + * + * The reference's dimensions are defaulted to the largest allowable size and + * the anchor point maps the tops left corner of the reference to an element + * in the underlying mapping. + * + * The reference traits must define a type that fits within the provided + * mapping given the anchor point. If this is not the case, lin assertion + * errors will be triggered. + * + * The anchor points specifies where the top left corner of the reference + * maps to in the underlying mapping. + * + * @sa internal::traits + */ + constexpr TensorMappingReference(Mapping &mapping, size_t i, size_t j) + : _mapping(mapping), _i(i), _j(j) { + LIN_ASSERT((i >= 0) && (i + Traits::max_rows <= mapping.rows())); + LIN_ASSERT((j >= 0) && (j + Traits::max_cols <= mapping.cols())); + + resize(Traits::max_rows, Traits::max_cols); + } + + /** @brief Constructs a new reference with the provided mapping, anchor point, + * and dimensions. + * + * @param mapping Underlying mapping. + * @param i Anchor point row index. + * @param j Anchor point column index. + * @param r Reference row dimension. + * @param c Reference column dimension. + * + * The anchor point maps the tops left corner of the reference to an element + * in the underlying mapping. + * + * The reference traits must define a type that fits within the provided + * mapping given the anchor point. If this is not the case, lin assertion + * errors will be triggered. + * + * The anchor points specifies where the top left corner of the reference + * maps to in the underlying mapping. + * + * Lin assertions errors will be triggered if the requested dimensions aren't + * possible given the reference's traits. + * + * @sa internal::traits + */ + constexpr TensorMappingReference(Mapping &mapping, size_t i, size_t j, size_t r, size_t c) + : _mapping(mapping), _i(i), _j(j) { + LIN_ASSERT((i >= 0) && (i + r <= mapping.rows())); + LIN_ASSERT((j >= 0) && (j + c <= mapping.cols())); + + resize(r, c); + } + + /** @brief Provides read and write access to tensor elements. + * + * @param i Row index. + * @param j Column index. + * + * @return Reference to the tensor element. + * + * If the indices are out of bounds as defined by the reference's current + * dimensions, lin assertion errors will be triggered. + */ + constexpr typename Traits::elem_t &operator()(size_t i, size_t j) { + LIN_ASSERT((i >= 0) && (i < rows())); + LIN_ASSERT((j >= 0) && (j < cols())); + + return _mapping(_i + i, _j + j); + } + + /** @brief Provides read and write access to tensor elements. + * + * @param i Index. + * + * @return Reference to the tensor element. + * + * Element access proceeds as if all the elements of the tensor stream were + * flattened into an array in row major order. + * + * If the index is out of bounds as defined by the tensor's current size, lin + * assertion errors will be triggered. + */ + constexpr typename Traits::elem_t &operator()(size_t i) { + LIN_ASSERT((i >= 0) && (i < size())); + + return operator()(i / cols(), i % cols()); + } +}; +} // namespace internal +} // namespace lin + +#endif diff --git a/include/lin/references/tensor_stream_reference.hpp b/include/lin/references/tensor_stream_reference.hpp new file mode 100644 index 0000000..afa74cc --- /dev/null +++ b/include/lin/references/tensor_stream_reference.hpp @@ -0,0 +1,175 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +/** @file lin/references/tensor_stream_reference.hpp + * @author Kyle Krol + */ + +#ifndef LIN_REFERENCES_TENSOR_STREAM_REFERENCE_HPP_ +#define LIN_REFERENCES_TENSOR_STREAM_REFERENCE_HPP_ + +#include "../core.hpp" + +namespace lin { +namespace internal { + +/** @brief Generic tensor reference with read only access. + * + * @tparam D Derived type. + * @tparam E Underlying referenced type. + * + * This allows users to interpret a portion of a larger internal::Stream as an + * independent tensor type with user specified traits. A common use may be to + * treat block diagonal elements of a larger matrix independently or perform + * vector operations on the columns of a matrix. + * + * It's important to note, if the underlying stream goes out of scope the + * reference is invalidated. + * + * @sa internal::Stream + * @sa internal::MatrixStreamReference + * @sa internal::VectorStreamReference + * @sa internal::RowVectorStreamReference + * + * @ingroup REFERENCES + */ +template +class TensorStreamReference : public Stream, public Dimensions { + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits Traits; + + private: + Stream const &_stream; + size_t const _i; + size_t const _j; + + protected: + using Stream::derived; + + using Dimensions::resize; + + public: + using Stream::size; + using Stream::eval; + + using Dimensions::rows; + using Dimensions::cols; + + constexpr TensorStreamReference() = delete; + constexpr TensorStreamReference(TensorStreamReference const &) = default; + constexpr TensorStreamReference(TensorStreamReference &&) = default; + constexpr TensorStreamReference &operator=(TensorStreamReference const &) = default; + constexpr TensorStreamReference &operator=(TensorStreamReference &&) = default; + + /** @brief Constructs a new reference with the provided stream and anchor + * point. + * + * @param stream Underlying stream. + * @param i Anchor point row index. + * @param j Anchor point column index. + * + * The reference's dimensions are defaulted to the largest allowable size and + * the anchor point maps the top left corner of the reference to an element + * in the underlying stream. + * + * The reference traits must define a type that fits within the provided + * mapping given the anchor point. If this is not the case, lin assertion + * errors will be triggered. + * + * The anchor points specifies where the top left corner of the reference + * maps to in the underlying stream. + * + * @sa internal::traits + */ + constexpr TensorStreamReference(Stream const &stream, size_t i, size_t j) + : _stream(stream), _i(i), _j(j) { + LIN_ASSERT((i >= 0) && (i + Traits::max_rows <= stream.rows())); + LIN_ASSERT((j >= 0) && (j + Traits::max_cols <= stream.cols())); + + resize(Traits::max_rows, Traits::max_cols); + } + + /** @brief Constructs a new reference with the provided mapping, anchor point, + * and dimensions. + * + * @param mapping Underlying stream. + * @param i Anchor point row index. + * @param j Anchor point column index. + * @param r Reference row dimension. + * @param c Reference column dimension. + * + * The anchor point maps the top left corner of the reference to an element + * in the underlying stream. + * + * The reference traits must define a type that fits within the provided + * mapping given the anchor point. If this is not the case, lin assertion + * errors will be triggered. + * + * The anchor points specifies where the top left corner of the reference + * maps to in the underlying stream. + * + * Lin assertions errors will be triggered if the requested dimensions aren't + * possible given the reference's traits. + * + * @sa internal::traits + */ + constexpr TensorStreamReference(Stream const &stream, size_t i, size_t j, size_t r, size_t c) + : _stream(stream), _i(i), _j(j) { + LIN_ASSERT((i >= 0) && (i + r <= stream.rows())); + LIN_ASSERT((j >= 0) && (j + c <= stream.cols())); + + resize(r, c); + } + + /** @brief Provides read only access to tensor elements. + * + * @param i Row index. + * @param j Column index. + * + * @return Value of the tensor element. + * + * If the indices are out of bounds as defined by the reference's current + * dimensions, lin assertion errors will be triggered. + * + * If accessing data from a lazily evaluation tensor operation, you may want + * to consider for the creation of a value backed type to reduce overhead. + * + * @sa internal::Stream::eval + */ + constexpr typename Traits::elem_t operator()(size_t i, size_t j) const { + LIN_ASSERT((i >= 0) && (i < rows())); + LIN_ASSERT((j >= 0) && (j < cols())); + + return _stream(_i + i, _j + j); + } + + /** @brief Provides read only access to tensor elements. + * + * @param i Index. + * + * @return Reference to the tensor element. + * + * Element access proceeds as if all the elements of the tensor stream were + * flattened into an array in row major order. + * + * If the index is out of bounds as defined by the tensor's current size, lin + * assertion errors will be triggered. + * + * If accessing data from a lazily evaluation tensor operation, you may want + * to consider for the creation of a value backed type to reduce overhead. + * + * @sa internal::Stream::eval + */ + constexpr typename Traits::elem_t operator()(size_t i) const { + LIN_ASSERT((i >= 0) && (i < size())); + + return operator()(i / cols(), i % cols()); + } +}; +} // namespace internal +} // namespace lin + +#endif diff --git a/include/lin/references/vector_mapping_reference.hpp b/include/lin/references/vector_mapping_reference.hpp new file mode 100644 index 0000000..13f6ea1 --- /dev/null +++ b/include/lin/references/vector_mapping_reference.hpp @@ -0,0 +1,208 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +/** @file lin/references/vector_mapping_reference.hpp + * @author Kyle Krol + */ + +#ifndef LIN_REFERENCES_VECTOR_MAPPING_REFERENCE_HPP_ +#define LIN_REFERENCES_VECTOR_MAPPING_REFERENCE_HPP_ + +#include "../core.hpp" +#include "tensor_mapping_reference.hpp" + +namespace lin { +namespace internal { + +/** @brief Generic vector reference with read and write access. + * + * @tparam E Underlying referenced type. + * @tparam N Length at compile time. + * @tparam MN Maximum length at compile time. + * + * The template parameters specify the reference's traits. The traits must + * qualify the type as a column vector. + * + * It's important to note, if the underlying type goes out of scope the + * reference is invalidated. + * + * @sa internal::TensorMappingReference + * @sa internal::traits + * @sa internal::is_col_vector + * + * @ingroup REFERENCES + */ +template +class VectorMappingReference : public TensorMappingReference, E> { + static_assert(is_col_vector>::value, + "Derived types to VectorMappingReference<...> must have column vector traits"); + + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits> Traits; + + /** @brief %Vector traits information for this type. + * + * @sa internal::vector_traits + */ + typedef vector_traits> VectorTraits; + + protected: + using TensorMappingReference, E>::derived; + using TensorMappingReference, E>::resize; + + public: + using TensorMappingReference, E>::TensorMappingReference; + using TensorMappingReference, E>::rows; + using TensorMappingReference, E>::cols; + using TensorMappingReference, E>::size; + using TensorMappingReference, E>::operator=; + using TensorMappingReference, E>::operator(); + using TensorMappingReference, E>::eval; + + constexpr VectorMappingReference() = delete; + constexpr VectorMappingReference(VectorMappingReference const &) = default; + constexpr VectorMappingReference(VectorMappingReference &&) = default; + constexpr VectorMappingReference &operator=(VectorMappingReference const &) = default; + constexpr VectorMappingReference &operator=(VectorMappingReference &&) = default; + + /** @brief Constructs a new vector reference with the provided mapping, anchor + * point, and length. + * + * @param mapping Underlying mapping. + * @param i Anchor point row index. + * @param j Anchor point column index. + * @param n Reference length. + * + * The anchor point maps the tops left corner of the reference to an element + * in the underlying mapping. + * + * The reference vector's traits must define a type that fits within the + * provided mapping given the anchor point. If this is not the case, lin + * assertion errors will be triggered. + * + * The anchor points specifies where the top left corner of the reference + * maps to in the underlying mapping. + * + * Lin assertions errors will be triggered if the requested length isn't + * possible given the reference's traits. + * + * @sa internal::traits + */ + constexpr VectorMappingReference(Mapping &mapping, size_t i, size_t j, size_t n) + : TensorMappingReference, E>(mapping, i, j, n, 1) { } +}; + +template +struct _elem> { + typedef _elem_t type; +}; + +template +struct _dims> { + static constexpr size_t rows = N; + static constexpr size_t cols = 1; + static constexpr size_t max_rows = MN; + static constexpr size_t max_cols = 1; +}; + +/** @brief Generic row vector reference with read and write access. + * + * @tparam E Underlying referenced type. + * @tparam N Length at compile time. + * @tparam MN Maximum length at compile time. + * + * The template parameters specify the reference's traits. The traits must + * qualify the type as a row vector. + * + * It's important to note, if the underlying type goes out of scope the + * reference is invalidated. + * + * @sa internal::TensorMappingReference + * @sa internal::traits + * @sa internal::is_row_vector + * + * @ingroup REFERENCES + */ +template +class RowVectorMappingReference : public TensorMappingReference, E> { + static_assert(is_row_vector>::value, + "Derived types to RowVectorMappingReference<...> must have row vector traits"); + + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits> Traits; + + /** @brief %Vector traits information for this type. + * + * @sa internal::vector_traits + */ + typedef vector_traits> VectorTraits; + + protected: + using TensorMappingReference, E>::derived; + using TensorMappingReference, E>::resize; + + public: + using TensorMappingReference, E>::TensorMappingReference; + using TensorMappingReference, E>::rows; + using TensorMappingReference, E>::cols; + using TensorMappingReference, E>::size; + using TensorMappingReference, E>::operator=; + using TensorMappingReference, E>::operator(); + using TensorMappingReference, E>::eval; + + constexpr RowVectorMappingReference() = delete; + constexpr RowVectorMappingReference(RowVectorMappingReference const &) = default; + constexpr RowVectorMappingReference(RowVectorMappingReference &&) = default; + constexpr RowVectorMappingReference &operator=(RowVectorMappingReference const &) = default; + constexpr RowVectorMappingReference &operator=(RowVectorMappingReference &&) = default; + + /** @brief Constructs a new row vector reference with the provided mapping, + * anchor point, and length. + * + * @param mapping Underlying mapping. + * @param i Anchor point row index. + * @param j Anchor point column index. + * @param n Reference length. + * + * The anchor point maps the tops left corner of the reference to an element + * in the underlying mapping. + * + * The reference row vector's traits must define a type that fits within the + * provided mapping given the anchor point. If this is not the case, lin + * assertion errors will be triggered. + * + * The anchor points specifies where the top left corner of the reference + * maps to in the underlying mapping. + * + * Lin assertions errors will be triggered if the requested length isn't + * possible given the reference's traits. + * + * @sa internal::traits + */ + constexpr RowVectorMappingReference(Mapping &mapping, size_t i, size_t j, size_t n) + : TensorMappingReference, E>(mapping, i, j, 1, n) { } +}; + +template +struct _elem> { + typedef _elem_t type; +}; + +template +struct _dims> { + static constexpr size_t rows = 1; + static constexpr size_t cols = N; + static constexpr size_t max_rows = 1; + static constexpr size_t max_cols = MN; +}; +} // namespace internal +} // namespace lin + +#endif diff --git a/include/lin/references/vector_stream_reference.hpp b/include/lin/references/vector_stream_reference.hpp new file mode 100644 index 0000000..1e587ce --- /dev/null +++ b/include/lin/references/vector_stream_reference.hpp @@ -0,0 +1,208 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +/** @file lin/references/vector_stream_reference.hpp + * @author Kyle Krol + */ + +#ifndef LIN_REFERENCES_VECTOR_STREAM_REFERENCE_HPP_ +#define LIN_REFERENCES_VECTOR_STREAM_REFERENCE_HPP_ + +#include "../core.hpp" +#include "tensor_stream_reference.hpp" + +namespace lin { +namespace internal { + +/** @brief Generic vector reference with read only access. + * + * @tparam E Underlying referenced type. + * @tparam N Length at compile time. + * @tparam MN Maximum length at compile time. + * + * The template parameters specify the reference's traits. The traits must + * qualify the type as a column vector. + * + * It's important to note, if the underlying type goes out of scope the + * reference is invalidated. + * + * @sa internal::TensorStreamReference + * @sa internal::traits + * @sa internal::is_col_vector + * + * @ingroup REFERENCES + */ +template +class VectorStreamReference : public TensorStreamReference, E> { + static_assert(is_col_vector>::value, + "Derived types to VectorStreamReference<...> must have column vector traits"); + + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits> Traits; + + /** @brief %Vector traits information for this type. + * + * @sa internal::vector_traits + */ + typedef vector_traits> VectorTraits; + + protected: + using TensorStreamReference, E>::derived; + using TensorStreamReference, E>::resize; + + public: + using TensorStreamReference, E>::TensorStreamReference; + using TensorStreamReference, E>::rows; + using TensorStreamReference, E>::cols; + using TensorStreamReference, E>::size; + using TensorStreamReference, E>::operator=; + using TensorStreamReference, E>::operator(); + using TensorStreamReference, E>::eval; + + constexpr VectorStreamReference() = delete; + constexpr VectorStreamReference(VectorStreamReference const &) = default; + constexpr VectorStreamReference(VectorStreamReference &&) = default; + constexpr VectorStreamReference &operator=(VectorStreamReference const &) = default; + constexpr VectorStreamReference &operator=(VectorStreamReference &&) = default; + + /** @brief Constructs a new vector reference with the provided stream, anchor + * point, and length. + * + * @param stream Underlying stream. + * @param i Anchor point row index. + * @param j Anchor point column index. + * @param n Reference length. + * + * The anchor point maps the tops left corner of the reference to an element + * in the underlying stream. + * + * The reference vector's traits must define a type that fits within the + * provided mapping given the anchor point. If this is not the case, lin + * assertion errors will be triggered. + * + * The anchor points specifies where the top left corner of the reference + * maps to in the underlying stream. + * + * Lin assertions errors will be triggered if the requested length isn't + * possible given the reference's traits. + * + * @sa internal::traits + */ + constexpr VectorStreamReference(Stream const &stream, size_t i, size_t j, size_t n) + : TensorStreamReference, E>(stream, i, j, n, 1) { } +}; + +template +struct _elem> { + typedef _elem_t type; +}; + +template +struct _dims> { + static constexpr size_t rows = N; + static constexpr size_t cols = 1; + static constexpr size_t max_rows = MN; + static constexpr size_t max_cols = 1; +}; + +/** @brief Generic row vector reference with read only access. + * + * @tparam E Underlying referenced type. + * @tparam N Length at compile time. + * @tparam MN Maximum length at compile time. + * + * The template parameters specify the reference's traits. The traits must + * qualify the type as a row vector. + * + * It's important to note, if the underlying type goes out of scope the + * reference is invalidated. + * + * @sa internal::TensorStreamReference + * @sa internal::traits + * @sa internal::is_row_vector + * + * @ingroup REFERENCES + */ +template +class RowVectorStreamReference : public TensorStreamReference, E> { + static_assert(is_row_vector>::value, + "Derived types to RowVectorStreamReference<...> must have row vector traits"); + + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits> Traits; + + /** @brief %Vector traits information for this type. + * + * @sa internal::vector_traits + */ + typedef vector_traits> VectorTraits; + + protected: + using TensorStreamReference, E>::derived; + using TensorStreamReference, E>::resize; + + public: + using TensorStreamReference, E>::TensorStreamReference; + using TensorStreamReference, E>::rows; + using TensorStreamReference, E>::cols; + using TensorStreamReference, E>::size; + using TensorStreamReference, E>::operator=; + using TensorStreamReference, E>::operator(); + using TensorStreamReference, E>::eval; + + constexpr RowVectorStreamReference() = delete; + constexpr RowVectorStreamReference(RowVectorStreamReference const &) = default; + constexpr RowVectorStreamReference(RowVectorStreamReference &&) = default; + constexpr RowVectorStreamReference &operator=(RowVectorStreamReference const &) = default; + constexpr RowVectorStreamReference &operator=(RowVectorStreamReference &&) = default; + + /** @brief Constructs a new row vector reference with the provided mapping, + * anchor point, and length. + * + * @param stream Underlying stream. + * @param i Anchor point row index. + * @param j Anchor point column index. + * @param n Reference length. + * + * The anchor point maps the tops left corner of the reference to an element + * in the underlying stream. + * + * The reference row vector's traits must define a type that fits within the + * provided mapping given the anchor point. If this is not the case, lin + * assertion errors will be triggered. + * + * The anchor points specifies where the top left corner of the reference + * maps to in the underlying stream. + * + * Lin assertions errors will be triggered if the requested length isn't + * possible given the reference's traits. + * + * @sa internal::traits + */ + constexpr RowVectorStreamReference(Stream const &stream, size_t i, size_t j, size_t n) + : TensorStreamReference, E>(stream, i, j, 1, n) { } +}; + +template +struct _elem> { + typedef _elem_t type; +}; + +template +struct _dims> { + static constexpr size_t rows = 1; + static constexpr size_t cols = N; + static constexpr size_t max_rows = 1; + static constexpr size_t max_cols = MN; +}; +} // namespace internal +} // namespace lin + +#endif diff --git a/include/lin/substitutions/inl/backward_substitution.inl b/include/lin/substitutions/inl/backward_substitution.inl index 13ad29e..bea5e90 100644 --- a/include/lin/substitutions/inl/backward_substitution.inl +++ b/include/lin/substitutions/inl/backward_substitution.inl @@ -22,13 +22,13 @@ constexpr int backward_sub(internal::Mapping const &U, internal::Mapping & // Solve for the last rows // It's trivially the last row of Y divided by the bottom right element of U const size_t m = U.rows() - 1; - ref_row(X, m) = ref_row(Y, m) / U(m, m); + row(X, m) = row(Y, m) / U(m, m); // Solve for the other rows in descending order for (size_t n = m - 1;; n--) { - ref_row(X, n) = ( - ref_row(Y, n) - (ref<1, 0, 1, TU::max_rows>(U, n, n + 1, 1, m - n) * - ref<0, TY::cols, TY::max_rows, TY::max_cols>(X, n + 1, 0, m - n, X.cols())) + row(X, n) = ( + row(Y, n) - (ref>(U, n, n + 1, m - n) * + ref>(X, n + 1, 0, m - n, X.cols())) ) / U(n, n); if (n == 0) break; // Must perform this check here for unsigned valu } diff --git a/include/lin/substitutions/inl/forward_substitution.inl b/include/lin/substitutions/inl/forward_substitution.inl index 8230bcb..99e4457 100644 --- a/include/lin/substitutions/inl/forward_substitution.inl +++ b/include/lin/substitutions/inl/forward_substitution.inl @@ -17,19 +17,20 @@ constexpr int forward_sub(internal::Mapping const &L, internal::Mapping &X LIN_ASSERT(Y.cols() == X.cols() /* X cols don't match in forward_sub(...) */); // Useful traits information + typedef typename C::Traits::elem_t Elem; constexpr size_t C_max_cols = C::Traits::max_cols; constexpr size_t E_cols = E::Traits::cols; constexpr size_t E_max_rows = E::Traits::max_rows; constexpr size_t E_max_cols = E::Traits::max_cols; // X(0, :) - lin::ref_row(X, 0) = lin::ref_row(Y, 0) / L(0, 0); + row(X, 0) = row(Y, 0) / L(0, 0); // X(1:, :) for (size_t i = 1; i < X.rows(); i++) // X(i, :) - lin::ref_row(X, i) = ( lin::ref_row(Y, i) - lin::ref<1, 0, 1, C_max_cols>(L, i, 0, 1, i) * - lin::ref<0, E_cols, E_max_rows, E_max_cols>(X, 0, 0, i, X.cols()) + row(X, i) = ( row(Y, i) - ref>(L, i, 0, i) * + ref>(X, 0, 0, i, X.cols()) ) / L(i, i); return 0; diff --git a/include/lin/views.hpp b/include/lin/views.hpp index 042adc1..8bf14e6 100644 --- a/include/lin/views.hpp +++ b/include/lin/views.hpp @@ -1,24 +1,50 @@ // vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab +// +// MIT License +// +// Copyright (c) 2020 kylekrol +// Copyright (c) 2020 Pathfinder for Autonomous Navigation (PAN) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + /** @file lin/views.hpp * @author Kyle Krol */ /** @defgroup VIEWS Views - * - * @brief Defines the tensor view types which allow raw pointers to be - * interpretted as value backed tensor types. - * + * + * @brief Allows arbitrary data buffers to be interpreted as value backed + * tensor types. + * * ## Overview * * The views module serves one main purpose: to allows external buffers to be * interpretted as tensor objects within lin. - * - * This may can be extremely helpful, say if you'd like to treat an array from - * the STL with length of three as a three dimensional lin vector. Once you - * create a lin::VectorView3f from it, it'll be compatible with all of lin - * operations and write changes directly back into the original array object. * + * This can be extremely helpful, say for example, if you'd like to treat an + * array from the STL as a three dimensional vector and perform some operations + * in a function to mutate it. All that's required is to use the lin::view + * function to create a vector view and then leverage the rest of the lin + * library. + * * See the following example which treats an array as a three dimensional * vector and rotates it in place about the z-axis by an angle `alpha`: * @@ -30,8 +56,8 @@ * #include * * void rotate_z(std::array &array, float alpha) { - * lin::VectorView3f v(array.data()); - * lin::Matrix3x3f R { + * auto v = lin::view(array.data()); + * lin::Matrix3x3f R = { * std::cos(alpha), -std::sin(alpha), 0.0f, * std::sin(alpha), std::cos(alpha), 0.0f, * 0.0f, 0.0f, 1.0f @@ -39,13 +65,229 @@ * v = (R * v).eval(); * } * ~~~ + * + * It's important to note that there are actually two types of views that can + * be returned by lin::view. The first is a standard view which allows read and + * write access to the underlying elements (this is seen in the example above). + * The second is known as a constant view and only allows read access to the + * underlying elements. This is done automatically if the buffer passed to + * lin::view points to const elements. */ #ifndef LIN_VIEWS_HPP_ #define LIN_VIEWS_HPP_ +#include "core.hpp" +#include "views/const_matrix_view.hpp" +#include "views/const_vector_view.hpp" #include "views/matrix_view.hpp" -#include "views/tensor_view.hpp" #include "views/vector_view.hpp" +#include + +namespace lin { +namespace internal { + +/** @internal + * + * @brief Provides a specific tensor type's corresponding view type. + * + * @tparam C %Tensor type. + * + * @sa internal::const_view + * + * @ingroup VIEWS + */ +template +struct view { }; + +template +using view_t = typename view::type; + +template +struct view::value>> { + typedef MatrixView type; +}; + +template +struct view::value>> { + typedef VectorView type; +}; + +template +struct view::value>> { + typedef RowVectorView type; +}; + +/** @internal + * + * @brief Provides a specific tensor type's corresponding constant view type. + * + * @tparam C %Tensor type. + * + * @sa internal::view + * + * @ingroup VIEWS + */ +template +struct const_view { }; + +template +using const_view_t = typename const_view::type; + +template +struct const_view::value>> { + typedef ConstMatrixView type; +}; + +template +struct const_view::value>> { + typedef ConstVectorView type; +}; + +template +struct const_view::value>> { + typedef ConstRowVectorView type; +}; +} // namespace internal + +/** @brief Creates a tensor view with default dimensions. + * + * @tparam C %Tensor type whose traits are replicated. + * + * @param elems Element backing array. + * + * @return internal::MatrixView, internal::RowVectorView, or + * internal::VectorView. + * + * If the view's traits support variable dimensions, the view is constructed + * with the largest allowable dimensions (i.e. default dimensions). + * + * @sa internal::traits + * @sa internal::view + * + * @ingroup VIEWS + */ +template ::value>> +constexpr auto view(typename C::Traits::elem_t *elems) { + return internal::view_t(elems); +} + +/** @brief Creates a vector view with the provided length. + * + * @tparam C %Vector type whose traits are replicated. + * + * @param elems Element backing array. + * @param n Initial length. + * + * @return internal::RowVectorView or internal::VectorView. + * + * Lin assertion errors will be triggered if the requested length isn't + * possible given the vector view's traits. + * + * @sa internal::traits + * @sa internal::view + * + * @ingroup VIEWS + */ +template , internal::is_vector>::value>> +constexpr auto view(typename C::Traits::elem_t *elems, size_t n) { + return internal::view_t(elems, n); +} + +/** @brief Creates a tensor view with the provided dimensions. + * + * @tparam C %Tensor type whose traits are replicated. + * + * @param elems Element backing array. + * @param r Initial row dimension. + * @param c Initial column dimension. + * + * @return internal::MatrixView, internal::RowVectorView, or + * internal::VectorView. + * + * Lin assertions errors will be triggered if the requested dimensions aren't + * possible given the view's traits. + * + * @sa internal::traits + * @sa internal::view + * + * @ingroup VIEWS + */ +template ::value>> +constexpr auto view(typename C::Traits::elem_t *elems, size_t r, size_t c) { + return internal::view_t(elems, r, c); +} + +/** @brief Creates a constant tensor view with default dimensions. + * + * @tparam C %Tensor type whose traits are replicated. + * + * @param elems Constant element backing array. + * + * @return internal::ConstMatrixView, internal::ConstRowVectorView, or + * internal::ConstVectorView. + * + * If the view's traits support variable dimensions, the view is constructed + * with the largest allowable dimensions (i.e. default dimensions). + * + * @sa internal::traits + * @sa internal::const_view + * + * @ingroup VIEWS + */ +template ::value>> +constexpr auto view(typename C::Traits::elem_t const *elems) { + return internal::const_view_t(elems); +} + +/** @brief Creates a constant vector view with the provided length. + * + * @tparam C %Vector type whose traits are replicated. + * + * @param elems Constant element backing array. + * @param n Initial length. + * + * @return internal::ConstRowVectorView or internal::ConstVectorView. + * + * Lin assertion errors will be triggered if the requested length isn't + * possible given the vector view's traits. + * + * @sa internal::traits + * @sa internal::const_view + * + * @ingroup VIEWS + */ +template , internal::is_vector>::value>> +constexpr auto view(typename C::Traits::elem_t const *elems, size_t n) { + return internal::const_view_t(elems, n); +} + +/** @brief Creates a constant tensor view with the provided dimensions. + * + * @tparam C %Tensor type whose traits are replicated. + * + * @param elems Constant element backing array. + * @param r Initial row dimension. + * @param c Initial column dimension. + * + * @return internal::ConstMatrixView, internal::ConstRowVectorView, or + * internal::ConstVectorView. + * + * Lin assertions errors will be triggered if the requested dimensions aren't + * possible given the view's traits. + * + * @sa internal::traits + * @sa internal::const_view + * + * @ingroup VIEWS + */ +template ::value>> +constexpr auto view(typename C::Traits::elem_t const *elems, size_t r, size_t c) { + return internal::const_view_t(elems, r, c); +} +} // namespace lin + #endif diff --git a/include/lin/views/const_matrix_view.hpp b/include/lin/views/const_matrix_view.hpp new file mode 100644 index 0000000..57703c7 --- /dev/null +++ b/include/lin/views/const_matrix_view.hpp @@ -0,0 +1,79 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +/** @file lin/views/const_matrix_view.hpp + * @author Kyle Krol + */ + +#ifndef LIN_VIEWS_CONST_MATRIX_VIEW_HPP_ +#define LIN_VIEWS_CONST_MATRIX_VIEW_HPP_ + +#include "../core.hpp" +#include "const_tensor_view.hpp" + +namespace lin { +namespace internal { + +/** @brief Generic constant matrix view. + * + * @tparam T Constant matrix view element type. + * @tparam R Rows at compile time. + * @tparam C Columns at compile time. + * @tparam MR Maximum rows at compile time. + * @tparam MC Maximum columns at compile time. + * + * The template parameters specify the matrix view's traits. The traits must + * qualify this type as a matrix. + * + * @sa internal::traits + * @sa internal::is_matrix + * + * @ingroup VIEWS + */ +template +class ConstMatrixView : public ConstTensorView> { + static_assert(is_matrix>::value, + "Invalid ConstMatrixView<...> parameters"); + + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits> Traits; + + protected: + using ConstTensorView>::derived; + + public: + using ConstTensorView>::ConstTensorView; + using ConstTensorView>::rows; + using ConstTensorView>::cols; + using ConstTensorView>::size; + using ConstTensorView>::data; + using ConstTensorView>::eval; + using ConstTensorView>::resize; + using ConstTensorView>::operator(); + + constexpr ConstMatrixView() = delete; + constexpr ConstMatrixView(ConstMatrixView const &) = default; + constexpr ConstMatrixView(ConstMatrixView &&) = default; + constexpr ConstMatrixView &operator=(ConstMatrixView const &) = default; + constexpr ConstMatrixView &operator=(ConstMatrixView &&) = default; +}; + +template +struct _elem> { + typedef T type; +}; + +template +struct _dims> { + static constexpr size_t rows = R; + static constexpr size_t cols = C; + static constexpr size_t max_rows = MR; + static constexpr size_t max_cols = MC; +}; +} // namespace internal +} // namespace lin + +#endif diff --git a/include/lin/views/const_tensor_view.hpp b/include/lin/views/const_tensor_view.hpp new file mode 100644 index 0000000..9d0a603 --- /dev/null +++ b/include/lin/views/const_tensor_view.hpp @@ -0,0 +1,118 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +/** @file lin/views/const_tensor_view.hpp + * @author Kyle Krol + */ + +#ifndef LIN_VIEWS_CONST_TENSOR_VIEW_HPP_ +#define LIN_VIEWS_CONST_TENSOR_VIEW_HPP_ + +#include "../core.hpp" + +namespace lin { +namespace internal { + +/** @brief Member pointer backed constant tensor. + * + * @tparam D Derived type. + * + * This allows users to interpret arbitrary buffers as tensor objects. The user + * specified buffer is assumed to be at least as large as the tensor's maximum + * size and elements are read and written to the buffer in row major order. + * + * @sa internal::ConstBase + * @sa internal::ConstMatrixView + * @sa internal::ConstRowVectorView + * @sa internal::ConstVectorView + * + * @ingroup VIEWS + */ +template +class ConstTensorView : public ConstBase { + static_assert(has_valid_traits::value, + "Derived types to ConstTensor<...> must have valid traits"); + + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits Traits; + + private: + typename Traits::elem_t const *const elems; + + protected: + using ConstBase::derived; + + public: + using ConstBase::rows; + using ConstBase::cols; + using ConstBase::resize; + using ConstBase::size; + using ConstBase::operator(); + using ConstBase::eval; + + constexpr ConstTensorView() = delete; + constexpr ConstTensorView(ConstTensorView const &) = default; + constexpr ConstTensorView(ConstTensorView &&) = default; + constexpr ConstTensorView &operator=(ConstTensorView const &) = default; + constexpr ConstTensorView &operator=(ConstTensorView &&) = default; + + /** @brief Constructs a new constant tensor tensor view with the provided + * backing array. + * + * @param elems Constant element backing array. + * + * The element backing array is a assumed to be in row major order. Elements + * of the tensor initially hold whatever values were left in the backing + * array. + * + * The backing array should be at least as large as the maximum size of the + * tensor (see internal::traits information). + * + * The size of the tensor defaults to the maximum allowed size. + */ + constexpr ConstTensorView(typename Traits::elem_t const *elems) + : elems(elems) { + resize(Traits::max_rows, Traits::max_cols); + } + + /** @brief Constructs a new constant tensor tensor view with the provided + * backing array and requested dimensions. + * + * @param elems Constant element backing array. + * @param r Initial row dimension. + * @param c Initial column dimension. + * + * The element backing array is a assumed to be in row major order. Elements + * of the tensor initially hold whatever values were left in the backing + * array. + * + * The backing array should be at least as large as the maximum size of the + * tensor (see internal::traits information). + * + * Lin assertions errors will be triggered if the requested dimensions aren't + * possible given the tensor's traits. + * + * @sa internal::traits + */ + constexpr ConstTensorView(typename Traits::elem_t const *elems, size_t r, size_t c) + : elems(elems) { + resize(r, c); + } + + /** @brief Retrives a constant pointer to the element backing array. + * + * @returns Constant pointer to the backing array. + * + * This is the same buffer the tensor view was constructed with. + */ + constexpr typename Traits::elem_t const *data() const { + return elems; + } +}; +} // namespace internal +} // namespace lin + +#endif diff --git a/include/lin/views/const_vector_view.hpp b/include/lin/views/const_vector_view.hpp new file mode 100644 index 0000000..8a326a5 --- /dev/null +++ b/include/lin/views/const_vector_view.hpp @@ -0,0 +1,213 @@ +// vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab + +/** @file lin/views/const_vector_view.hpp + * @author Kyle Krol + */ + +#ifndef LIN_VIEWS_CONST_VECTOR_VIEW_HPP_ +#define LIN_VIEWS_CONST_VECTOR_VIEW_HPP_ + +#include "../core.hpp" +#include "const_tensor_view.hpp" + +namespace lin { +namespace internal { + +/** @brief Generic constant vector view. + * + * @tparam T Constant vector view element type. + * @tparam N Number of elements at compile time (i.e. number of rows). + * @tparam MN Maximum number of elements (i.e. maximum number of rows). + * + * The template parameters specify the vector views's traits. The traits must + * qualify this type as a column vector. + * + * @sa internal::traits + * @sa internal::is_col_vector + * + * @ingroup VIEWS + */ +template +class ConstVectorView : public ConstTensorView> { + static_assert(is_col_vector>::value, + "Invalid ConstVectorView<...> parameters"); + + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits> Traits; + + /** @brief Vector traits information for this type. + * + * @sa internal::vector_traits + */ + typedef vector_traits> VectorTraits; + + protected: + using ConstTensorView>::derived; + + public: + using ConstTensorView>::ConstTensorView; + using ConstTensorView>::rows; + using ConstTensorView>::cols; + using ConstTensorView>::size; + using ConstTensorView>::data; + using ConstTensorView>::eval; + using ConstTensorView>::resize; + using ConstTensorView>::operator(); + + constexpr ConstVectorView() = delete; + constexpr ConstVectorView(ConstVectorView const &) = default; + constexpr ConstVectorView(ConstVectorView &&) = default; + constexpr ConstVectorView &operator=(ConstVectorView const &) = default; + constexpr ConstVectorView &operator=(ConstVectorView &&) = default; + + /** @brief Constructs a constant vector view with the provided backing array + * and requested length. + * + * @param elems Constant element backing array. + * @param n Initial length. + * + * The backing array should be at least as large as the maximum length of the + * vector (see internal::traits information). + * + * Lin assertion errors will be triggered if the requested length isn't + * possible given the vector view's traits. + * + * @sa internal::has_fixed_rows + * @sa internal::has_strictly_bounded_rows + */ + constexpr ConstVectorView(typename Traits::elem_t const *elems, size_t n) + : ConstTensorView>(elems, n, 1) { } + + /** @brief Resizes the constant vector view's length. + * + * @param n Length. + * + * Lin assertion errors will be triggered if the requested length isn't + * possible given the vector view's traits. + * + * @sa internal::has_fixed_rows + * @sa internal::has_strictly_bounded_rows + */ + constexpr void resize(size_t n) { + resize(n, 1); + } +}; + +/** @brief Generic constant row vector view. + * + * @tparam T Constant row vector view element type. + * @tparam N Number of elements at compile time (i.e. number of rows). + * @tparam MN Maximum number of elements (i.e. maximum number of rows). + * + * The template parameters specify the row vector views's traits. The traits + * must qualify this type as a row vector. + * + * @sa internal::traits + * @sa internal::is_row_vector + * + * @ingroup VIEWS + */ +template +class ConstRowVectorView : public ConstTensorView> { + static_assert(is_row_vector>::value, + "Invalid ConstRowVectorView<...> parameters"); + + public: + /** @brief Traits information for this type. + * + * @sa internal::traits + */ + typedef traits> Traits; + + /** @brief Vector traits information for this type. + * + * @sa internal::vector_traits + */ + typedef vector_traits> VectorTraits; + + protected: + using ConstTensorView>::derived; + + public: + using ConstTensorView>::ConstTensorView; + using ConstTensorView>::rows; + using ConstTensorView>::cols; + using ConstTensorView>::size; + using ConstTensorView>::data; + using ConstTensorView>::eval; + using ConstTensorView>::resize; + using ConstTensorView>::operator=; + using ConstTensorView>::operator(); + + constexpr ConstRowVectorView() = default; + constexpr ConstRowVectorView(ConstRowVectorView const &) = default; + constexpr ConstRowVectorView(ConstRowVectorView &&) = default; + constexpr ConstRowVectorView &operator=(ConstRowVectorView const &) = default; + constexpr ConstRowVectorView &operator=(ConstRowVectorView &&) = default; + + /** @brief Constructs a vector view with the provided backing array and + * requested length. + * + * @param elems Constant element backing array. + * @param n Initial length. + * + * The backing array should be at least as large as the maximum length of the + * row vector (see internal::traits information). + * + * Lin assertion errors will be triggered if the requested length isn't + * possible given the row vector view's traits. + * + * @sa internal::has_fixed_cols + * @sa internal::has_strictly_bounded_cols + */ + constexpr ConstRowVectorView(typename Traits::elem_t const *elems, size_t n) + : ConstTensorView>(elems, 1, n) { } + + /** @brief Resizes the row vector view's length. + * + * @param n Length. + * + * Lin assertion errors will be triggered if the requested length isn't + * possible given the row vector view's traits. + * + * @sa internal::has_fixed_cols + * @sa internal::has_strictly_bounded_cols + */ + constexpr void resize(size_t n) { + resize(1, n); + } +}; + +template +struct _elem> { + typedef T type; +}; + +template +struct _dims> { + static constexpr size_t rows = N; + static constexpr size_t cols = 1; + static constexpr size_t max_rows = MN; + static constexpr size_t max_cols = 1; +}; + +template +struct _elem> { + typedef T type; +}; + +template +struct _dims> { + static constexpr size_t rows = 1; + static constexpr size_t cols = N; + static constexpr size_t max_rows = 1; + static constexpr size_t max_cols = MN; +}; +} // namespace internal +} // namespace lin + +#endif diff --git a/include/lin/views/matrix_view.hpp b/include/lin/views/matrix_view.hpp index 07b6ddc..a1bc067 100644 --- a/include/lin/views/matrix_view.hpp +++ b/include/lin/views/matrix_view.hpp @@ -11,10 +11,11 @@ #include "tensor_view.hpp" namespace lin { +namespace internal { /** @brief Generic matrix view. * - * @param T %Matrix view element type. + * @tparam T %Matrix view element type. * @tparam R Rows at compile time. * @tparam C Columns at compile time. * @tparam MR Maximum rows at compile time. @@ -25,12 +26,13 @@ namespace lin { * * @sa internal::traits * @sa internal::is_matrix + * @sa internal::TensorView * * @ingroup VIEWS */ template -class MatrixView : public internal::TensorView> { - static_assert(internal::is_matrix>::value, +class MatrixView : public TensorView> { + static_assert(is_matrix>::value, "Invalid MatrixView<...> parameters"); public: @@ -38,21 +40,21 @@ class MatrixView : public internal::TensorView> { * * @sa internal::traits */ - typedef internal::traits> Traits; + typedef traits> Traits; protected: - using internal::TensorView>::derived; + using TensorView>::derived; public: - using internal::TensorView>::TensorView; - using internal::TensorView>::rows; - using internal::TensorView>::cols; - using internal::TensorView>::size; - using internal::TensorView>::data; - using internal::TensorView>::eval; - using internal::TensorView>::resize; - using internal::TensorView>::operator=; - using internal::TensorView>::operator(); + using TensorView>::TensorView; + using TensorView>::rows; + using TensorView>::cols; + using TensorView>::size; + using TensorView>::data; + using TensorView>::eval; + using TensorView>::resize; + using TensorView>::operator=; + using TensorView>::operator(); constexpr MatrixView() = default; constexpr MatrixView(MatrixView const &) = default; @@ -61,61 +63,6 @@ class MatrixView : public internal::TensorView> { constexpr MatrixView &operator=(MatrixView &&) = default; }; -/** @weakgroup VIEWS - * @{ - */ - -/** @brief Generic float matrix view. - * - * @tparam R Rows at compile time. - * @tparam C Columns at compile time. - * @tparam MR Maximum rows. - * @tparam MC Maximum columns. - * - * @sa internal::traits - * @sa MatrixView - */ -template -using MatrixViewf = MatrixView; - -typedef MatrixViewf<2, 2> MatrixView2x2f; ///< Two by two float matrix view. -typedef MatrixViewf<3, 2> MatrixView3x2f; ///< Three by two float matrix view. -typedef MatrixViewf<4, 2> MatrixView4x2f; ///< Four by two float matrix view. -typedef MatrixViewf<2, 3> MatrixView2x3f; ///< Two by three float matrix view. -typedef MatrixViewf<3, 3> MatrixView3x3f; ///< Three by three float matrix view. -typedef MatrixViewf<4, 3> MatrixView4x3f; ///< Four by three float matrix view. -typedef MatrixViewf<2, 4> MatrixView2x4f; ///< Two by four float matrix view. -typedef MatrixViewf<3, 4> MatrixView3x4f; ///< Three by four float matrix view. -typedef MatrixViewf<4, 4> MatrixView4x4f; ///< Four by four float matrix view. - -/** @brief Generic double matrix view. - * - * @tparam R Rows at compile time. - * @tparam C Columns at compile time. - * @tparam MR Maximum rows. - * @tparam MC Maximum columns. - * - * @sa internal::traits - * @sa MatrixView - */ -template -using MatrixViewd = MatrixView; - -typedef MatrixViewd<2, 2> MatrixView2x2d; ///< Two by two double matrix view. -typedef MatrixViewd<3, 2> MatrixView3x2d; ///< Three by two double matrix view. -typedef MatrixViewd<4, 2> MatrixView4x2d; ///< Four by two double matrix view. -typedef MatrixViewd<2, 3> MatrixView2x3d; ///< Two by three double matrix view. -typedef MatrixViewd<3, 3> MatrixView3x3d; ///< Three by three double matrix view. -typedef MatrixViewd<4, 3> MatrixView4x3d; ///< Four by three double matrix view. -typedef MatrixViewd<2, 4> MatrixView2x4d; ///< Two by four double matrix view. -typedef MatrixViewd<3, 4> MatrixView3x4d; ///< Three by four double matrix view. -typedef MatrixViewd<4, 4> MatrixView4x4d; ///< Four by four double matrix view. - -/** @} - */ - -namespace internal { - template struct _elem> { typedef T type; diff --git a/include/lin/views/tensor_view.hpp b/include/lin/views/tensor_view.hpp index 0cf5fab..27eb700 100644 --- a/include/lin/views/tensor_view.hpp +++ b/include/lin/views/tensor_view.hpp @@ -16,19 +16,19 @@ namespace internal { * * @tparam D Derived type. * - * This allows users to interpret arbitary buffers as tensor objects. The user + * This allows users to interpret arbitrary buffers as tensor objects. The user * specified buffer is assumed to be at least as large as the tensor's maximum * size and elements are read and written to the buffer in row major order. * * @sa internal::Base - * @sa MatrixView - * @sa RowVectorView - * @sa VectorView + * @sa internal::MatrixView + * @sa internal::RowVectorView + * @sa internal::VectorView * * @ingroup VIEWS */ template -class TensorView : public internal::Base { +class TensorView : public Base { static_assert(has_valid_traits::value, "Derived types to Tensor<...> must have valid traits"); @@ -55,6 +55,7 @@ class TensorView : public internal::Base { using Base::data; using Base::eval; + constexpr TensorView() = delete; constexpr TensorView(TensorView const &) = default; constexpr TensorView(TensorView &&) = default; constexpr TensorView &operator=(TensorView const &) = default; @@ -80,11 +81,11 @@ class TensorView : public internal::Base { } /** @brief Constructs a new tensor tensor view with the provided backing - * array and requested dimesnions. + * array and requested dimensions. * - * @param elems + * @param elems Element backing array. * @param r Initial row dimension. - * @param c Initial column dimesnion. + * @param c Initial column dimension. * * The element backing array is a assumed to be in row major order. Elements * of the tensor initially hold whatever values were left in the backing diff --git a/include/lin/views/vector_view.hpp b/include/lin/views/vector_view.hpp index ba8d426..fcd289e 100644 --- a/include/lin/views/vector_view.hpp +++ b/include/lin/views/vector_view.hpp @@ -11,6 +11,7 @@ #include "tensor_view.hpp" namespace lin { +namespace internal { /** @brief Generic vector view. * @@ -27,8 +28,8 @@ namespace lin { * @ingroup VIEWS */ template -class VectorView : public internal::TensorView> { - static_assert(internal::is_col_vector>::value, +class VectorView : public TensorView> { + static_assert(is_col_vector>::value, "Invalid VectorView<...> parameters"); public: @@ -36,29 +37,29 @@ class VectorView : public internal::TensorView> { * * @sa internal::traits */ - typedef internal::traits> Traits; + typedef traits> Traits; /** @brief Vector traits information for this type. * * @sa internal::vector_traits */ - typedef internal::vector_traits> VectorTraits; + typedef vector_traits> VectorTraits; protected: - using internal::TensorView>::derived; + using TensorView>::derived; public: - using internal::TensorView>::TensorView; - using internal::TensorView>::rows; - using internal::TensorView>::cols; - using internal::TensorView>::size; - using internal::TensorView>::data; - using internal::TensorView>::eval; - using internal::TensorView>::resize; - using internal::TensorView>::operator=; - using internal::TensorView>::operator(); - - constexpr VectorView() = default; + using TensorView>::TensorView; + using TensorView>::rows; + using TensorView>::cols; + using TensorView>::size; + using TensorView>::data; + using TensorView>::eval; + using TensorView>::resize; + using TensorView>::operator=; + using TensorView>::operator(); + + constexpr VectorView() = delete; constexpr VectorView(VectorView const &) = default; constexpr VectorView(VectorView &&) = default; constexpr VectorView &operator=(VectorView const &) = default; @@ -80,7 +81,7 @@ class VectorView : public internal::TensorView> { * @sa internal::has_strictly_bounded_rows */ constexpr VectorView(typename Traits::elem_t *elems, size_t n) - : internal::TensorView>(elems, n, 1) { } + : TensorView>(elems, n, 1) { } /** @brief Resizes the vector view's length. * @@ -99,7 +100,7 @@ class VectorView : public internal::TensorView> { /** @brief Generic row vector view. * - * @tparam T Row vector element type. + * @tparam T Row vector view element type. * @tparam N Number of elements at compile time (i.e. number of rows). * @tparam MN Maximum number of elements (i.e. maximum number of rows). * @@ -112,8 +113,8 @@ class VectorView : public internal::TensorView> { * @ingroup VIEWS */ template -class RowVectorView : public internal::TensorView> { - static_assert(internal::is_row_vector>::value, +class RowVectorView : public TensorView> { + static_assert(is_row_vector>::value, "Invalid RowVectorView<...> parameters"); public: @@ -121,27 +122,27 @@ class RowVectorView : public internal::TensorView> { * * @sa internal::traits */ - typedef internal::traits> Traits; + typedef traits> Traits; /** @brief Vector traits information for this type. * * @sa internal::vector_traits */ - typedef internal::vector_traits> VectorTraits; + typedef vector_traits> VectorTraits; protected: - using internal::TensorView>::derived; + using TensorView>::derived; public: - using internal::TensorView>::TensorView; - using internal::TensorView>::rows; - using internal::TensorView>::cols; - using internal::TensorView>::size; - using internal::TensorView>::data; - using internal::TensorView>::eval; - using internal::TensorView>::resize; - using internal::TensorView>::operator=; - using internal::TensorView>::operator(); + using TensorView>::TensorView; + using TensorView>::rows; + using TensorView>::cols; + using TensorView>::size; + using TensorView>::data; + using TensorView>::eval; + using TensorView>::resize; + using TensorView>::operator=; + using TensorView>::operator(); constexpr RowVectorView() = default; constexpr RowVectorView(RowVectorView const &) = default; @@ -165,7 +166,7 @@ class RowVectorView : public internal::TensorView> { * @sa internal::has_strictly_bounded_cols */ constexpr RowVectorView(typename Traits::elem_t *elems, size_t n) - : internal::TensorView>(elems, 1, n) { } + : TensorView>(elems, 1, n) { } /** @brief Resizes the row vector view's length. * @@ -182,76 +183,6 @@ class RowVectorView : public internal::TensorView> { } }; -/** @weakgroup VIEWS - * @{ - */ - - -/** @brief Generic float vector view. - * - * @tparam N Length at compile time - * @tparam MN Max length. - * - * @sa internal::traits - * @sa VectorView - */ -template -using VectorViewf = VectorView; - -typedef VectorViewf<2> VectorView2f; ///< Two dimensional float vector view. -typedef VectorViewf<3> VectorView3f; ///< Three dimensional float vector view. -typedef VectorViewf<4> VectorView4f; ///< Four dimensional float vector view. - -/** @brief Generic double vector view. - * - * @tparam N Length at compile time - * @tparam MN Max length. - * - * @sa internal::traits - * @sa VectorView - */ -template -using VectorViewd = VectorView; - -typedef VectorViewd<2> VectorView2d; ///< Two dimensional double vector view. -typedef VectorViewd<3> VectorView3d; ///< Three dimensional double vector view. -typedef VectorViewd<4> VectorView4d; ///< Four dimensional double vector view. - -/** @brief Generic float row vector view. - * - * @tparam N Length at compile time - * @tparam MN Max length. - * - * @sa internal::traits - * @sa RowVectorView - */ -template -using RowVectorViewf = RowVectorView; - -typedef RowVectorViewf<2> RowVectorView2f; ///< Two dimensional float row vector view. -typedef RowVectorViewf<3> RowVectorView3f; ///< Three dimensional float row vector view. -typedef RowVectorViewf<4> RowVectorView4f; ///< Four dimensional float row vector view. - -/** @brief Generic double row vector view. - * - * @tparam N Length at compile time - * @tparam MN Max length. - * - * @sa internal::traits - * @sa RowVectorView - */ -template -using RowVectorViewd = RowVectorView; - -typedef RowVectorViewd<2> RowVectorView2d; ///< Two dimensional double row vector view. -typedef RowVectorViewd<3> RowVectorView3d; ///< Three dimensional double row vector view. -typedef RowVectorViewd<4> RowVectorView4d; ///< Four dimensional double row vector view. - -/** @} - */ - -namespace internal { - template struct _elem> { typedef T type; diff --git a/library.json b/library.json index e5ef406..5b6eb05 100644 --- a/library.json +++ b/library.json @@ -3,10 +3,11 @@ "version": "0.0.1", "license": "MIT", "build": { - "includeDir": "include" + "includeDir": "include", + "libArchive": false }, "repository": { "type": "git", "url": "https://github.com/kkrol27/lin.git" } -} \ No newline at end of file +} diff --git a/setup.py b/setup.py index 28dea9d..dff5a0a 100644 --- a/setup.py +++ b/setup.py @@ -52,7 +52,7 @@ def has_flag(compiler, flagname): def cpp_flag(compiler): - for flag in ['-std=c++17', '-std=c++14']: + for flag in ['-std=c++14']: if has_flag(compiler, flag): return flag @@ -82,8 +82,8 @@ def build_extensions(self): opts.append(cpp_flag(self.compiler)) if has_flag(self.compiler, '-fvisibility=hidden'): opts.append('-fvisibility=hidden') - if has_flag(self.compiler, '-Werror'): - opts.append('-Werror') + #if has_flag(self.compiler, '-Werror'): + # opts.append('-Werror') for ext in self.extensions: ext.define_macros = [('VERSION_INFO', '"{}"'.format(self.distribution.get_version()))] @@ -468,7 +468,7 @@ def __gen_bops(cxx_class): description='Simple python wrapper for lin matrix and vector types.', long_description='', ext_modules=ext_modules, - setup_requires=['pybind11>=2.5.0'], + setup_requires=['pybind11>=2.6.0'], install_requires=['numpy'], cmdclass={'build_ext': BuildExt}, zip_safe=False, diff --git a/test/core/operations_tensor_operations_test.cpp b/test/core/operations_tensor_operations_test.cpp index 83100c7..4386173 100644 --- a/test/core/operations_tensor_operations_test.cpp +++ b/test/core/operations_tensor_operations_test.cpp @@ -178,14 +178,20 @@ TEST(CoreOperationsTensorOperations, Sum) { ASSERT_FLOAT_EQ(2.0f, lin::sum(A)); } -TEST(CoreOperationsTensorOperations, Transpose) { +TEST(CoreOperationsTensorOperations, MappingTranspose) { lin::Matrix2x2f A({0.0f, 1.0f, 2.0f, 3.0f}); - auto const transpose_A = lin::transpose(A); + auto transpose_A = lin::transpose(A); ASSERT_FLOAT_EQ(0.0f, transpose_A(0, 0)); ASSERT_FLOAT_EQ(2.0f, transpose_A(0, 1)); ASSERT_FLOAT_EQ(1.0f, transpose_A(1, 0)); ASSERT_FLOAT_EQ(3.0f, transpose_A(1, 1)); + transpose_A = { 1.0f, 2.0f, 3.0f, 4.0f }; + ASSERT_FLOAT_EQ(1.0f, A(0, 0)); + ASSERT_FLOAT_EQ(3.0f, A(0, 1)); + ASSERT_FLOAT_EQ(2.0f, A(1, 0)); + ASSERT_FLOAT_EQ(4.0f, A(1, 1)); + lin::Matrixf<0, 0, 4, 4> B(3, 2); auto const transpose_B = lin::transpose(B); ASSERT_EQ(2, transpose_B.rows()); @@ -198,3 +204,24 @@ TEST(CoreOperationsTensorOperations, Transpose) { ASSERT_EQ(2, transpose_C.cols()); ASSERT_EQ(8, transpose_C.size()); } + +TEST(CoreOperationsTensorOperations, StreamTranspose) { + lin::Matrix2x2f const A({0.0f, 1.0f, 2.0f, 3.0f}); + auto const transpose_A = lin::transpose(A); + ASSERT_FLOAT_EQ(0.0f, transpose_A(0, 0)); + ASSERT_FLOAT_EQ(2.0f, transpose_A(0, 1)); + ASSERT_FLOAT_EQ(1.0f, transpose_A(1, 0)); + ASSERT_FLOAT_EQ(3.0f, transpose_A(1, 1)); + + lin::Matrixf<0, 0, 4, 4> const B(3, 2); + auto const transpose_B = lin::transpose(B); + ASSERT_EQ(2, transpose_B.rows()); + ASSERT_EQ(3, transpose_B.cols()); + ASSERT_EQ(6, transpose_B.size()); + + lin::Matrix2x4f const C; + auto const transpose_C = lin::transpose(C); + ASSERT_EQ(4, transpose_C.rows()); + ASSERT_EQ(2, transpose_C.cols()); + ASSERT_EQ(8, transpose_C.size()); +} diff --git a/test/generators/diagonal_test.cpp b/test/generators/diagonal_test.cpp new file mode 100644 index 0000000..5570a4a --- /dev/null +++ b/test/generators/diagonal_test.cpp @@ -0,0 +1,40 @@ +/** @file test/generators/diagonal_test.cpp + * @author Kyle Krol */ + +#include +#include + +#include + +#include +#include + +TEST(GeneratorsDiagonal, Diagonal) { + lin::Vector2f a = { + 1.0f, + 2.0f + }; + + auto const A = lin::diag(a); + static_assert(lin::internal::have_same_traits, lin::Matrix2x2f>::value, ""); + ASSERT_FLOAT_EQ(1.0f, A(0, 0)); + ASSERT_FLOAT_EQ(0.0f, A(0, 1)); + ASSERT_FLOAT_EQ(0.0f, A(1, 0)); + ASSERT_FLOAT_EQ(2.0f, A(1, 1)); + ASSERT_EQ(2, A.rows()); + ASSERT_EQ(2, A.cols()); + + lin::Vectorf<0, 3> b(2, { + 1.0f, + 2.0f + }); + + auto const B = lin::diag(b); + static_assert(lin::internal::have_same_traits, lin::Matrixf<0, 0, 3, 3>>::value, ""); + ASSERT_FLOAT_EQ(1.0f, B(0, 0)); + ASSERT_FLOAT_EQ(0.0f, B(0, 1)); + ASSERT_FLOAT_EQ(0.0f, B(1, 0)); + ASSERT_FLOAT_EQ(2.0f, B(1, 1)); + ASSERT_EQ(2, B.rows()); + ASSERT_EQ(2, B.cols()); +} diff --git a/test/generators/randoms_test.cpp b/test/generators/randoms_test.cpp index 678f72b..55cd75b 100644 --- a/test/generators/randoms_test.cpp +++ b/test/generators/randoms_test.cpp @@ -1,6 +1,7 @@ /** @file test/generators/randoms_test.cpp - * @author Kyle Krol */ - + * @author Kyle Krol + * @author Shihao Cao +*/ #include #include @@ -11,12 +12,32 @@ TEST(GeneratorsRandoms, RandomsGenerator) { lin::internal::RandomsGenerator rand; for (lin::size_t i = 0; i < 10000; i++) { - double x = rand.next(); + double x = rand.rand(); ASSERT_LE(x, 1.0); ASSERT_GT(x, 0.0); } } +TEST(GeneratorsRandoms, GaussianRandomsGenerator) { + lin::internal::RandomsGenerator rand; + double mean = 0.0L; + double std = 0.0L; + uint N = 10000000; + for (lin::size_t i = 0; i < N; i++) { + double x = rand.gaussian(); + mean += x; + std += x*x; + } + std = std::sqrt(std/N); + mean = mean/N; + + ASSERT_LE(mean,0.01); + ASSERT_GT(mean,-0.01); + + ASSERT_LE(std,1.01); + ASSERT_GT(std,0.99); +} + TEST(GeneratorsRandoms, Rands) { lin::internal::RandomsGenerator rand; auto const A = lin::rands>(rand, 4, 3); @@ -25,3 +46,37 @@ TEST(GeneratorsRandoms, Rands) { ASSERT_EQ( 3, A.cols()); ASSERT_EQ(12, A.size()); } + +TEST(GeneratorRandoms, GaussianRandsShape){ + lin::internal::RandomsGenerator rand; + auto const A = lin::gaussians>(rand, 4, 3); + static_assert(std::is_same, lin::Matrixd<0, 3, 5, 3>>::value, ""); + ASSERT_EQ( 4, A.rows()); + ASSERT_EQ( 3, A.cols()); + ASSERT_EQ(12, A.size()); +} + +TEST(GeneratorsRandoms, GaussianRands){ + lin::internal::RandomsGenerator rand; + double mean = 0.0; + double std = 0.0; + uint L = 100000; + uint N = L*15; + for(uint j = 0; j>(rand, 3, 5); + // std::cout << A; + for(lin::size_t i = 0; i < A.size(); i++){ + mean += A(i); + std += A(i)*A(i); + } + } + + std = std::sqrt(std/N); + mean = mean/N; + + ASSERT_LE(mean,0.01); + ASSERT_GT(mean,-0.01); + + ASSERT_LE(std,1.01); + ASSERT_GT(std,0.99); +} \ No newline at end of file diff --git a/test/references/mapping_reference_test.cpp b/test/references/mapping_reference_test.cpp index 09dfa63..185c732 100644 --- a/test/references/mapping_reference_test.cpp +++ b/test/references/mapping_reference_test.cpp @@ -1,70 +1,150 @@ -/** @file test/generators/mapping_reference_test.cpp - * @author Kyle Krol */ +/** @file test/references/mapping_reference_test.cpp + * @author Kyle Krol + */ #include -#include +#include #include #include -TEST(MappingReference, Reference) { - lin::Matrixf<3, 3> A({ +TEST(MappingReference, MatrixMappingReference) { + lin::Matrix3x3f A = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f - }); - lin::Matrixf<2, 2> B({ + }; + lin::Matrix2x2f B = { 3.0f, 4.0f, 6.0f, 7.0f - }); - auto C = lin::ref<2, 2>(A, 1, 0); + }; + + auto C = lin::ref(A, 1, 0); + static_assert(lin::internal::have_same_traits::value, ""); ASSERT_FLOAT_EQ(0.0f, lin::fro(B - C)); ASSERT_EQ(2, C.rows()); ASSERT_EQ(2, C.cols()); - ASSERT_EQ(4, C.size()); - lin::Matrixf<0, 0, 5, 5> D(2, 3, { + lin::Matrixf<0, 0, 5, 5> D(2, 3); + D = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f - }); - lin::Matrixf<0, 0, 5, 5> E(2, 2, { + }; + lin::Matrixf<0, 0, 5, 5> E(2, 2); + E = { 1.0f, 2.0f, 4.0f, 5.0f - }); - auto F = lin::ref<0, 0, 5, 5>(D, 0, 1, 2, 2); + }; + + auto F = lin::ref>(D, 0, 1, 2, 2); + static_assert(lin::internal::have_same_traits>::value, ""); ASSERT_FLOAT_EQ(0.0f, lin::fro(E - F)); ASSERT_EQ(2, F.rows()); ASSERT_EQ(2, F.cols()); - ASSERT_EQ(4, F.size()); + + F(0, 0) = 10.0f; + ASSERT_FLOAT_EQ(10.0f, D(0, 1)); } -TEST(MappingReference, ReferenceRow) { - lin::Matrixf<0, 0, 4, 4> A(3, 2, { - 0.0f, 1.0f, - 2.0f, 3.0f, - 4.0f, 5.0f - }); - auto a = lin::ref_row(A, 1); - ASSERT_FLOAT_EQ(0.0f, lin::fro(a - lin::RowVectorf<0, 4>(2, {2.0f, 3.0f}))); - ASSERT_EQ(1, a.rows()); - ASSERT_EQ(2, a.cols()); - ASSERT_EQ(2, a.size()); - a(0) = 0.0f; - ASSERT_FLOAT_EQ(0.0f, A(1, 0)); +TEST(MappingReference, VectorMappingReference) { + lin::Matrix3x3f A = { + 0.0f, 1.0f, 2.0f, + 3.0f, 4.0f, 5.0f, + 6.0f, 7.0f, 8.0f + }; + lin::Vector3f a = { + 1.0f, + 4.0f, + 7.0f + }; + + auto b = lin::ref(A, 0, 1); + static_assert(lin::internal::have_same_traits::value, ""); + ASSERT_FLOAT_EQ(0.0f, lin::fro(a - b)); + ASSERT_EQ(3, b.rows()); + ASSERT_EQ(1, b.cols()); + + lin::Vectorf<0, 3> c(2); + c = { + 4.0f, + 7.0f + }; + + auto d = lin::ref>(A, 1, 1, 2); + static_assert(lin::internal::have_same_traits>::value, ""); + ASSERT_FLOAT_EQ(0.0f, lin::fro(c - d)); + ASSERT_EQ(2, d.rows()); + ASSERT_EQ(1, d.cols()); + + d(0) = 10.0f; + ASSERT_FLOAT_EQ(10.0f, A(1, 1)); +} + +TEST(MappingReference, RowVectorMappingReference) { + lin::Matrix3x3f A = { + 0.0f, 1.0f, 2.0f, + 3.0f, 4.0f, 5.0f, + 6.0f, 7.0f, 8.0f + }; + lin::RowVector3f a = { + 3.0f, 4.0f, 5.0f + }; + + auto b = lin::ref(A, 1, 0); + static_assert(lin::internal::have_same_traits::value, ""); + ASSERT_FLOAT_EQ(0.0f, lin::fro(a - b)); + ASSERT_EQ(1, b.rows()); + ASSERT_EQ(3, b.cols()); + + lin::RowVectorf<0, 3> c(2); + c = { + 7.0f, 8.0f + }; + + auto d = lin::ref>(A, 2, 1, 2); + static_assert(lin::internal::have_same_traits>::value, ""); + ASSERT_FLOAT_EQ(0.0f, lin::fro(c - d)); + ASSERT_EQ(1, d.rows()); + ASSERT_EQ(2, d.cols()); + + d(1) = 10.0f; + ASSERT_FLOAT_EQ(10.0f, A(2, 2)); } -TEST(MappingReference, ReferenceColumn) { - lin::Matrixf<0, 0, 4, 4> A(3, 2, { +TEST(MappingReference, DiagonalMappingReference) { + lin::Matrix3x3f A = { + 0.0f, 1.0f, 2.0f, + 3.0f, 4.0f, 5.0f, + 6.0f, 7.0f, 8.0f + }; + lin::Vector3f a = { + 0.0f, + 4.0f, + 8.0f + }; + + auto b = lin::diag(A); + static_assert(lin::internal::have_same_traits::value, ""); + ASSERT_FLOAT_EQ(0.0f, lin::fro(a - b)); + ASSERT_EQ(3, b.rows()); + ASSERT_EQ(1, b.cols()); + + lin::Matrixf<0, 0, 5, 5> B(2, 2, { 0.0f, 1.0f, - 2.0f, 3.0f, - 4.0f, 5.0f + 2.0f, 3.0f + }); + lin::Vectorf<0, 5> c(2, { + 0.0f, + 3.0f }); - auto a = lin::ref_col(A, 1); - ASSERT_FLOAT_EQ(0.0f, lin::fro(a - lin::Vectorf<0, 4>(3, {1.0f, 3.0f, 5.0f}))); - ASSERT_EQ(3, a.rows()); - ASSERT_EQ(1, a.cols()); - ASSERT_EQ(3, a.size()); - a(2) = 4.0f; - ASSERT_FLOAT_EQ(4.0f, A(2, 1)); + + auto d = lin::diag(B); + static_assert(lin::internal::have_same_traits>::value, ""); + ASSERT_FLOAT_EQ(0.0f, lin::fro(c - d)); + ASSERT_EQ(2, d.rows()); + ASSERT_EQ(1, d.cols()); + + d(1) = 4.0f; + ASSERT_FLOAT_EQ(4.0f, B(1, 1)); } diff --git a/test/references/stream_reference_test.cpp b/test/references/stream_reference_test.cpp index 1b37615..fb3aaa4 100644 --- a/test/references/stream_reference_test.cpp +++ b/test/references/stream_reference_test.cpp @@ -1,66 +1,134 @@ -/** @file test/generators/randoms_test.cpp - * @author Kyle Krol */ +/** @file test/references/stream_reference_test.cpp + * @author Kyle Krol + */ #include -#include +#include #include #include -TEST(StreamReference, Reference) { - lin::Matrixf<3, 3> A({ +TEST(StreamReference, MatrixStreamReference) { + lin::Matrix3x3f const A = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f - }); - lin::Matrixf<2, 2> B({ + }; + lin::Matrix2x2f const B = { 3.0f, 4.0f, 6.0f, 7.0f - }); - auto const C = lin::ref<2, 2>(A, 1, 0); + }; + + auto const C = lin::ref(A, 1, 0); + static_assert(lin::internal::have_same_traits, lin::Matrix2x2f>::value, ""); ASSERT_FLOAT_EQ(0.0f, lin::fro(B - C)); ASSERT_EQ(2, C.rows()); ASSERT_EQ(2, C.cols()); - ASSERT_EQ(4, C.size()); - lin::Matrixf<0, 0, 5, 5> D(2, 3, { + lin::Matrixf<0, 0, 5, 5> const D(2, 3, { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }); - lin::Matrixf<0, 0, 5, 5> E(2, 2, { + lin::Matrixf<0, 0, 5, 5> const E(2, 2, { 1.0f, 2.0f, 4.0f, 5.0f }); - auto const F = lin::ref<0, 0, 5, 5>(D, 0, 1, 2, 2); + + auto const F = lin::ref>(D, 0, 1, 2, 2); + static_assert(lin::internal::have_same_traits, lin::Matrixf<0, 0, 5, 5>>::value, ""); ASSERT_FLOAT_EQ(0.0f, lin::fro(E - F)); ASSERT_EQ(2, F.rows()); ASSERT_EQ(2, F.cols()); - ASSERT_EQ(4, F.size()); } -TEST(StreamReference, ReferenceRow) { - lin::Matrixf<0, 0, 4, 4> A(3, 2, { - 0.0f, 1.0f, - 2.0f, 3.0f, - 4.0f, 5.0f +TEST(StreamReference, VectorStreamReference) { + lin::Matrix3x3f const A = { + 0.0f, 1.0f, 2.0f, + 3.0f, 4.0f, 5.0f, + 6.0f, 7.0f, 8.0f + }; + lin::Vector3f const a = { + 1.0f, + 4.0f, + 7.0f + }; + + auto const b = lin::ref(A, 0, 1); + static_assert(lin::internal::have_same_traits, lin::Vector3f>::value, ""); + ASSERT_FLOAT_EQ(0.0f, lin::fro(a - b)); + ASSERT_EQ(3, b.rows()); + ASSERT_EQ(1, b.cols()); + + lin::Vectorf<0, 3> const c(2, { + 4.0f, + 7.0f + }); + + auto const d = lin::ref>(A, 1, 1, 2); + static_assert(lin::internal::have_same_traits, lin::Vectorf<0, 3>>::value, ""); + ASSERT_FLOAT_EQ(0.0f, lin::fro(c - d)); + ASSERT_EQ(2, d.rows()); + ASSERT_EQ(1, d.cols()); +} + +TEST(StreamReference, RowVectorStreamReference) { + lin::Matrix3x3f const A = { + 0.0f, 1.0f, 2.0f, + 3.0f, 4.0f, 5.0f, + 6.0f, 7.0f, 8.0f + }; + lin::RowVector3f const a = { + 3.0f, 4.0f, 5.0f + }; + + auto const b = lin::ref(A, 1, 0); + static_assert(lin::internal::have_same_traits, lin::RowVector3f>::value, ""); + ASSERT_FLOAT_EQ(0.0f, lin::fro(a - b)); + ASSERT_EQ(1, b.rows()); + ASSERT_EQ(3, b.cols()); + + lin::RowVectorf<0, 3> const c(2, { + 7.0f, 8.0f }); - auto const a = lin::ref_row(A, 1); - ASSERT_FLOAT_EQ(0.0f, lin::fro(a - lin::RowVectorf<0, 4>(2, {2.0f, 3.0f}))); - ASSERT_EQ(1, a.rows()); - ASSERT_EQ(2, a.cols()); - ASSERT_EQ(2, a.size()); + + auto const d = lin::ref>(A, 2, 1, 2); + static_assert(lin::internal::have_same_traits, lin::RowVectorf<0, 3>>::value, ""); + ASSERT_FLOAT_EQ(0.0f, lin::fro(c - d)); + ASSERT_EQ(1, d.rows()); + ASSERT_EQ(2, d.cols()); } -TEST(StreamReference, ReferenceColumn) { - lin::Matrixf<0, 0, 4, 4> A(3, 2, { +TEST(StreamReference, StreamMappingReference) { + lin::Matrix3x3f const A = { + 0.0f, 1.0f, 2.0f, + 3.0f, 4.0f, 5.0f, + 6.0f, 7.0f, 8.0f + }; + lin::Vector3f const a = { + 0.0f, + 4.0f, + 8.0f + }; + + auto const b = lin::diag(A); + static_assert(lin::internal::have_same_traits, lin::Vector3f>::value, ""); + ASSERT_FLOAT_EQ(0.0f, lin::fro(a - b)); + ASSERT_EQ(3, b.rows()); + ASSERT_EQ(1, b.cols()); + + lin::Matrixf<0, 0, 5, 5> const B(2, 2, { 0.0f, 1.0f, - 2.0f, 3.0f, - 4.0f, 5.0f + 2.0f, 3.0f + }); + lin::Vectorf<0, 5> const c(2, { + 0.0f, + 3.0f }); - auto const a = lin::ref_col(A, 1); - ASSERT_FLOAT_EQ(0.0f, lin::fro(a - lin::Vectorf<0, 4>(3, {1.0f, 3.0f, 5.0f}))); - ASSERT_EQ(3, a.rows()); - ASSERT_EQ(1, a.cols()); - ASSERT_EQ(3, a.size()); + + auto const d = lin::diag(B); + static_assert(lin::internal::have_same_traits, lin::Vectorf<0, 5>>::value, ""); + ASSERT_FLOAT_EQ(0.0f, lin::fro(c - d)); + ASSERT_EQ(2, d.rows()); + ASSERT_EQ(1, d.cols()); } diff --git a/test/views/matrix_views_test.cpp b/test/views/matrix_views_test.cpp index 43520a7..91fca54 100644 --- a/test/views/matrix_views_test.cpp +++ b/test/views/matrix_views_test.cpp @@ -1,10 +1,12 @@ // vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab #include -#include +#include #include +#include + TEST(MatrixViews, FixedSizeMatrixView) { float buf[9] = { 1.0f, 2.0f, 3.0f, @@ -12,8 +14,9 @@ TEST(MatrixViews, FixedSizeMatrixView) { 7.0f, 8.0f, 9.0f }; - lin::MatrixView3x3f A(buf); - static_assert(lin::internal::have_same_traits::value, ""); + auto A = lin::view(buf); + static_assert(std::is_same>::value, ""); + static_assert(lin::internal::have_same_traits::value, ""); ASSERT_EQ(A.rows(), 3); ASSERT_EQ(A.cols(), 3); @@ -34,6 +37,34 @@ TEST(MatrixViews, FixedSizeMatrixView) { ASSERT_EQ(A.data(), buf); } +TEST(MatrixViews, FixedSizeConstMatrixView) { + float const buf[9] = { + 1.0f, 2.0f, 3.0f, + 4.0f, 5.0f, 6.0f, + 7.0f, 8.0f, 9.0f + }; + + auto A = lin::view(buf); + static_assert(std::is_same>::value, ""); + static_assert(lin::internal::have_same_traits::value, ""); + + ASSERT_EQ(A.rows(), 3); + ASSERT_EQ(A.cols(), 3); + + ASSERT_FLOAT_EQ(A(0, 0), 1.0f); + ASSERT_FLOAT_EQ(A(0, 1), 2.0f); + ASSERT_FLOAT_EQ(A(0, 2), 3.0f); + ASSERT_FLOAT_EQ(A(1, 0), 4.0f); + ASSERT_FLOAT_EQ(A(1, 1), 5.0f); + ASSERT_FLOAT_EQ(A(1, 2), 6.0f); + ASSERT_FLOAT_EQ(A(2, 0), 7.0f); + ASSERT_FLOAT_EQ(A(2, 1), 8.0f); + ASSERT_FLOAT_EQ(A(2, 2), 9.0f); + + // Test the correct buffer is returned + ASSERT_EQ(A.data(), buf); +} + TEST(MatrixViews, VariableSizeMatrixView) { float buf[9] = { 1.0f, 2.0f, 3.0f, @@ -41,8 +72,9 @@ TEST(MatrixViews, VariableSizeMatrixView) { 7.0f, 8.0f, 9.0f }; - lin::MatrixViewf<0, 0, 3, 3> A(buf, 2, 2); - static_assert(lin::internal::have_same_traits, lin::MatrixViewf<0, 0, 3, 3>>::value, ""); + auto A = lin::view>(buf, 2, 2); + static_assert(std::is_same>::value, ""); + static_assert(lin::internal::have_same_traits>::value, ""); ASSERT_EQ(A.rows(), 2); ASSERT_EQ(A.cols(), 2); @@ -64,3 +96,37 @@ TEST(MatrixViews, VariableSizeMatrixView) { ASSERT_EQ(A.data(), buf); } + +TEST(MatrixViews, VariableSizeConstMatrixView) { + float const buf[9] = { + 1.0f, 2.0f, 3.0f, + 4.0f, 5.0f, 6.0f, + 7.0f, 8.0f, 9.0f + }; + + auto A = lin::view>(buf, 2, 2); + static_assert(std::is_same>::value, ""); + static_assert(lin::internal::have_same_traits>::value, ""); + + ASSERT_EQ(A.rows(), 2); + ASSERT_EQ(A.cols(), 2); + + ASSERT_FLOAT_EQ(A(0, 0), 1.0f); + ASSERT_FLOAT_EQ(A(0, 1), 2.0f); + ASSERT_FLOAT_EQ(A(1, 0), 3.0f); + ASSERT_FLOAT_EQ(A(1, 1), 4.0f); + + A.resize(3, 2); + ASSERT_EQ(A.rows(), 3); + ASSERT_EQ(A.cols(), 2); + + ASSERT_FLOAT_EQ(A(0, 0), 1.0f); + ASSERT_FLOAT_EQ(A(0, 1), 2.0f); + ASSERT_FLOAT_EQ(A(1, 0), 3.0f); + ASSERT_FLOAT_EQ(A(1, 1), 4.0f); + ASSERT_FLOAT_EQ(A(2, 0), 5.0f); + ASSERT_FLOAT_EQ(A(2, 1), 6.0f); + + // Test the correct buffer is returned + ASSERT_EQ(A.data(), buf); +} diff --git a/test/views/vector_views_test.cpp b/test/views/vector_views_test.cpp index 466c2ab..ede379e 100644 --- a/test/views/vector_views_test.cpp +++ b/test/views/vector_views_test.cpp @@ -1,22 +1,20 @@ // vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab #include -#include +#include #include -TEST(VectorViews, FixedSizeVectorView) { - float buf[3]; +#include - buf[0] = 1.0f; - buf[1] = 2.0f; - buf[2] = 3.0f; - lin::VectorView3f a(buf); +TEST(VectorViews, FixedSizeVectorView) { + float buf[3] = {1.0f, 2.0f, 3.0f}; - // Check traits are correct - static_assert(lin::internal::have_same_traits::value, ""); + auto a = lin::view(buf); + static_assert(std::is_same>::value, ""); + static_assert(lin::internal::have_same_traits::value, ""); - // Check dimesnions + // Check dimensions ASSERT_EQ(a.rows(), 3); ASSERT_EQ(a.cols(), 1); @@ -33,18 +31,34 @@ TEST(VectorViews, FixedSizeVectorView) { ASSERT_EQ(a.data(), buf); } -TEST(VectorViews, FixedSizeRowVectorView) { - float buf[3]; +TEST(VectorViews, FixedSizeConstVectorView) { + float const buf[3] = {1.0f, 2.0f, 3.0f}; + + auto a = lin::view(buf); + static_assert(std::is_same>::value, ""); + static_assert(lin::internal::have_same_traits::value, ""); + + // Check dimensions + ASSERT_EQ(a.rows(), 3); + ASSERT_EQ(a.cols(), 1); + + // Check elements are correct + ASSERT_FLOAT_EQ(a(0), 1.0f); + ASSERT_FLOAT_EQ(a(1), 2.0f); + ASSERT_FLOAT_EQ(a(2), 3.0f); - buf[0] = 1.0f; - buf[1] = 2.0f; - buf[2] = 3.0f; - lin::RowVectorView3f a(buf); + // Test the correct buffer is returned + ASSERT_EQ(a.data(), buf); +} + +TEST(VectorViews, FixedSizeRowVectorView) { + float buf[3] = {1.0f, 2.0f, 3.0f}; - // Check traits are correct - static_assert(lin::internal::have_same_traits::value, ""); + auto a = lin::view(buf); + static_assert(std::is_same>::value, ""); + static_assert(lin::internal::have_same_traits::value, ""); - // Check dimesnions + // Check dimensions ASSERT_EQ(a.rows(), 1); ASSERT_EQ(a.cols(), 3); @@ -56,21 +70,39 @@ TEST(VectorViews, FixedSizeRowVectorView) { // Test changes are reflected in the original buffer a(1) = 4.0f; ASSERT_FLOAT_EQ(buf[1], 4.0f); + + // Test the correct buffer is returned + ASSERT_EQ(a.data(), buf); } -TEST(VectorViews, VariableSizeVectorView) { - double buf[6]; +TEST(VectorViews, FixedSizeConstRowVectorView) { + float const buf[3] = {1.0f, 2.0f, 3.0f}; + + auto a = lin::view(buf); + static_assert(std::is_same>::value, ""); + static_assert(lin::internal::have_same_traits::value, ""); + + // Check dimensions + ASSERT_EQ(a.rows(), 1); + ASSERT_EQ(a.cols(), 3); + + // Check elements are correct + ASSERT_FLOAT_EQ(a(0), 1.0f); + ASSERT_FLOAT_EQ(a(1), 2.0f); + ASSERT_FLOAT_EQ(a(2), 3.0f); - buf[0] = 1.0; - buf[1] = 2.0; - buf[2] = 3.0; - buf[3] = 4.0; - lin::VectorViewd<0, 6> a(buf, 4); + // Test the correct buffer is returned + ASSERT_EQ(a.data(), buf); +} + +TEST(VectorViews, VariableSizeVectorView) { + double buf[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; - // Check traits are correct - static_assert(lin::internal::have_same_traits, lin::VectorViewd<0, 6>>::value, ""); + auto a = lin::view>(buf, 4); + static_assert(std::is_same>::value, ""); + static_assert(lin::internal::have_same_traits>::value, ""); - // Check dimesnions + // Check dimensions ASSERT_EQ(a.rows(), 4); ASSERT_EQ(a.cols(), 1); @@ -94,17 +126,40 @@ TEST(VectorViews, VariableSizeVectorView) { ASSERT_EQ(a.data(), buf); } -TEST(VectorViews, VariableSizeRowVectorView) { - double buf[6]; +TEST(VectorViews, VariableSizeConstVectorView) { + double const buf[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; - buf[0] = 1.0; - buf[1] = 2.0; - lin::RowVectorViewd<0, 6> a(buf, 2); + auto a = lin::view>(buf, 4); + static_assert(std::is_same>::value, ""); + static_assert(lin::internal::have_same_traits>::value, ""); - // Check traits are correct - static_assert(lin::internal::have_same_traits, lin::RowVectorViewd<0, 6>>::value, ""); + // Check dimensions + ASSERT_EQ(a.rows(), 4); + ASSERT_EQ(a.cols(), 1); + + // Check elements are correct + ASSERT_DOUBLE_EQ(a(0), 1.0); + ASSERT_DOUBLE_EQ(a(1), 2.0); + ASSERT_DOUBLE_EQ(a(2), 3.0); + ASSERT_DOUBLE_EQ(a(3), 4.0); + + // Test resize + a.resize(6); + ASSERT_EQ(a.rows(), 6); + ASSERT_DOUBLE_EQ(buf[5], 6.0); + + // Test the correct buffer is returned + ASSERT_EQ(a.data(), buf); +} + +TEST(VectorViews, VariableSizeRowVectorView) { + double buf[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; - // Check dimesnions + auto a = lin::view>(buf, 2); + static_assert(std::is_same>::value, ""); + static_assert(lin::internal::have_same_traits>::value, ""); + + // Check dimensions ASSERT_EQ(a.rows(), 1); ASSERT_EQ(a.cols(), 2); @@ -125,3 +180,27 @@ TEST(VectorViews, VariableSizeRowVectorView) { // Test the correct buffer is returned ASSERT_EQ(a.data(), buf); } + +TEST(VectorViews, VariableSizeConstRowVectorView) { + double const buf[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; + + auto a = lin::view>(buf, 2); + static_assert(std::is_same>::value, ""); + static_assert(lin::internal::have_same_traits>::value, ""); + + // Check dimensions + ASSERT_EQ(a.rows(), 1); + ASSERT_EQ(a.cols(), 2); + + // Check elements are correct + ASSERT_DOUBLE_EQ(a(0), 1.0); + ASSERT_DOUBLE_EQ(a(1), 2.0); + + // Test resize + a.resize(5); + ASSERT_EQ(a.cols(), 5); + ASSERT_DOUBLE_EQ(buf[4], 5.0); + + // Test the correct buffer is returned + ASSERT_EQ(a.data(), buf); +}