Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 468ef4b

Browse files
committedJan 18, 2025·
[linalg] indexed support
1 parent 31ce4b4 commit 468ef4b

40 files changed

+1142
-157
lines changed
 

‎.github/workflows/citation.yml

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: 'Citation'
2+
3+
on:
4+
push:
5+
paths:
6+
- CITATION.cff
7+
8+
concurrency:
9+
group: ${{ github.workflow }}-${{ github.ref }}
10+
cancel-in-progress: true
11+
12+
jobs:
13+
validate:
14+
name: Validate Citation
15+
runs-on: ubuntu-24.04
16+
env:
17+
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
21+
- name: Validate
22+
uses: dieghernan/cff-validator@4c19ae163bc427f66a5b69ddd4487cfbf5bec48d # v3
23+
with:
24+
install-r: true

‎.github/workflows/cppcheck.yml

+4
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,16 @@ jobs:
4545
--suppress=missingIncludeSystem \
4646
--suppress=preprocessorErrorDirective \
4747
--suppress=unusedFunction:include/fcarouge/format.hpp \
48+
--suppress=syntaxError: test/units_kf_6x2x0_vehicle_location.cpp \
4849
--verbose \
4950
-I benchmark/include \
5051
-I include \
5152
-I support/eigen \
53+
-I support/eigexed \
5254
-I support/generator \
55+
-I support/indexed \
5356
-I support/lazy \
5457
-I support/mp_units \
5558
-I support/naive \
59+
-I support/quantity \
5660
.

‎.github/workflows/pipeline.yml

+7-9
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ jobs:
2323
include:
2424
- { os: 'ubuntu-24.04', cxx: 'clang++-18', cc: 'clang-18', generator: 'Unix Makefiles', packages: 'clang-18' }
2525
- { os: 'ubuntu-24.04', cxx: 'g++-14', cc: 'gcc-14', generator: 'Unix Makefiles', packages: 'g++-14' }
26-
- { os: 'windows-latest', cxx: 'cl', cc: 'cl', generator: 'Ninja', config: 'Debug' }
27-
- { os: 'windows-latest', cxx: 'cl', cc: 'cl', generator: 'Ninja', config: 'Release' }
26+
- { os: 'windows-2022', cxx: 'cl', cc: 'cl', generator: 'Visual Studio 17 2022', config: 'Debug' }
27+
- { os: 'windows-2022', cxx: 'cl', cc: 'cl', generator: 'Visual Studio 17 2022', config: 'Release' }
2828
name: '${{ matrix.os }} / ${{ matrix.cxx }} / ${{ matrix.generator }} / ${{ matrix.config }}'
2929
runs-on: '${{ matrix.os }}'
3030
steps:
@@ -34,8 +34,6 @@ jobs:
3434
egress-policy: audit
3535
- name: 'Checkout'
3636
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
37-
- name: 'Install: MSVC'
38-
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
3937
- name: 'Configure'
4038
env:
4139
CXX: '${{ matrix.cxx }}'
@@ -44,10 +42,10 @@ jobs:
4442
- name: 'Build'
4543
run: cmake --build 'build' --config '${{ matrix.config }}' --verbose --parallel 4
4644
- name: 'Test'
47-
run: ctest --test-dir 'build' --timeout 2 --tests-regex 'kalman' --verbose --parallel 4
45+
run: ctest --test-dir 'build' --build-config '${{ matrix.config }}' --timeout 2 --tests-regex 'kalman' --verbose --parallel 1
4846
- name: 'Install'
49-
run: cmake --install 'build' --prefix 'install' --verbose
47+
run: cmake --install 'build' --config '${{ matrix.config }}' --prefix 'install' --verbose
5048
- name: 'Package'
51-
run: cmake --build 'build' --target 'package' --verbose --parallel 4
52-
- name: 'Package Source'
53-
run: cmake --build 'build' --target 'package_source' --verbose --parallel 4
49+
run: cmake --build 'build' --target 'package' --config '${{ matrix.config }}' --verbose --parallel 4
50+
51+
# TODO: Pin OS versions everywhere.

‎include/fcarouge/internal/x_z_p_q_r_h_f.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ template <typename State, typename Output> struct x_z_p_q_r_h_f {
5050
using output_uncertainty = ᴀʙᵀ<output, output>;
5151
using state_transition = ᴀʙᵀ<state, state>;
5252
using output_model = ᴀʙᵀ<output, state>;
53+
54+
//! @todo Fix me: this gain type is incorrect for physical arithmetic types.
5355
using gain = ᴀʙᵀ<state, output>;
5456
using innovation = output;
5557
using innovation_uncertainty = output_uncertainty;

‎include/fcarouge/internal/x_z_p_r_f.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ For more information, please refer to <https://unlicense.org> */
4242
#include "fcarouge/utility.hpp"
4343

4444
namespace fcarouge::internal {
45+
// This filter requires the state type to be the same as the output? Add tests?
46+
// Conditions? Check the deduced filter in tests?
47+
// Is this a consequence, optimization of the special case where the estimated
48+
// state is also exactly the measured output? Interesting?
4549
template <typename State, typename Output> struct x_z_p_r_f {
4650
using state = State;
4751
using output = Output;

‎include/fcarouge/kalman.hpp

+15-2
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,13 @@ class kalman : public internal::conditional_member_types<Filter> {
231231
//! @note Overloading the operator dot would have been nice had it existed.
232232
inline constexpr auto &&x(this auto &&self);
233233

234+
//! @todo We're still not sure this is the right APi for strongly types
235+
//! algebra.
236+
template <auto Index> inline constexpr auto x(this auto &&self) {
237+
return std::forward<decltype(self)>(self)
238+
.filter.x.template operator()<Index>();
239+
}
240+
234241
//! @brief Sets the state estimate column vector X.
235242
//!
236243
//! @param value The first copied initializer used to set the state estimate
@@ -533,12 +540,18 @@ using internal::output_uncertainty;
533540
//! @brief Process uncertainty type wrapper for filter declaration support.
534541
using internal::process_uncertainty;
535542

536-
//! @brief Input type wrapper for filter declaration support.
543+
//! @brief Input value wrapper for filter declaration support.
537544
using internal::input;
538545

539-
//! @brief Output type wrapper for filter declaration support.
546+
//! @brief Input type wrapper for filter declaration support.
547+
using internal::input_t;
548+
549+
//! @brief Output value wrapper for filter declaration support.
540550
using internal::output;
541551

552+
//! @brief Output type wrapper for filter declaration support.
553+
using internal::output_t;
554+
542555
//! @brief Output model type wrapper for filter declaration support.
543556
using internal::output_model;
544557

‎include/fcarouge/utility.hpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,11 @@ inline constexpr Arithmetic identity<Arithmetic>{1};
253253

254254
template <typename Type>
255255
requires requires { Type::Identity(); }
256-
inline auto identity<Type>{Type::Identity()};
256+
inline Type identity<Type>{Type::Identity()};
257257

258258
template <typename Type>
259259
requires requires { Type::identity(); }
260-
inline auto identity<Type>{Type::identity()};
260+
inline Type identity<Type>{Type::identity()};
261261

262262
//! @brief The zero matrix.
263263
//!
@@ -272,11 +272,11 @@ inline constexpr Arithmetic zero<Arithmetic>{0};
272272

273273
template <typename Type>
274274
requires requires { Type::Zero(); }
275-
inline auto zero<Type>{Type::Zero()};
275+
inline Type zero<Type>{Type::Zero()};
276276

277277
template <typename Type>
278278
requires requires { Type::zero(); }
279-
inline auto zero<Type>{Type::zero()};
279+
inline Type zero<Type>{Type::zero()};
280280

281281
//! @}
282282

‎sample/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ sample(NAME "ekf_4x1x0_soaring" BACKENDS "eigen" "naive")
4242
sample(NAME "kf_1x1x0_building_height")
4343
sample(NAME "kf_1x1x0_liquid_temperature")
4444
sample(NAME "kf_1x1x1_dog_position")
45-
sample(NAME "kf_2x1x1_rocket_altitude" BACKENDS "eigen" "naive")
45+
sample(NAME "kf_2x1x1_rocket_altitude" BACKENDS "eigen")
4646
sample(NAME "kf_6x2x0_vehicle_location" BACKENDS "eigen")
4747
sample(NAME "kf_8x4x0_deep_sort_bounding_box" BACKENDS "eigen")

‎support/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@ OTHER DEALINGS IN THE SOFTWARE.
3636
3737
For more information, please refer to <https://unlicense.org> ]]
3838

39+
add_subdirectory("eigexed")
3940
add_subdirectory("eigen")
41+
add_subdirectory("indexed")
4042
add_subdirectory("main")
4143
add_subdirectory("mp_units")
4244
add_subdirectory("naive")
45+
add_subdirectory("quantity")
4346

4447
add_library(kalman_options INTERFACE)
4548

‎support/eigexed/CMakeLists.txt

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#[[ __ _ __ __ _ _
2+
| |/ / /\ | | | \/ | /\ | \ | |
3+
| ' / / \ | | | \ / | / \ | \| |
4+
| < / /\ \ | | | |\/| | / /\ \ | . ` |
5+
| . \ / ____ \| |____| | | |/ ____ \| |\ |
6+
|_|\_\/_/ \_\______|_| |_/_/ \_\_| \_|
7+
8+
Kalman Filter
9+
Version 0.4.0
10+
https://github.com/FrancoisCarouge/Kalman
11+
12+
SPDX-License-Identifier: Unlicense
13+
14+
This is free and unencumbered software released into the public domain.
15+
16+
Anyone is free to copy, modify, publish, use, compile, sell, or
17+
distribute this software, either in source code form or as a compiled
18+
binary, for any purpose, commercial or non-commercial, and by any
19+
means.
20+
21+
In jurisdictions that recognize copyright laws, the author or authors
22+
of this software dedicate any and all copyright interest in the
23+
software to the public domain. We make this dedication for the benefit
24+
of the public at large and to the detriment of our heirs and
25+
successors. We intend this dedication to be an overt act of
26+
relinquishment in perpetuity of all present and future rights to this
27+
software under copyright law.
28+
29+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
33+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
34+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
35+
OTHER DEALINGS IN THE SOFTWARE.
36+
37+
For more information, please refer to <https://unlicense.org> ]]
38+
39+
add_library(kalman_linalg_eigexed INTERFACE)
40+
target_sources(
41+
kalman_linalg_eigexed INTERFACE FILE_SET "linalg_headers" TYPE "HEADERS"
42+
FILES "fcarouge/linalg.hpp")
43+
target_link_libraries(
44+
kalman_linalg_eigexed INTERFACE kalman kalman_linalg_eigen
45+
kalman_linalg_indexed)

‎support/eigexed/fcarouge/linalg.hpp

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/* __ _ __ __ _ _
2+
| |/ / /\ | | | \/ | /\ | \ | |
3+
| ' / / \ | | | \ / | / \ | \| |
4+
| < / /\ \ | | | |\/| | / /\ \ | . ` |
5+
| . \ / ____ \| |____| | | |/ ____ \| |\ |
6+
|_|\_\/_/ \_\______|_| |_/_/ \_\_| \_|
7+
8+
Kalman Filter
9+
Version 0.4.0
10+
https://github.com/FrancoisCarouge/Kalman
11+
12+
SPDX-License-Identifier: Unlicense
13+
14+
This is free and unencumbered software released into the public domain.
15+
16+
Anyone is free to copy, modify, publish, use, compile, sell, or
17+
distribute this software, either in source code form or as a compiled
18+
binary, for any purpose, commercial or non-commercial, and by any
19+
means.
20+
21+
In jurisdictions that recognize copyright laws, the author or authors
22+
of this software dedicate any and all copyright interest in the
23+
software to the public domain. We make this dedication for the benefit
24+
of the public at large and to the detriment of our heirs and
25+
successors. We intend this dedication to be an overt act of
26+
relinquishment in perpetuity of all present and future rights to this
27+
software under copyright law.
28+
29+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
33+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
34+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
35+
OTHER DEALINGS IN THE SOFTWARE.
36+
37+
For more information, please refer to <https://unlicense.org> */
38+
39+
#ifndef FCAROUGE_LINALG_HPP
40+
#define FCAROUGE_LINALG_HPP
41+
42+
//! @file
43+
//! @brief Scalar type indexed-based linear algebra with Eigen implementations.
44+
45+
#include "fcarouge/eigen.hpp"
46+
#include "fcarouge/indexed_linalg.hpp"
47+
48+
namespace fcarouge {
49+
50+
//! @name Types
51+
//! @{
52+
53+
//! @brief A simple index based on a built-in scalar type.
54+
//!
55+
//! @todo Contrain the index with a concept, static assert.
56+
template <typename Type> struct scalar_index {
57+
using scalar = Type;
58+
using type = Type;
59+
60+
[[nodiscard]] static constexpr auto convert(const Type &value) -> scalar {
61+
return value;
62+
}
63+
};
64+
65+
//! @brief Scalar type indexed-based matrix with Eigen implementations.
66+
template <typename Type = double, auto Row = 1, auto Column = 1>
67+
using matrix = indexed_matrix<eigen::matrix<Type, Row, Column>,
68+
tuple_n_type<scalar_index<Type>, Row>,
69+
tuple_n_type<scalar_index<Type>, Column>>;
70+
71+
//! @brief Scalar type indexed-based column vector with Eigen implementations.
72+
template <typename Type = double, auto Row = 1>
73+
using column_vector = matrix<Type, Row, 1>;
74+
75+
//! @}
76+
77+
} // namespace fcarouge
78+
79+
#endif // FCAROUGE_LINALG_HPP

‎support/indexed/CMakeLists.txt

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#[[ __ _ __ __ _ _
2+
| |/ / /\ | | | \/ | /\ | \ | |
3+
| ' / / \ | | | \ / | / \ | \| |
4+
| < / /\ \ | | | |\/| | / /\ \ | . ` |
5+
| . \ / ____ \| |____| | | |/ ____ \| |\ |
6+
|_|\_\/_/ \_\______|_| |_/_/ \_\_| \_|
7+
8+
Kalman Filter
9+
Version 0.4.0
10+
https://github.com/FrancoisCarouge/Kalman
11+
12+
SPDX-License-Identifier: Unlicense
13+
14+
This is free and unencumbered software released into the public domain.
15+
16+
Anyone is free to copy, modify, publish, use, compile, sell, or
17+
distribute this software, either in source code form or as a compiled
18+
binary, for any purpose, commercial or non-commercial, and by any
19+
means.
20+
21+
In jurisdictions that recognize copyright laws, the author or authors
22+
of this software dedicate any and all copyright interest in the
23+
software to the public domain. We make this dedication for the benefit
24+
of the public at large and to the detriment of our heirs and
25+
successors. We intend this dedication to be an overt act of
26+
relinquishment in perpetuity of all present and future rights to this
27+
software under copyright law.
28+
29+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
33+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
34+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
35+
OTHER DEALINGS IN THE SOFTWARE.
36+
37+
For more information, please refer to <https://unlicense.org> ]]
38+
39+
add_library(kalman_linalg_indexed INTERFACE)
40+
target_sources(
41+
kalman_linalg_indexed INTERFACE FILE_SET "unit_headers" TYPE "HEADERS" FILES
42+
"fcarouge/indexed_linalg.hpp")
43+
target_link_libraries(kalman_linalg_indexed INTERFACE kalman)

‎support/indexed/fcarouge/indexed_linalg.hpp

+488
Large diffs are not rendered by default.

‎support/mp_units/CMakeLists.txt

-7
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,6 @@ For more information, please refer to <https://unlicense.org> ]]
3838

3939
include(FetchContent)
4040

41-
FetchContent_Declare(
42-
fmt
43-
GIT_REPOSITORY "https://github.com/fmtlib/fmt"
44-
GIT_SHALLOW TRUE
45-
FIND_PACKAGE_ARGS NAMES fmt)
46-
FetchContent_MakeAvailable(fmt)
47-
4841
FetchContent_Declare(
4942
gsl-lite
5043
GIT_REPOSITORY "https://github.com/gsl-lite/gsl-lite"

‎support/mp_units/fcarouge/unit.hpp

+9
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,17 @@ using quantity = mp_units::quantity<Reference, Representation>;
6060
template <mp_units::Quantity Type>
6161
inline constexpr auto identity<Type>{Type::one()};
6262

63+
using mp_units::si::metre;
64+
using mp_units::si::second;
6365
using mp_units::si::unit_symbols::m;
6466
using mp_units::si::unit_symbols::m2;
67+
using mp_units::si::unit_symbols::s;
68+
using mp_units::si::unit_symbols::s2;
69+
using mp_units::si::unit_symbols::s3;
70+
71+
//! @todo: Consider upstreaming named symbols up to pow<6> because that would be
72+
//! common for constant jerk uncertainties values?
73+
inline constexpr auto s4{pow<4>(second)};
6574
} // namespace fcarouge
6675

6776
#endif // FCAROUGE_UNIT_HPP

‎support/quantity/CMakeLists.txt

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#[[ __ _ __ __ _ _
2+
| |/ / /\ | | | \/ | /\ | \ | |
3+
| ' / / \ | | | \ / | / \ | \| |
4+
| < / /\ \ | | | |\/| | / /\ \ | . ` |
5+
| . \ / ____ \| |____| | | |/ ____ \| |\ |
6+
|_|\_\/_/ \_\______|_| |_/_/ \_\_| \_|
7+
8+
Kalman Filter
9+
Version 0.4.0
10+
https://github.com/FrancoisCarouge/Kalman
11+
12+
SPDX-License-Identifier: Unlicense
13+
14+
This is free and unencumbered software released into the public domain.
15+
16+
Anyone is free to copy, modify, publish, use, compile, sell, or
17+
distribute this software, either in source code form or as a compiled
18+
binary, for any purpose, commercial or non-commercial, and by any
19+
means.
20+
21+
In jurisdictions that recognize copyright laws, the author or authors
22+
of this software dedicate any and all copyright interest in the
23+
software to the public domain. We make this dedication for the benefit
24+
of the public at large and to the detriment of our heirs and
25+
successors. We intend this dedication to be an overt act of
26+
relinquishment in perpetuity of all present and future rights to this
27+
software under copyright law.
28+
29+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
33+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
34+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
35+
OTHER DEALINGS IN THE SOFTWARE.
36+
37+
For more information, please refer to <https://unlicense.org> ]]
38+
39+
add_library(kalman_linalg_quantity INTERFACE)
40+
target_sources(
41+
kalman_linalg_quantity INTERFACE FILE_SET "linalg_headers" TYPE "HEADERS"
42+
FILES "fcarouge/linalg.hpp")
43+
target_link_libraries(
44+
kalman_linalg_quantity
45+
INTERFACE kalman kalman_linalg_eigen
46+
# kalman unit lib should be here?
47+
kalman_linalg_indexed)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/* __ _ __ __ _ _
2+
| |/ / /\ | | | \/ | /\ | \ | |
3+
| ' / / \ | | | \ / | / \ | \| |
4+
| < / /\ \ | | | |\/| | / /\ \ | . ` |
5+
| . \ / ____ \| |____| | | |/ ____ \| |\ |
6+
|_|\_\/_/ \_\______|_| |_/_/ \_\_| \_|
7+
8+
Kalman Filter
9+
Version 0.4.0
10+
https://github.com/FrancoisCarouge/Kalman
11+
12+
SPDX-License-Identifier: Unlicense
13+
14+
This is free and unencumbered software released into the public domain.
15+
16+
Anyone is free to copy, modify, publish, use, compile, sell, or
17+
distribute this software, either in source code form or as a compiled
18+
binary, for any purpose, commercial or non-commercial, and by any
19+
means.
20+
21+
In jurisdictions that recognize copyright laws, the author or authors
22+
of this software dedicate any and all copyright interest in the
23+
software to the public domain. We make this dedication for the benefit
24+
of the public at large and to the detriment of our heirs and
25+
successors. We intend this dedication to be an overt act of
26+
relinquishment in perpetuity of all present and future rights to this
27+
software under copyright law.
28+
29+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
33+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
34+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
35+
OTHER DEALINGS IN THE SOFTWARE.
36+
37+
For more information, please refer to <https://unlicense.org> */
38+
39+
#ifndef FCAROUGE_QUANTITY_LINALG_HPP
40+
#define FCAROUGE_QUANTITY_LINALG_HPP
41+
42+
//! @file
43+
//! @brief Indexed-based linear algebra with mp-units with Eigen
44+
//! implementations.
45+
46+
#include "fcarouge/indexed_linalg.hpp"
47+
#include "fcarouge/linalg.hpp"
48+
#include "fcarouge/unit.hpp"
49+
50+
namespace fcarouge {
51+
52+
//! @name Types
53+
//! @{
54+
55+
//! @brief A quantity index based on the mp-units quantity.
56+
//!
57+
//! @todo Constraint index types with a concept: scalar/underlying, type,
58+
//! conversion members?
59+
template <auto Reference> struct quantity_index {
60+
using scalar = double;
61+
using type = quantity<Reference, scalar>;
62+
63+
//! @todo Can we do without this structure altogether with the help of
64+
//! https://mpusz.github.io/mp-units/latest/users_guide/use_cases/interoperability_with_other_libraries/
65+
//! Or can this definition be more generic?
66+
[[nodiscard]] static constexpr auto convert(const auto &value) -> scalar {
67+
return value.numerical_value_in(value.unit);
68+
}
69+
};
70+
71+
//! @brief Quantity column vector with mp-units and Eigen implementations.
72+
template <auto... Reference>
73+
using quantity_vector = indexed_column_vector<
74+
column_vector<typename quantity_index<first_v<Reference...>>::scalar,
75+
sizeof...(Reference)>,
76+
quantity_index<Reference>...>;
77+
78+
//! @}
79+
} // namespace fcarouge
80+
81+
#endif // FCAROUGE_QUANTITY_LINALG_HPP

‎test/CMakeLists.txt

+34-33
Original file line numberDiff line numberDiff line change
@@ -38,46 +38,47 @@ For more information, please refer to <https://unlicense.org> ]]
3838

3939
include(test.cmake)
4040

41-
test(NAME "kalman_assign_move_5x4x3" BACKENDS "eigen")
42-
test(NAME "kalman_constructor_default_1x1x3" BACKENDS "eigen")
43-
test(NAME "kalman_constructor_default_1x4x1" BACKENDS "eigen")
44-
test(NAME "kalman_constructor_default_1x4x3" BACKENDS "eigen")
45-
test(NAME "kalman_constructor_default_5x1x1" BACKENDS "eigen")
46-
test(NAME "kalman_constructor_default_5x1x3" BACKENDS "eigen")
41+
test(NAME "kalman_assign_move_5x4x3" BACKENDS "eigen" "eigexed")
42+
test(NAME "kalman_constructor_default_1x4x1" BACKENDS "eigen" "eigexed")
43+
test(NAME "kalman_constructor_default_1x4x3" BACKENDS "eigen" "eigexed")
44+
test(NAME "kalman_constructor_default_5x1x1" BACKENDS "eigen" "eigexed")
45+
test(NAME "kalman_constructor_default_5x1x3" BACKENDS "eigen" "eigexed")
4746
test(NAME "kalman_constructor_default_5x4x0" BACKENDS "eigen")
48-
test(NAME "kalman_constructor_default_5x4x1" BACKENDS "eigen")
49-
test(NAME "kalman_constructor_default_5x4x3" BACKENDS "eigen")
47+
test(NAME "kalman_constructor_default_5x4x1" BACKENDS "eigen" "eigexed")
48+
test(NAME "kalman_constructor_default_5x4x3" BACKENDS "eigen" "eigexed")
5049
test(NAME "kalman_constructor_default_float_1x1x1")
5150
test(NAME "kalman_constructor_default")
52-
test(NAME "kalman_constructor_move_5x4x3" BACKENDS "eigen")
53-
test(NAME "kalman_f_5x4x3" BACKENDS "eigen")
51+
test(NAME "kalman_constructor_move_5x4x3" BACKENDS "eigen" "eigexed")
52+
test(NAME "kalman_f_5x4x3" BACKENDS "eigen" "eigexed")
5453
test(NAME "kalman_f")
55-
test(NAME "kalman_format_1x4x3" BACKENDS "eigen")
56-
test(NAME "kalman_format_5x4x3" BACKENDS "eigen")
54+
test(NAME "kalman_format_1x4x3" BACKENDS "eigen" "eigexed")
55+
test(NAME "kalman_format_5x4x3" BACKENDS "eigen" "eigexed")
5756
test(NAME "kalman_format_arguments")
5857
test(NAME "kalman_format_float_1x1x1")
5958
test(NAME "kalman_format")
60-
test(NAME "kalman_h_5x4x3" BACKENDS "eigen")
59+
test(NAME "kalman_h_5x4x3" BACKENDS "eigen" "eigexed")
6160
test(NAME "kalman_println_1x1x0")
62-
test(NAME "linalg_addition" BACKENDS "eigen" "naive")
63-
test(NAME "linalg_assign" BACKENDS "eigen" "naive")
64-
test(NAME "linalg_constructor_1x1_array" BACKENDS "eigen" "naive")
65-
test(NAME "linalg_constructor_1x1" BACKENDS "eigen" "naive")
66-
test(NAME "linalg_constructor_1xn_array" BACKENDS "eigen" "naive")
67-
test(NAME "linalg_constructor_1xn" BACKENDS "eigen" "naive")
68-
test(NAME "linalg_constructor_initializer_lists" BACKENDS "eigen" "naive")
69-
test(NAME "linalg_constructor_nx1_array" BACKENDS "eigen" "naive")
70-
test(NAME "linalg_constructor_nx1" BACKENDS "eigen" "naive")
71-
test(NAME "linalg_copy" BACKENDS "eigen" "naive")
72-
test(NAME "linalg_identity" BACKENDS "eigen" "naive")
73-
test(NAME "linalg_multiplication_arithmetic" BACKENDS "eigen" "naive")
74-
test(NAME "linalg_multiplication_rxc" BACKENDS "eigen" "naive")
75-
test(NAME "linalg_multiplication_sxc" BACKENDS "eigen" "naive")
76-
test(NAME "linalg_operator_bracket" BACKENDS "eigen" "naive")
77-
test(NAME "linalg_operator_equality" BACKENDS "eigen" "naive")
78-
test(NAME "linalg_zero" BACKENDS "eigen" "naive")
61+
test(NAME "linalg_addition" BACKENDS "eigen" "eigexed" "naive")
62+
test(NAME "linalg_assign" BACKENDS "eigen" "eigexed" "naive")
63+
test(NAME "linalg_constructor_1x1_array" BACKENDS "eigen" "eigexed" "naive")
64+
test(NAME "linalg_constructor_1x1" BACKENDS "eigen" "eigexed" "naive")
65+
test(NAME "linalg_constructor_1xn_array" BACKENDS "eigen" "eigexed" "naive")
66+
test(NAME "linalg_constructor_1xn" BACKENDS "eigen" "eigexed" "naive")
67+
test(NAME "linalg_constructor_initializer_lists" BACKENDS "eigen" "eigexed"
68+
"naive")
69+
test(NAME "linalg_constructor_nx1_array" BACKENDS "eigen" "eigexed" "naive")
70+
test(NAME "linalg_constructor_nx1" BACKENDS "eigen" "eigexed" "naive")
71+
test(NAME "linalg_copy" BACKENDS "eigen" "eigexed" "naive")
72+
test(NAME "linalg_identity" BACKENDS "eigen" "eigexed" "naive")
73+
test(NAME "linalg_multiplication_arithmetic" BACKENDS "eigen" "eigexed" "naive")
74+
test(NAME "linalg_multiplication_rxc" BACKENDS "eigen" "eigexed" "naive")
75+
test(NAME "linalg_multiplication_sxc" BACKENDS "eigen" "eigexed" "naive")
76+
test(NAME "linalg_operator_bracket" BACKENDS "eigen" "eigexed" "naive")
77+
test(NAME "linalg_operator_equality" BACKENDS "eigexed")
78+
test(NAME "linalg_zero" BACKENDS "eigen" "eigexed" "naive")
7979
test(NAME "printer_1x1x0")
80-
test(NAME "printer_2x3x4" BACKENDS "eigen")
80+
test(NAME "printer_2x3x4" BACKENDS "eigen" "eigexed")
8181
test(NAME "units_kf_1x1x0_building_height")
82-
test(NAME "utility_identity_default" BACKENDS "eigen" "naive")
83-
test(NAME "utility_zero_default" BACKENDS "eigen" "naive")
82+
test(NAME "units_kf_6x2x0_vehicle_location" BACKENDS "quantity")
83+
test(NAME "utility_identity_default")
84+
test(NAME "utility_zero_default")

‎test/kalman_assign_move_5x4x3.cpp

+10-10
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,16 @@ template <auto Row, auto Column> using matrix = matrix<double, Row, Column>;
4949

5050
//! @test Verifies the multi-dimension filter is move-assignable.
5151
[[maybe_unused]] auto test{[] {
52-
const auto z3x1{zero<vector<3>>};
53-
const auto i4x4{identity<matrix<4, 4>>};
54-
const auto i4x5{identity<matrix<4, 5>>};
55-
const auto i5x3{identity<matrix<5, 3>>};
56-
const auto i5x4{identity<matrix<5, 4>>};
57-
const auto i5x5{identity<matrix<5, 5>>};
58-
const auto z4x1{zero<vector<4>>};
59-
const auto z4x4{zero<matrix<4, 4>>};
60-
const auto z5x1{zero<vector<5>>};
61-
const auto z5x5{zero<matrix<5, 5>>};
52+
vector<3> z3x1{zero<vector<3>>};
53+
matrix<4, 4> i4x4{identity<matrix<4, 4>>};
54+
matrix<4, 5> i4x5{identity<matrix<4, 5>>};
55+
matrix<5, 3> i5x3{identity<matrix<5, 3>>};
56+
matrix<5, 4> i5x4{identity<matrix<5, 4>>};
57+
matrix<5, 5> i5x5{identity<matrix<5, 5>>};
58+
vector<4> z4x1{zero<vector<4>>};
59+
matrix<4, 4> z4x4{zero<matrix<4, 4>>};
60+
vector<5> z5x1{zero<vector<5>>};
61+
matrix<5, 5> z5x5{zero<matrix<5, 5>>};
6262
kalman filter{state{vector<5>{0.0, 0.0, 0.0, 0.0, 0.0}}, output<vector<4>>,
6363
input<vector<3>>};
6464
{

‎test/kalman_constructor_default_1x1x3.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,10 @@ template <auto Row, auto Column> using matrix = matrix<double, Row, Column>;
4848

4949
//! @test Verifies default values are initialized for multi-dimension filters.
5050
[[maybe_unused]] auto test{[] {
51+
vector<3> z3x1{zero<vector<3>>};
52+
matrix<1, 3> i1x3{identity<matrix<1, 3>>};
5153
kalman filter{state{0.0}, output<double>, input<vector<3>>};
5254

53-
const auto z3x1{zero<vector<3>>};
54-
const auto i1x3{identity<matrix<1, 3>>};
55-
5655
assert(filter.f() == 1);
5756
assert(filter.g() == i1x3);
5857
assert(filter.h() == 1);

‎test/kalman_constructor_default_1x4x1.cpp

+5-6
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,13 @@ template <auto Row, auto Column> using matrix = matrix<double, Row, Column>;
4949
//! @test Verifies default values are initialized for multi-dimension filters,
5050
//! single state and input edge case.
5151
[[maybe_unused]] auto test{[] {
52+
matrix<4, 4> i4x4{identity<matrix<4, 4>>};
53+
matrix<4, 1> i4x1{identity<matrix<4, 1>>};
54+
matrix<1, 4> i1x4{identity<matrix<1, 4>>};
55+
vector<4> z4x1{zero<vector<4>>};
56+
matrix<4, 4> z4x4{zero<matrix<4, 4>>};
5257
kalman filter{state{0.0}, output<vector<4>>, input<double>};
5358

54-
const auto i4x4{identity<matrix<4, 4>>};
55-
const auto i4x1{identity<matrix<4, 1>>};
56-
const auto i1x4{identity<matrix<1, 4>>};
57-
const auto z4x1{zero<vector<4>>};
58-
const auto z4x4{zero<matrix<4, 4>>};
59-
6059
assert(filter.f() == 1);
6160
assert(filter.g() == 1);
6261
assert(filter.h() == i4x1);

‎test/kalman_constructor_default_1x4x3.cpp

+7-8
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,15 @@ template <auto Row, auto Column> using matrix = matrix<double, Row, Column>;
4949
//! @test Verifies default values are initialized for multi-dimension filters,
5050
//! single state edge case.
5151
[[maybe_unused]] auto test{[] {
52+
vector<3> z3x1{zero<vector<3>>};
53+
matrix<4, 4> i4x4{identity<matrix<4, 4>>};
54+
matrix<4, 1> i4x1{identity<matrix<4, 1>>};
55+
matrix<1, 3> i1x3{identity<matrix<1, 3>>};
56+
matrix<1, 4> i1x4{identity<matrix<1, 4>>};
57+
vector<4> z4x1{zero<vector<4>>};
58+
matrix<4, 4> z4x4{zero<matrix<4, 4>>};
5259
kalman filter{state{0.0}, output<vector<4>>, input<vector<3>>};
5360

54-
const auto z3x1{zero<vector<3>>};
55-
const auto i4x4{identity<matrix<4, 4>>};
56-
const auto i4x1{identity<matrix<4, 1>>};
57-
const auto i1x3{identity<matrix<1, 3>>};
58-
const auto i1x4{identity<matrix<1, 4>>};
59-
const auto z4x1{zero<vector<4>>};
60-
const auto z4x4{zero<matrix<4, 4>>};
61-
6261
assert(filter.f() == 1);
6362
assert(filter.g() == i1x3);
6463
assert(filter.h() == i4x1);

‎test/kalman_constructor_default_5x1x1.cpp

+5-6
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,14 @@ template <auto Row, auto Column> using matrix = matrix<double, Row, Column>;
4949
//! @test Verifies default values are initialized for multi-dimension filters,
5050
//! single output and input edge case.
5151
[[maybe_unused]] auto test{[] {
52+
matrix<1, 5> i1x5{identity<matrix<1, 5>>};
53+
matrix<5, 1> i5x1{identity<matrix<5, 1>>};
54+
matrix<5, 5> i5x5{identity<matrix<5, 5>>};
55+
vector<5> z5x1{zero<vector<5>>};
56+
matrix<5, 5> z5x5{zero<matrix<5, 5>>};
5257
kalman filter{state{vector<5>{0.0, 0.0, 0.0, 0.0, 0.0}}, output<double>,
5358
input<double>};
5459

55-
const auto i1x5{identity<matrix<1, 5>>};
56-
const auto i5x1{identity<matrix<5, 1>>};
57-
const auto i5x5{identity<matrix<5, 5>>};
58-
const auto z5x1{zero<vector<5>>};
59-
const auto z5x5{zero<matrix<5, 5>>};
60-
6160
assert(filter.f() == i5x5);
6261
assert(filter.g() == i5x1);
6362
assert(filter.h() == i1x5);

‎test/kalman_constructor_default_5x1x3.cpp

+7-8
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,16 @@ template <auto Row, auto Column> using matrix = matrix<double, Row, Column>;
4949
//! @test Verifies default values are initialized for multi-dimension filters,
5050
//! single output edge case.
5151
[[maybe_unused]] auto test{[] {
52+
vector<3> z3x1{zero<vector<3>>};
53+
matrix<1, 5> i1x5{identity<matrix<1, 5>>};
54+
matrix<5, 3> i5x3{identity<matrix<5, 3>>};
55+
matrix<5, 1> i5x1{identity<matrix<5, 1>>};
56+
matrix<5, 5> i5x5{identity<matrix<5, 5>>};
57+
vector<5> z5x1{zero<vector<5>>};
58+
matrix<5, 5> z5x5{zero<matrix<5, 5>>};
5259
kalman filter{state{vector<5>{0.0, 0.0, 0.0, 0.0, 0.0}}, output<double>,
5360
input<vector<3>>};
5461

55-
const auto z3x1{zero<vector<3>>};
56-
const auto i1x5{identity<matrix<1, 5>>};
57-
const auto i5x3{identity<matrix<5, 3>>};
58-
const auto i5x1{identity<matrix<5, 1>>};
59-
const auto i5x5{identity<matrix<5, 5>>};
60-
const auto z5x1{zero<vector<5>>};
61-
const auto z5x5{zero<matrix<5, 5>>};
62-
6362
assert(filter.f() == i5x5);
6463
assert(filter.g() == i5x3);
6564
assert(filter.h() == i1x5);

‎test/kalman_constructor_default_5x4x0.cpp

+6-7
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,14 @@ template <auto Row, auto Column> using matrix = matrix<double, Row, Column>;
4949
//! @test Verifies default values are initialized for multi-dimension filters,
5050
//! no input.
5151
[[maybe_unused]] auto test{[] {
52+
matrix<4, 4> i4x4{identity<matrix<4, 4>>};
53+
matrix<5, 4> i5x4{identity<matrix<5, 4>>};
54+
matrix<5, 5> i5x5{identity<matrix<5, 5>>};
55+
vector<4> z4x1{zero<vector<4>>};
56+
matrix<4, 4> z4x4{zero<matrix<4, 4>>};
57+
vector<5> z5x1{zero<vector<5>>};
5258
kalman filter{state{vector<5>{0., 0., 0., 0., 0.}}, output<vector<4>>};
5359

54-
const auto i4x4{identity<matrix<4, 4>>};
55-
const auto i5x4{identity<matrix<5, 4>>};
56-
const auto i5x5{identity<matrix<5, 5>>};
57-
const auto z4x1{zero<vector<4>>};
58-
const auto z4x4{zero<matrix<4, 4>>};
59-
const auto z5x1{zero<vector<5>>};
60-
6160
assert(filter.f() == i5x5);
6261
assert(filter.k() == i5x4);
6362
assert(filter.p() == i5x5);

‎test/kalman_constructor_default_5x4x1.cpp

+9-10
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,18 @@ template <auto Row, auto Column> using matrix = matrix<double, Row, Column>;
4949
//! @test Verifies default values are initialized for multi-dimension filters,
5050
//! single input edge case.
5151
[[maybe_unused]] auto test{[] {
52+
matrix<4, 4> i4x4{identity<matrix<4, 4>>};
53+
matrix<4, 5> i4x5{identity<matrix<4, 5>>};
54+
matrix<5, 1> i5x1{identity<matrix<5, 1>>};
55+
matrix<5, 4> i5x4{identity<matrix<5, 4>>};
56+
matrix<5, 5> i5x5{identity<matrix<5, 5>>};
57+
vector<4> z4x1{zero<vector<4>>};
58+
matrix<4, 4> z4x4{zero<matrix<4, 4>>};
59+
vector<5> z5x1{zero<vector<5>>};
60+
matrix<5, 5> z5x5{zero<matrix<5, 5>>};
5261
kalman filter{state{vector<5>{0.0, 0.0, 0.0, 0.0, 0.0}}, output<vector<4>>,
5362
input<double>};
5463

55-
const auto i4x4{identity<matrix<4, 4>>};
56-
const auto i4x5{identity<matrix<4, 5>>};
57-
const auto i5x1{identity<matrix<5, 1>>};
58-
const auto i5x4{identity<matrix<5, 4>>};
59-
const auto i5x5{identity<matrix<5, 5>>};
60-
const auto z4x1{zero<vector<4>>};
61-
const auto z4x4{zero<matrix<4, 4>>};
62-
const auto z5x1{zero<vector<5>>};
63-
const auto z5x5{zero<matrix<5, 5>>};
64-
6564
assert(filter.f() == i5x5);
6665
assert(filter.g() == i5x1);
6766
assert(filter.h() == i4x5);

‎test/kalman_constructor_default_5x4x3.cpp

+10-11
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,19 @@ template <auto Row, auto Column> using matrix = matrix<double, Row, Column>;
4848

4949
//! @test Verifies default values are initialized for multi-dimension filters.
5050
[[maybe_unused]] auto test{[] {
51+
vector<3> z3x1{zero<vector<3>>};
52+
matrix<4, 4> i4x4{identity<matrix<4, 4>>};
53+
matrix<4, 5> i4x5{identity<matrix<4, 5>>};
54+
matrix<5, 3> i5x3{identity<matrix<5, 3>>};
55+
matrix<5, 4> i5x4{identity<matrix<5, 4>>};
56+
matrix<5, 5> i5x5{identity<matrix<5, 5>>};
57+
vector<4> z4x1{zero<vector<4>>};
58+
matrix<4, 4> z4x4{zero<matrix<4, 4>>};
59+
vector<5> z5x1{zero<vector<5>>};
60+
matrix<5, 5> z5x5{zero<matrix<5, 5>>};
5161
kalman filter{state{vector<5>{0.0, 0.0, 0.0, 0.0, 0.0}}, output<vector<4>>,
5262
input<vector<3>>};
5363

54-
const auto z3x1{zero<vector<3>>};
55-
const auto i4x4{identity<matrix<4, 4>>};
56-
const auto i4x5{identity<matrix<4, 5>>};
57-
const auto i5x3{identity<matrix<5, 3>>};
58-
const auto i5x4{identity<matrix<5, 4>>};
59-
const auto i5x5{identity<matrix<5, 5>>};
60-
const auto z4x1{zero<vector<4>>};
61-
const auto z4x4{zero<matrix<4, 4>>};
62-
const auto z5x1{zero<vector<5>>};
63-
const auto z5x5{zero<matrix<5, 5>>};
64-
6564
assert(filter.f() == i5x5);
6665
assert(filter.g() == i5x3);
6766
assert(filter.h() == i4x5);

‎test/kalman_constructor_move_5x4x3.cpp

+10-10
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,16 @@ template <auto Row, auto Column> using matrix = matrix<double, Row, Column>;
4949

5050
//! @test Verifies the multi-dimension filter is move-constructible.
5151
[[maybe_unused]] auto test{[] {
52-
const auto z3x1{zero<vector<3>>};
53-
const auto i4x4{identity<matrix<4, 4>>};
54-
const auto i4x5{identity<matrix<4, 5>>};
55-
const auto i5x3{identity<matrix<5, 3>>};
56-
const auto i5x4{identity<matrix<5, 4>>};
57-
const auto i5x5{identity<matrix<5, 5>>};
58-
const auto z4x1{zero<vector<4>>};
59-
const auto z4x4{zero<matrix<4, 4>>};
60-
const auto z5x1{zero<vector<5>>};
61-
const auto z5x5{zero<matrix<5, 5>>};
52+
vector<3> z3x1{zero<vector<3>>};
53+
matrix<4, 4> i4x4{identity<matrix<4, 4>>};
54+
matrix<4, 5> i4x5{identity<matrix<4, 5>>};
55+
matrix<5, 3> i5x3{identity<matrix<5, 3>>};
56+
matrix<5, 4> i5x4{identity<matrix<5, 4>>};
57+
matrix<5, 5> i5x5{identity<matrix<5, 5>>};
58+
vector<4> z4x1{zero<vector<4>>};
59+
matrix<4, 4> z4x4{zero<matrix<4, 4>>};
60+
vector<5> z5x1{zero<vector<5>>};
61+
matrix<5, 5> z5x5{zero<matrix<5, 5>>};
6262
kalman another_filter{state{vector<5>{0.0, 0.0, 0.0, 0.0, 0.0}},
6363
output<vector<4>>, input<vector<3>>};
6464

‎test/kalman_f.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ namespace {
5050
assert(filter.f() == 1);
5151

5252
{
53-
const auto f{2.};
53+
double f{2.};
5454
filter.f(f);
5555
assert(filter.f() == 2);
5656
}
5757

5858
{
59-
const auto f{3.};
59+
double f{3.};
6060
filter.f(f);
6161
assert(filter.f() == 3);
6262
}

‎test/kalman_f_5x4x3.cpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -49,23 +49,22 @@ template <auto Row, auto Column> using matrix = matrix<double, Row, Column>;
4949
//! @test Verifies the state transition matrix F management overloads for
5050
//! the Eigen filter type.
5151
[[maybe_unused]] auto test{[] {
52-
const auto i5x5{identity<matrix<5, 5>>};
53-
const auto z5x5{zero<matrix<5, 5>>};
54-
const vector<3> z3{zero<vector<3>>};
52+
matrix<5, 5> i5x5{identity<matrix<5, 5>>};
53+
matrix<5, 5> z5x5{zero<matrix<5, 5>>};
5554
kalman filter{state{vector<5>{0., 0., 0., 0., 0.}}, output<vector<4>>,
5655
input<vector<3>>, update_types<double, float, int>,
5756
prediction_types<int, float, double>};
5857

5958
assert(filter.f() == i5x5);
6059

6160
{
62-
const auto f{z5x5};
61+
matrix<5, 5> f{z5x5};
6362
filter.f(f);
6463
assert(filter.f() == z5x5);
6564
}
6665

6766
{
68-
const auto f{i5x5};
67+
matrix<5, 5> f{i5x5};
6968
filter.f(f);
7069
assert(filter.f() == i5x5);
7170
}

‎test/kalman_h_5x4x3.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -49,22 +49,22 @@ template <auto Row, auto Column> using matrix = matrix<double, Row, Column>;
4949
//! @test Verifies the observation transition matrix H management overloads for
5050
//! the Eigen filter type.
5151
[[maybe_unused]] auto test{[] {
52-
const auto i4x5{identity<matrix<4, 5>>};
53-
const auto z4x5{zero<matrix<4, 5>>};
52+
matrix<4, 5> i4x5{identity<matrix<4, 5>>};
53+
matrix<4, 5> z4x5{zero<matrix<4, 5>>};
5454
kalman filter{state{vector<5>{0., 0., 0., 0., 0.}}, output<vector<4>>,
5555
input<vector<3>>, update_types<double, float, int>,
5656
prediction_types<int, float, double>};
5757

5858
assert(filter.h() == i4x5);
5959

6060
{
61-
const auto h{z4x5};
61+
matrix<4, 5> h{z4x5};
6262
filter.h(h);
6363
assert(filter.h() == z4x5);
6464
}
6565

6666
{
67-
const auto h{i4x5};
67+
matrix<4, 5> h{i4x5};
6868
filter.h(h);
6969
assert(filter.h() == i4x5);
7070
}

‎test/linalg_assign.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ namespace fcarouge::test {
4444
namespace {
4545
//! @test Verifies the assignment operator.
4646
[[maybe_unused]] auto test{[] {
47-
auto m{identity<matrix<double, 5, 5>>};
48-
auto c = m;
47+
matrix<double, 5, 5> m{identity<matrix<double, 5, 5>>};
48+
matrix<double, 5, 5> c = m;
4949

5050
assert((c == identity<matrix<double, 5, 5>>));
5151

‎test/linalg_copy.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ namespace fcarouge::test {
4444
namespace {
4545
//! @test Verifies the copy constructor.
4646
[[maybe_unused]] auto test{[] {
47-
auto m{identity<matrix<double, 5, 5>>};
48-
auto c{m};
47+
matrix<double, 5, 5> m{identity<matrix<double, 5, 5>>};
48+
matrix<double, 5, 5> c{m};
4949

5050
assert((c == identity<matrix<double, 5, 5>>));
5151

‎test/linalg_identity.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ namespace fcarouge::test {
4444
namespace {
4545
//! @test Verifies the identity matrices values are unit diagonals.
4646
[[maybe_unused]] auto test{[] {
47-
auto i{identity<matrix<double, 3, 3>>};
47+
matrix<double, 3, 3> i{identity<matrix<double, 3, 3>>};
4848

4949
assert(i(0, 0) == 1.0);
5050
assert(i(0, 1) == 0.0);

‎test/linalg_multiplication_sxc.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ namespace {
4646
[[maybe_unused]] auto test{[] {
4747
matrix<double, 2, 2> a{{1.0, 2.0}, {3.0, 4.0}};
4848
matrix<double, 2, 1> b{3.0, 4.0};
49-
auto r{a * b};
49+
matrix<double, 2, 1> r{a * b};
5050

5151
assert(r(0, 0) == 11.0);
5252
assert(r(1, 0) == 25.0);

‎test/linalg_operator_equality.cpp

+19-3
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,29 @@ For more information, please refer to <https://unlicense.org> */
4040

4141
#include <cassert>
4242

43+
#include <print>
44+
#include <typeinfo>
45+
#include <type_traits>
46+
#include <concepts>
47+
4348
namespace fcarouge::test {
4449
namespace {
4550
//! @test Verifies the equality operator.
4651
[[maybe_unused]] auto test{[] {
47-
auto m{zero<matrix<double, 5, 5>>};
48-
auto i{identity<matrix<double, 5, 5>>};
49-
auto z{zero<matrix<double, 5, 5>>};
52+
const matrix<double, 5, 5> m{zero<matrix<double, 5, 5>>};
53+
const matrix<double, 5, 5> i{identity<matrix<double, 5, 5>>};
54+
const matrix<double, 5, 5> z{zero<matrix<double, 5, 5>>};
55+
56+
std::println("M: {}", typeid(m).name());
57+
std::println("I: {}", typeid(i).name());
58+
std::println("Z: {}", typeid(z).name());
59+
60+
// static_assert(std::is_same_v<int, matrix<double, 5, 5>>);
61+
// carouge::indexed_matrix<Eigen::Matrix<double, 5, 5, 0, 5, 5>, std::tuple<fcarouge::scalar_index<double>, fcarouge::scalar_index<double>, fcarouge::scalar_index<double>, fcarouge::scalar_index<double>, fcarouge::scalar_index<double>>, std::tuple<fcarouge::scalar_index<double>, fcarouge::scalar_index<double>, fcarouge::scalar_index<double>, fcarouge::scalar_index<double>, fcarouge::scalar_index<double>>>
62+
63+
std::println("M: {}", m);
64+
std::println("Z: {}", z);
65+
std::println("I: {}", i);
5066

5167
assert(m == z);
5268
assert(m != i);

‎test/linalg_zero.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ namespace fcarouge::test {
4444
namespace {
4545
//! @test Verifies the zero matrices values are null.
4646
[[maybe_unused]] auto test{[] {
47-
auto z{zero<matrix<double, 3, 3>>};
47+
matrix<double, 3, 3> z{zero<matrix<double, 3, 3>>};
4848

4949
assert(z(0, 0) == 0.0);
5050
assert(z(0, 1) == 0.0);

‎test/test.cmake

+2-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ function(test)
6161
"${TEST_NAME}.cpp")
6262
target_link_libraries(
6363
kalman_test_${BACKEND}_${TEST_NAME}_driver
64-
PRIVATE kalman kalman_main kalman_linalg_${BACKEND} kalman_options)
64+
PRIVATE kalman kalman_main kalman_linalg_${BACKEND} kalman_options
65+
kalman_unit_mp_units)
6566
separate_arguments(TEST_COMMAND UNIX_COMMAND $ENV{COMMAND})
6667
add_test(
6768
NAME kalman_test_${BACKEND}_${TEST_NAME}

‎test/units_kf_1x1x0_building_height.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ For more information, please refer to <https://unlicense.org> */
4040
#include "fcarouge/unit.hpp"
4141

4242
#include <cassert>
43+
#include <format>
44+
45+
#include <print>
4346

4447
namespace fcarouge::test {
4548
namespace {
@@ -65,6 +68,17 @@ namespace {
6568

6669
assert(abs(1 - filter.x() / (49.57 * m)) < 0.001);
6770

71+
//! @todo Support floating point formatting precission to make this
72+
//! demonstrator readable.
73+
// assert(std::format("{}", filter) == R"({"f": 1 m²,)"
74+
// R"( "k": 0.09890109890109894,)"
75+
// R"( "p": 2.4725274725274726 m²,)"
76+
// R"( "r": 25 m²,)"
77+
// R"( "s": 27.743902439024392 m²,)"
78+
// R"( "x": 49.5698901098901 m,)"
79+
// R"( "y": 0.4218292682926972 m,)"
80+
// R"( "z": 49.95 m})");
81+
6882
return 0;
6983
}()};
7084
} // namespace
+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/* __ _ __ __ _ _
2+
| |/ / /\ | | | \/ | /\ | \ | |
3+
| ' / / \ | | | \ / | / \ | \| |
4+
| < / /\ \ | | | |\/| | / /\ \ | . ` |
5+
| . \ / ____ \| |____| | | |/ ____ \| |\ |
6+
|_|\_\/_/ \_\______|_| |_/_/ \_\_| \_|
7+
8+
Kalman Filter
9+
Version 0.4.0
10+
https://github.com/FrancoisCarouge/Kalman
11+
12+
SPDX-License-Identifier: Unlicense
13+
14+
This is free and unencumbered software released into the public domain.
15+
16+
Anyone is free to copy, modify, publish, use, compile, sell, or
17+
distribute this software, either in source code form or as a compiled
18+
binary, for any purpose, commercial or non-commercial, and by any
19+
means.
20+
21+
In jurisdictions that recognize copyright laws, the author or authors
22+
of this software dedicate any and all copyright interest in the
23+
software to the public domain. We make this dedication for the benefit
24+
of the public at large and to the detriment of our heirs and
25+
successors. We intend this dedication to be an overt act of
26+
relinquishment in perpetuity of all present and future rights to this
27+
software under copyright law.
28+
29+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
33+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
34+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
35+
OTHER DEALINGS IN THE SOFTWARE.
36+
37+
For more information, please refer to <https://unlicense.org> */
38+
39+
#include "fcarouge/kalman.hpp"
40+
#include "fcarouge/quantity_linalg.hpp"
41+
#include "fcarouge/unit.hpp"
42+
43+
#include <cassert>
44+
#include <format>
45+
46+
namespace fcarouge::test {
47+
namespace {
48+
using state =
49+
fcarouge::state<quantity_vector<m, m / s, m / s2, m, m / s, m / s2>>;
50+
using output_t = quantity_vector<m, m>;
51+
using estimate_uncertainty =
52+
fcarouge::estimate_uncertainty<ᴀʙᵀ<state::type, state::type>>;
53+
using process_uncertainty =
54+
fcarouge::process_uncertainty<ᴀʙᵀ<state::type, state::type>>;
55+
using output_uncertainty =
56+
fcarouge::output_uncertainty<ᴀʙᵀ<output_t, output_t>>;
57+
using output_model = fcarouge::output_model<ᴀʙᵀ<output_t, state::type>>;
58+
using state_transition =
59+
fcarouge::state_transition<ᴀʙᵀ<state::type, state::type>>;
60+
61+
template <auto... Reference>
62+
inline fcarouge::output_t<quantity_vector<Reference...>> output{
63+
fcarouge::output<quantity_vector<Reference...>>};
64+
65+
//! @test Verifies compatibility with the `mp-units` quantities and units
66+
//! library for C++ in the case of an algebraic 6x2x0 filter estimating the
67+
//! vehicle location.
68+
//!
69+
//! @details See the sample for details.
70+
[[maybe_unused]] auto test{[] {
71+
kalman filter{
72+
state{0. * m, 0. * m / s, 0. * m / s2, 0. * m, 0. * m / s, 0. * m / s2},
73+
output<m, m>,
74+
estimate_uncertainty{500. * identity<estimate_uncertainty::type>},
75+
process_uncertainty{[]() {
76+
process_uncertainty::type value{identity<process_uncertainty::type>};
77+
value[0, 0] = 0.25 * m2;
78+
value[0, 1] = 0.5 * m2 / s;
79+
value[0, 2] = 0.5 * m2 / s2;
80+
value[1, 0] = 0.5 * m2 / s;
81+
value[1, 2] = 1 * m2 / s3;
82+
value[2, 0] = 0.5 * m2 / s2;
83+
value[2, 1] = 1 * m2 / s4;
84+
value[3, 3] = 0.25 * m2;
85+
value[3, 4] = 0.5 * m2 / s;
86+
value[3, 5] = 0.5 * m2 / s2;
87+
value[4, 3] = 0.5 * m2 / s;
88+
value[4, 5] = 1 * m2 / s3;
89+
value[5, 3] = 0.5 * m2 / s2;
90+
value[5, 4] = 1 * m2 / s4;
91+
return 0.2 * 0.2 * value;
92+
}()},
93+
output_uncertainty{{9. * m2, 0. * m2}, {0. * m2, 9. * m2}},
94+
output_model{[]() {
95+
output_model::type value{zero<output_model::type>};
96+
value[0, 0] = 1. * m2;
97+
value[1, 3] = 1. * m2;
98+
return value;
99+
}()},
100+
state_transition{[]() {
101+
state_transition::type value{identity<state_transition::type>};
102+
value[0, 1] = 1. * m2 / s;
103+
value[0, 2] = 0.5 * m2 / s2;
104+
value[1, 2] = 1. * m2 / s3;
105+
value[3, 4] = 1. * m2 / s;
106+
value[3, 5] = 0.5 * m2 / s2;
107+
value[4, 5] = 1. * m2 / s3;
108+
return value;
109+
}()}};
110+
111+
filter.predict();
112+
filter.update(-393.66 * m, 300.4 * m);
113+
filter.predict();
114+
filter.update(-375.93 * m, 301.78 * m);
115+
filter.predict();
116+
117+
// Verify the example estimated state at 0.1% accuracy.
118+
assert(abs(1 - filter.x<0>() / (-277.8 * m)) < 0.001 &&
119+
abs(1 - filter.x<1>() / (148.3 * m / s)) < 0.001 &&
120+
abs(1 - filter.x<2>() / (94.5 * m / s2)) < 0.001 &&
121+
abs(1 - filter.x<3>() / (249.8 * m)) < 0.001 &&
122+
abs(1 - filter.x<4>() / (-85.9 * m / s)) < 0.001 &&
123+
abs(1 - filter.x<5>() / (-63.62 * m / s2)) < 0.001 &&
124+
"The state estimates expected at 0.1% accuracy.");
125+
126+
return 0;
127+
}()};
128+
} // namespace
129+
} // namespace fcarouge::test

0 commit comments

Comments
 (0)
Please sign in to comment.