Skip to content

Commit

Permalink
[filter] support constexpr linear algebra
Browse files Browse the repository at this point in the history
  • Loading branch information
FrancoisCarouge committed Apr 16, 2023
1 parent babad2e commit 59aeb3f
Show file tree
Hide file tree
Showing 9 changed files with 672 additions and 8 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/cppcheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ jobs:
--enable=all \
--error-exitcode=1 \
--suppress=missingIncludeSystem \
--suppress=unusedFunction:benchmark/eigen_predict_x1x.cpp \
--suppress=unusedFunction:benchmark/eigen_update_xx0.cpp \
--suppress=noExplicitConstructor:include/fcarouge/linalg.hpp \
--suppress=unusedFunction:benchmark/const_predict_x1x.cpp \
--suppress=unusedFunction:benchmark/const_update_xx0.cpp \
--suppress=unusedStructMember:sample/ekf_4x1x0_soaring.cpp \
--verbose \
-I benchmark/include \
Expand Down
41 changes: 41 additions & 0 deletions benchmark/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,47 @@ foreach(BENCHMARK "baseline.cpp" "predict_1x1x0.cpp" "predict_1x1x1.cpp"
"--benchmark_out=${NAME}.json")
endforeach()

foreach(STATE_SIZE RANGE 1 2)
foreach(OUTPUT_SIZE RANGE 1 2)
configure_file(const_update_xx0.cpp
const_update_${STATE_SIZE}x${OUTPUT_SIZE}x0.cpp)
get_filename_component(NAME const_update_${STATE_SIZE}x${OUTPUT_SIZE}x0.cpp
NAME_WE)
add_executable(kalman_benchmark_${NAME}_driver
const_update_${STATE_SIZE}x${OUTPUT_SIZE}x0.cpp)
target_include_directories(kalman_benchmark_${NAME}_driver
PRIVATE "include")
set_target_properties(kalman_benchmark_${NAME}_driver
PROPERTIES CXX_STANDARD 23)
set_target_properties(kalman_benchmark_${NAME}_driver
PROPERTIES CXX_EXTENSIONS OFF)
target_link_libraries(
kalman_benchmark_${NAME}_driver PRIVATE benchmark::benchmark
benchmark::benchmark_main kalman)
add_test(kalman_benchmark_${NAME} kalman_benchmark_${NAME}_driver
"--benchmark_out=${NAME}.json")
endforeach()
foreach(INPUT_SIZE RANGE 1 2)
configure_file(const_predict_x1x.cpp
const_predict_${STATE_SIZE}x1x${INPUT_SIZE}.cpp)
get_filename_component(NAME const_predict_${STATE_SIZE}x1x${INPUT_SIZE}.cpp
NAME_WE)
add_executable(kalman_benchmark_${NAME}_driver
const_predict_${STATE_SIZE}x1x${INPUT_SIZE}.cpp)
target_include_directories(kalman_benchmark_${NAME}_driver
PRIVATE "include")
set_target_properties(kalman_benchmark_${NAME}_driver
PROPERTIES CXX_STANDARD 23)
set_target_properties(kalman_benchmark_${NAME}_driver
PROPERTIES CXX_EXTENSIONS OFF)
target_link_libraries(
kalman_benchmark_${NAME}_driver PRIVATE benchmark::benchmark
benchmark::benchmark_main kalman)
add_test(kalman_benchmark_${NAME} kalman_benchmark_${NAME}_driver
"--benchmark_out=${NAME}.json")
endforeach()
endforeach()

foreach(STATE_SIZE RANGE 1 2)
foreach(OUTPUT_SIZE RANGE 1 2)
configure_file(eigen_update_xx0.cpp
Expand Down
111 changes: 111 additions & 0 deletions benchmark/const_predict_x1x.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* __ _ __ __ _ _
| |/ / /\ | | | \/ | /\ | \ | |
| ' / / \ | | | \ / | / \ | \| |
| < / /\ \ | | | |\/| | / /\ \ | . ` |
| . \ / ____ \| |____| | | |/ ____ \| |\ |
|_|\_\/_/ \_\______|_| |_/_/ \_\_| \_|
Kalman Filter
Version 0.2.0
https://github.com/FrancoisCarouge/Kalman
SPDX-License-Identifier: Unlicense
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
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 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.
For more information, please refer to <https://unlicense.org> */

#include "benchmark.hpp"
#include "fcarouge/internal/utility.hpp"
#include "fcarouge/kalman.hpp"
#include "fcarouge/linalg.hpp"

#include <benchmark/benchmark.h>

#include <algorithm>
#include <chrono>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <random>

namespace fcarouge::benchmark {
namespace {

template <auto Size> using vector = linalg::column_vector<float, Size>;

//! @benchmark Measure the prediction of the filter for different dimensions of
//! states and inputs with the Eigen linear algebra backend.
template <std::size_t StateSize, std::size_t InputSize>
void eigen_predict(::benchmark::State &state) {
using kalman =
kalman<vector<StateSize>, /*float*/ vector<1>, vector<InputSize>>;

kalman filter;
std::random_device random_device;
std::mt19937 random_generator{random_device()};
std::uniform_real_distribution<float> uniformly_distributed;

for (auto _ : state) {

float uv[InputSize];

internal::for_constexpr<std::size_t{0}, InputSize, 1>(
[&uv, &uniformly_distributed, &random_generator](auto position) {
uv[position] = uniformly_distributed(random_generator);
});

typename kalman::input u{uv};

::benchmark::ClobberMemory();
const auto start{clock::now()};

filter.predict(u);

::benchmark::ClobberMemory();
const auto end{clock::now()};

state.SetIterationTime(std::chrono::duration<double>{end - start}.count());
}
}

//! @todo Find a way to remove macros or find a different benchmark library that
//! doesn't use macros.
BENCHMARK(eigen_predict<${STATE_SIZE}, ${INPUT_SIZE}>)
->Name("eigen_predict_${STATE_SIZE}x1x${INPUT_SIZE}")
->Unit(::benchmark::kNanosecond)
->ComputeStatistics("min",
[](const auto &results) {
return std::ranges::min(results);
})
-> ComputeStatistics("max",
[](const auto &results) {
return std::ranges::max(results);
}) -> UseManualTime()
-> Complexity(::benchmark::oAuto) -> DisplayAggregatesOnly(true)
-> Repetitions(100);

} // namespace
} // namespace fcarouge::benchmark
111 changes: 111 additions & 0 deletions benchmark/const_update_xx0.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* __ _ __ __ _ _
| |/ / /\ | | | \/ | /\ | \ | |
| ' / / \ | | | \ / | / \ | \| |
| < / /\ \ | | | |\/| | / /\ \ | . ` |
| . \ / ____ \| |____| | | |/ ____ \| |\ |
|_|\_\/_/ \_\______|_| |_/_/ \_\_| \_|
Kalman Filter
Version 0.2.0
https://github.com/FrancoisCarouge/Kalman
SPDX-License-Identifier: Unlicense
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
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 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.
For more information, please refer to <https://unlicense.org> */

#include "benchmark.hpp"
#include "fcarouge/internal/utility.hpp"
#include "fcarouge/kalman.hpp"
#include "fcarouge/linalg.hpp"

#include <benchmark/benchmark.h>

#include <algorithm>
#include <chrono>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <random>

namespace fcarouge::benchmark {
namespace {

template <auto Size> using vector = linalg::column_vector<float, Size>;

//! @benchmark Measure the update of the filter for different dimensions of
//! states and outputs with the Eigen linear algebra backend.
template <std::size_t StateSize, std::size_t OutputSize>
void eigen_update(::benchmark::State &state) {

using kalman = kalman<vector<StateSize>, vector<OutputSize>, void>;

kalman filter;
std::random_device random_device;
std::mt19937 random_generator{random_device()};
std::uniform_real_distribution<float> uniformly_distributed;

for (auto _ : state) {

float zv[OutputSize];

internal::for_constexpr<std::size_t{0}, OutputSize, 1>(
[&zv, &uniformly_distributed, &random_generator](auto position) {
zv[position] = uniformly_distributed(random_generator);
});

typename kalman::output z{zv};

::benchmark::ClobberMemory();
const auto start{clock::now()};

filter.update(z);

::benchmark::ClobberMemory();
const auto end{clock::now()};

state.SetIterationTime(std::chrono::duration<double>{end - start}.count());
}
}

//! @todo Find a way to remove macros or find a different benchmark library that
//! doesn't use macros.
BENCHMARK(eigen_update<${STATE_SIZE}, ${OUTPUT_SIZE}>)
->Name("eigen_update_${STATE_SIZE}x${OUTPUT_SIZE}x0")
->Unit(::benchmark::kNanosecond)
->ComputeStatistics("min",
[](const auto &results) {
return std::ranges::min(results);
})
-> ComputeStatistics("max",
[](const auto &results) {
return std::ranges::max(results);
}) -> UseManualTime()
-> Complexity(::benchmark::oAuto) -> DisplayAggregatesOnly(true)
-> Repetitions(100);

} // namespace
} // namespace fcarouge::benchmark
1 change: 1 addition & 0 deletions include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ target_sources(
"fcarouge/internal/kalman.tpp"
"fcarouge/internal/utility.hpp"
"fcarouge/kalman.hpp"
"fcarouge/linalg.hpp"
"fcarouge/utility.hpp")
target_compile_options(kalman INTERFACE ${OPTIONS})
target_link_libraries(kalman INTERFACE $<$<NOT:$<BOOL:${WIN32}>>:kalman_format>)
Expand Down
64 changes: 58 additions & 6 deletions include/fcarouge/internal/utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,7 @@ constexpr void for_constexpr(Function &&function) {
}

template <typename Type>
inline constexpr Type identity_v{
//! @todo Implement standard, default form.
};
inline constexpr Type identity_v; // Your type not supported, add nice message.

template <arithmetic Arithmetic>
inline constexpr Arithmetic identity_v<Arithmetic>{1};
Expand All @@ -93,9 +91,7 @@ requires requires(Matrix value) { value.Identity(); }
inline const auto identity_v<Matrix>{Matrix::Identity()};

template <typename Type>
inline constexpr Type zero_v{
//! @todo Implement standard, default form.
};
inline constexpr Type zero_v; // Your type not supported, add nice message.

template <arithmetic Arithmetic>
inline constexpr Arithmetic zero_v<Arithmetic>{0};
Expand All @@ -104,6 +100,9 @@ template <typename Matrix>
requires requires(Matrix value) { value.Zero(); }
inline const auto zero_v<Matrix>{Matrix::Zero()};

inline constexpr auto adl_transpose{
[](const auto &value) { return transpose(value); }};

struct transpose final {
template <arithmetic Arithmetic>
[[nodiscard]] inline constexpr auto
Expand All @@ -116,6 +115,11 @@ struct transpose final {
[[nodiscard]] inline constexpr auto operator()(const Matrix &value) const {
return value.transpose();
}

template <typename Matrix>
[[nodiscard]] inline constexpr auto operator()(const Matrix &value) const {
return adl_transpose(value);
}
};

//! @todo The dimensional analysis shows the deduction of matrices gives us the
Expand Down Expand Up @@ -155,6 +159,54 @@ struct deducer final {
[[nodiscard]] inline constexpr auto operator()(const Lhs &lhs,
const Rhs &rhs) const ->
typename decltype(rhs.transpose())::PlainMatrix;

/////////////////////////////////////////////////////////////////////////
// For Lhs [m by n] and Rhs [o by n] -> Result [m by o].
template <template <typename, auto, auto> typename Matrix, typename Type,
auto M, auto N, auto O>
requires requires { requires !(M == 1 && N == 1 && O == 1); }
[[nodiscard]] inline constexpr auto
operator()(const Matrix<Type, M, N> &lhs, const Matrix<Type, O, N> &rhs) const
-> Matrix<Type, M, O>;

template <template <typename, auto, auto> typename Matrix, typename Type>
[[nodiscard]] inline constexpr auto
operator()(const Matrix<Type, 1, 1> &lhs, const Matrix<Type, 1, 1> &rhs) const
-> Type;

// template <template <typename, auto, auto> typename Matrix, typename Type>
// [[nodiscard]] inline constexpr auto
// operator()(const Matrix<Type, 1, 1> &lhs, const Matrix<Type, 1, 1> &rhs)
// const
// -> Type;

// template <arithmetic Lhs, template <typename, auto, auto> typename Rhs,
// typename Type, auto Row>
// [[nodiscard]] inline constexpr auto
// operator()(const Lhs &lhs, const Rhs<Type, Row, 1> &rhs) const
// -> Rhs<Type, 1, Row>;

// For Lhs [m by n] and Rhs [o by n] -> Result [m by o],
// with m > 1, and n = o = 1, the result is [m by 1].
template <template <typename, auto, auto> typename Lhs, typename Type, auto M>
requires requires {
requires M >
1;
}
[[nodiscard]] inline constexpr auto operator()(const Lhs<Type, M, 1> &lhs,
arithmetic auto rhs) const
-> Lhs<Type, M, 1>;

// For Lhs [m by n] and Rhs [o by n] -> Result [m by o],
// with m = n = 1, and o > 1, the result is [1 by o].
template <template <typename, auto, auto> typename Rhs, typename Type, auto O>
requires requires {
requires O >
1;
}
[[nodiscard]] inline constexpr auto
operator()(arithmetic auto lhs, const Rhs<Type, O, 1> &rhs) const
-> Rhs<Type, 1, O>;
};

template <typename Numerator, typename Denominator>
Expand Down
Loading

0 comments on commit 59aeb3f

Please sign in to comment.