Skip to content

Commit

Permalink
[filter] declarative paradigm
Browse files Browse the repository at this point in the history
  • Loading branch information
FrancoisCarouge committed Jan 26, 2024
1 parent 4331741 commit 76d949b
Show file tree
Hide file tree
Showing 18 changed files with 721 additions and 374 deletions.
110 changes: 46 additions & 64 deletions benchmark/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,12 @@ FetchContent_MakeAvailable(google_benchmark)

set(PROCESSOR_AFFINITY TRUE)

foreach(BENCHMARK "baseline.cpp" "predict_1x1x0.cpp" "predict_1x1x1.cpp"
"update_1x1x0.cpp" "update_1x1x1.cpp")
foreach(
BENCHMARK
"baseline.cpp"
# "predict_1x1x0.cpp" "predict_1x1x1.cpp" # "update_1x1x0.cpp"
# "update_1x1x1.cpp"
)
get_filename_component(NAME ${BENCHMARK} NAME_WE)
add_executable(kalman_benchmark_${NAME}_driver ${BENCHMARK})
target_include_directories(kalman_benchmark_${NAME}_driver PRIVATE "include")
Expand All @@ -75,66 +79,44 @@ foreach(BENCHMARK "baseline.cpp" "predict_1x1x0.cpp" "predict_1x1x1.cpp"
"--benchmark_out=${NAME}.json")
endforeach()

foreach(BACKEND IN ITEMS "eigen" "naive")
foreach(STATE_SIZE RANGE 1 2)
foreach(INPUT_SIZE RANGE 1 2)
configure_file(predict_linalg_x1x.cpp
predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}.cpp)
add_executable(
kalman_benchmark_predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}_driver
predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}.cpp)
target_include_directories(
kalman_benchmark_predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}_driver
PRIVATE "include")
set_target_properties(
kalman_benchmark_predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}_driver
PROPERTIES CXX_STANDARD 23
CXX_EXTENSIONS OFF
INTERPROCEDURAL_OPTIMIZATION TRUE)
target_link_libraries(
kalman_benchmark_predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}_driver
PRIVATE benchmark::benchmark benchmark::benchmark_main kalman
kalman_linalg_${BACKEND} kalman_options)
separate_arguments(TEST_COMMAND UNIX_COMMAND $ENV{COMMAND})
add_test(
NAME kalman_benchmark_predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}
COMMAND
${TEST_COMMAND}
$<TARGET_FILE:kalman_benchmark_predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}_driver>
"--benchmark_out=predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}.json"
)
endforeach()
endforeach()
endforeach()
# foreach(BACKEND IN ITEMS "eigen" "naive") foreach(STATE_SIZE RANGE 1 2)
# foreach(INPUT_SIZE RANGE 1 2) configure_file(predict_linalg_x1x.cpp
# predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}.cpp) add_executable(
# kalman_benchmark_predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}_driver
# predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}.cpp)
# target_include_directories(
# kalman_benchmark_predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}_driver
# PRIVATE "include") set_target_properties(
# kalman_benchmark_predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}_driver
# PROPERTIES CXX_STANDARD 23 CXX_EXTENSIONS OFF INTERPROCEDURAL_OPTIMIZATION
# TRUE) target_link_libraries(
# kalman_benchmark_predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}_driver
# PRIVATE benchmark::benchmark benchmark::benchmark_main kalman
# kalman_linalg_${BACKEND} kalman_options) separate_arguments(TEST_COMMAND
# UNIX_COMMAND $ENV{COMMAND}) add_test( NAME
# kalman_benchmark_predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE} COMMAND
# ${TEST_COMMAND}
# $<TARGET_FILE:kalman_benchmark_predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}_driver>
# "--benchmark_out=predict_${BACKEND}_${STATE_SIZE}x1x${INPUT_SIZE}.json" )
# endforeach() endforeach() endforeach()

foreach(BACKEND IN ITEMS "eigen")
foreach(STATE_SIZE RANGE 1 2)
foreach(OUTPUT_SIZE RANGE 1 2)
configure_file(update_linalg_xx0.cpp
update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0.cpp)
add_executable(
kalman_benchmark_update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0_driver
update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0.cpp)
target_include_directories(
kalman_benchmark_update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0_driver
PRIVATE "include")
set_target_properties(
kalman_benchmark_update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0_driver
PROPERTIES CXX_STANDARD 23
CXX_EXTENSIONS OFF
INTERPROCEDURAL_OPTIMIZATION TRUE)
target_link_libraries(
kalman_benchmark_update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0_driver
PRIVATE benchmark::benchmark benchmark::benchmark_main kalman
kalman_linalg_${BACKEND} kalman_options)
separate_arguments(TEST_COMMAND UNIX_COMMAND $ENV{COMMAND})
add_test(
NAME kalman_benchmark_update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0
COMMAND
${TEST_COMMAND}
$<TARGET_FILE:kalman_benchmark_update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0_driver>
"--benchmark_out=update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0.json"
)
endforeach()
endforeach()
endforeach()
# foreach(BACKEND IN ITEMS "eigen") foreach(STATE_SIZE RANGE 1 2)
# foreach(OUTPUT_SIZE RANGE 1 2) configure_file(update_linalg_xx0.cpp
# update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0.cpp) add_executable(
# kalman_benchmark_update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0_driver
# update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0.cpp)
# target_include_directories(
# kalman_benchmark_update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0_driver
# PRIVATE "include") set_target_properties(
# kalman_benchmark_update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0_driver
# PROPERTIES CXX_STANDARD 23 CXX_EXTENSIONS OFF INTERPROCEDURAL_OPTIMIZATION
# TRUE) target_link_libraries(
# kalman_benchmark_update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0_driver
# PRIVATE benchmark::benchmark benchmark::benchmark_main kalman
# kalman_linalg_${BACKEND} kalman_options) separate_arguments(TEST_COMMAND
# UNIX_COMMAND $ENV{COMMAND}) add_test( NAME
# kalman_benchmark_update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0 COMMAND
# ${TEST_COMMAND}
# $<TARGET_FILE:kalman_benchmark_update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0_driver>
# "--benchmark_out=update_${BACKEND}_${STATE_SIZE}x${OUTPUT_SIZE}x0.json" )
# endforeach() endforeach() endforeach()
44 changes: 22 additions & 22 deletions include/fcarouge/internal/format.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,23 @@ For more information, please refer to <https://unlicense.org> */
#include <type_traits>

namespace fcarouge {
template <typename, typename, typename, typename, typename> class kalman;
template <typename> class kalman;
} // namespace fcarouge

template <typename State, typename Output, typename Input, typename UpdateTypes,
typename PredictionTypes, typename Char>
template <typename Filter, typename Char>
// It is allowed to add template specializations for any standard library class
// template to the namespace std only if the declaration depends on at least one
// program-defined type and the specialization satisfies all requirements for
// the original template, except where such specializations are prohibited.
// NOLINTNEXTLINE(cert-dcl58-cpp)
struct std::formatter<
fcarouge::kalman<State, Output, Input, UpdateTypes, PredictionTypes>,
Char> {
struct std::formatter<fcarouge::kalman<Filter>, Char> {
constexpr auto parse(std::basic_format_parse_context<Char> &parse_context) {
return parse_context.begin();
}

//! @todo P2585 may be useful in simplifying and standardizing the support.
template <typename OutputIt>
auto format(const fcarouge::kalman<State, Output, Input, UpdateTypes,
PredictionTypes> &filter,
auto format(const fcarouge::kalman<Filter> &filter,
std::basic_format_context<OutputIt, Char> &format_context) const
-> OutputIt {
format_context.advance_to(
Expand All @@ -80,17 +76,19 @@ struct std::formatter<
R"("h": {}, "k": {}, "p": {}, )",
filter.h(), filter.k(), filter.p()));

{
constexpr auto end{fcarouge::internal::repack_s<PredictionTypes>};
[&]<template <typename> typename Type, typename InternalFilter>(
const Type<InternalFilter> &f) {
constexpr auto end{fcarouge::internal::repack_s<
typename InternalFilter::prediction_types>};
constexpr decltype(end) begin{0};
constexpr decltype(end) next{1};
fcarouge::internal::for_constexpr<begin, end, next>(
[&format_context, &filter](auto position) {
[&format_context, &f](auto position) {
format_context.advance_to(
format_to(format_context.out(), R"("prediction_{}": {}, )",
position(), filter.template predict<position>()));
position(), f.template predict<position>()));
});
}
}(filter);

format_context.advance_to(format_to(format_context.out(),
R"("q": {}, "r": {}, "s": {}, )",
Expand All @@ -101,17 +99,19 @@ struct std::formatter<
format_to(format_context.out(), R"("u": {}, )", filter.u()));
}

{
constexpr auto end{fcarouge::internal::repack_s<UpdateTypes>};
[&]<template <typename> typename Type, typename InternalFilter>(
const Type<InternalFilter> &f) {
constexpr auto end{
fcarouge::internal::repack_s<typename InternalFilter::update_types>};
constexpr decltype(end) begin{0};
constexpr decltype(end) next{1};
fcarouge::internal::for_constexpr<begin, end, next>(
[&format_context, &filter](auto position) {
format_context.advance_to(
format_to(format_context.out(), R"("update_{}": {}, )",
position(), filter.template update<position>()));
});
}
fcarouge::internal::for_constexpr<begin, end, next>([&format_context,
&f](auto position) {
format_context.advance_to(format_to(format_context.out(),
R"("update_{}": {}, )", position(),
f.template update<position>()));
});
}(filter);

format_context.advance_to(format_to(format_context.out(),
R"("x": {}, "y": {}, "z": {}}})",
Expand Down
140 changes: 133 additions & 7 deletions include/fcarouge/internal/kalman.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,19 @@ For more information, please refer to <https://unlicense.org> */
#include "utility.hpp"

#include <tuple>
#include <type_traits>

namespace fcarouge::internal {
template <typename, typename, typename, typename, typename>
struct kalman final {
template <typename, typename, typename, typename>
struct kalman_s_o_us_ps final {
//! @todo Support some more specializations, all, or disable others?
//! @todo Add a pretty compilation error?
};

template <typename State, typename Output, typename... UpdateTypes,
typename... PredictionTypes>
struct kalman<State, Output, void, pack<UpdateTypes...>,
pack<PredictionTypes...>> {
struct kalman_s_o_us_ps<State, Output, pack<UpdateTypes...>,
pack<PredictionTypes...>> {
using state = State;
using output = Output;
using input = empty;
Expand Down Expand Up @@ -163,10 +164,16 @@ struct kalman<State, Output, void, pack<UpdateTypes...>,
}
};

template <typename, typename, typename, typename, typename>
struct kalman_s_o_i_us_ps final {
//! @todo Support some more specializations, all, or disable others?
//! @todo Add a pretty compilation error?
};

template <typename State, typename Output, typename Input,
typename... UpdateTypes, typename... PredictionTypes>
struct kalman<State, Output, Input, pack<UpdateTypes...>,
pack<PredictionTypes...>> {
struct kalman_s_o_i_us_ps<State, Output, Input, pack<UpdateTypes...>,
pack<PredictionTypes...>> {
using state = State;
using output = Output;
using input = Input;
Expand Down Expand Up @@ -202,14 +209,14 @@ struct kalman<State, Output, Input, pack<UpdateTypes...>,
estimate_uncertainty p{identity_v<estimate_uncertainty>};
process_uncertainty q{zero_v<process_uncertainty>};
output_uncertainty r{zero_v<output_uncertainty>};
input u{zero_v<input>};
output_model h{identity_v<output_model>};
state_transition f{identity_v<state_transition>};
input_control g{identity_v<input_control>};
gain k{identity_v<gain>};
innovation y{zero_v<innovation>};
innovation_uncertainty s{identity_v<innovation_uncertainty>};
output z{zero_v<output>};
input u{zero_v<input>};
update_types update_arguments{};
prediction_types prediction_arguments{};
transpose t{};
Expand Down Expand Up @@ -293,6 +300,125 @@ struct kalman<State, Output, Input, pack<UpdateTypes...>,
p = estimate_uncertainty{f * p * t(f) + q};
}
};

template <typename Type> struct state {
Type value;
using type = Type;
};

template <typename Type> struct estimate_uncertainty {
Type value;
using type = Type;
};

template <typename Type> struct output_uncertainty {
Type value;
using type = Type;
};

template <typename Type> struct process_uncertainty {
Type value;
using type = Type;
};

//! @todo Should we just use the template syntax instead of allowing value
//! construction/CTAD?
template <typename Type> struct input {
Type value;
using type = Type;
};

template <typename Type> struct output {
Type value;
using type = Type;
};

template <typename Type> struct output_model {
Type value;
using type = Type;
};

//! WHY NO WORKY?
//! @todo Better name not ending by *_types?
// template <typename... Types> struct update_types {
// inline constexpr explicit update_types(
// [[maybe_unused]] auto &&...any) noexcept {}
// };

template <typename... Types> using update_types = std::tuple<Types...>;

// template <typename... Types> struct prediction_types {
// inline constexpr explicit prediction_types(
// [[maybe_unused]] auto &&...any) noexcept {}
// };

template <typename... Types> using prediction_types = std::tuple<Types...>;

//! @todo Support arbritary order of configuration parameters?
struct make_filter {
inline constexpr auto operator()() const {
return kalman_s_o_us_ps<double, double, empty_pack, empty_pack>{};
}

template <typename State, typename Input>
inline constexpr auto operator()(state<State> x,
[[maybe_unused]] input<Input> u) const {
return kalman_s_o_i_us_ps<State, State, Input, empty_pack, empty_pack>{
x.value};
}

template <typename State, typename EstimateUncertainty,
typename OutputUncertainty>
inline constexpr auto
operator()(state<State> x, estimate_uncertainty<EstimateUncertainty> p,
output_uncertainty<OutputUncertainty> r) const {
return kalman_s_o_us_ps<State, State, empty_pack, empty_pack>{
x.value, p.value, {}, r.value};
}

template <typename State, typename EstimateUncertainty,
typename OutputUncertainty, typename ProcessUncertainty>
inline constexpr auto
operator()(state<State> x, estimate_uncertainty<EstimateUncertainty> p,
process_uncertainty<ProcessUncertainty> q,
output_uncertainty<OutputUncertainty> r) const {
return kalman_s_o_us_ps<State, State, empty_pack, empty_pack>{
x.value, p.value, q.value, r.value};
}

template <typename State, typename Input, typename EstimateUncertainty,
typename OutputUncertainty, typename ProcessUncertainty>
inline constexpr auto
operator()(state<State> x, [[maybe_unused]] input<Input> u,
estimate_uncertainty<EstimateUncertainty> p,
process_uncertainty<ProcessUncertainty> q,
output_uncertainty<OutputUncertainty> r) const {
return kalman_s_o_i_us_ps<State, State, Input, empty_pack, empty_pack>{
x.value, p.value, q.value, r.value};
}
template <typename State, typename Input, typename EstimateUncertainty,
typename OutputUncertainty, typename ProcessUncertainty,
typename... Us, typename... Ps>
inline constexpr auto
operator()(state<State> x, [[maybe_unused]] input<Input> u,
estimate_uncertainty<EstimateUncertainty> p,
process_uncertainty<ProcessUncertainty> q,
output_uncertainty<OutputUncertainty> r,
[[maybe_unused]] update_types<Us...> uts,
[[maybe_unused]] prediction_types<Ps...> pts) const {

return kalman_s_o_i_us_ps<State, State, Input,
repack_t<update_types<Us...>>,
repack_t<prediction_types<Ps...>>>{
x.value, p.value, q.value, r.value};
}
};

inline constexpr make_filter filter{};

template <typename... Arguments>
using filter_t = std::invoke_result_t<make_filter, Arguments...>;

} // namespace fcarouge::internal

#endif // FCAROUGE_INTERNAL_KALMAN_HPP
Loading

0 comments on commit 76d949b

Please sign in to comment.