44 T::ValueDimensionAtCompileTime,
47 T::MaxValueDimensionAtCompileTime,
50 typename T::SpaceType;
52 { density.logDensity(x) } -> std::convertible_to<typename T::Scalar>;
62concept CheckedParams =
requires(T
const & params) {
63 { params.toDensity().has_value() } -> std::convertible_to<bool>;
64 requires HasLogDensity<
typename decltype(params.toDensity())::value_type>;
69concept HasMoments =
requires(T
const & distribution) { distribution.moments(); };
80 || (internal::CheckedParams<T>
81 && internal::HasMoments<
typename decltype(std::declval<T const &>().toDensity())::value_type>);
89template <
typename Own,
typename Block>
90inline constexpr bool factorFits = std::is_same_v<Own, Block> || std::derived_from<Block, Own>
97template <
typename Placed>
102template <ProductFactor F,
typename Path>
103struct PlacedFactor<OnPath<F, Path>>
106 template <
typename Space>
110 template <
typename Space>
111 [[nodiscard]]
static F
112 factorIn(OnPath<F, Path> && placed,
Space const &)
114 return std::move(placed.value);
118 template <
typename Space>
119 [[nodiscard]]
static auto
120 indicesIn(OnPath<F, Path>
const &,
Space const & space)
126 template <
typename Space>
127 static constexpr bool fitsIn = factorFits<typename F::SpaceType, PathSubspaceType<Space, Path>>;
133template <ProductFactor F,
typename Indices>
141template <ProductFactor F,
typename Indices>
142struct PlacedFactor<FactorAt<F, Indices>>
145 template <
typename Space>
149 template <
typename Space>
150 [[nodiscard]]
static F
151 factorIn(FactorAt<F, Indices> && placed,
Space const &)
153 return std::move(placed.factor);
157 template <
typename Space>
158 [[nodiscard]]
static auto
159 indicesIn(FactorAt<F, Indices>
const & placed,
Space const &)
161 return asIndexSet(placed.indices);
165 template <
typename Space>
166 static constexpr bool fitsIn =
true;
170template <
typename Indices, ProductFactor F>
171[[nodiscard]] FactorAt<F, Indices>
172placedAt(Indices indices, F factor)
174 return {std::move(factor), std::move(indices)};
179[[nodiscard]]
decltype(
auto)
180densityOf(F
const & factor)
188 auto const density = factor.toDensity();
189 auto view = *density;
196inline constexpr bool momentsMayFail =
197 isExpected<std::remove_cvref_t<decltype(densityOf(std::declval<F const &>()).moments())>>;
200template <
typename... T>
205template <std::size_t N,
typename... T>
209 using type = TypeList<T...>;
213template <std::size_t N,
typename First,
typename... Rest>
215struct DropFrontImpl<N, First, Rest...> : DropFrontImpl<N - 1, Rest...>
219template <std::size_t N,
typename... T>
220using DropFront =
typename DropFrontImpl<N, T...>::type;
223template <std::size_t N,
typename Done,
typename... T>
231template <std::size_t N,
typename... Done,
typename First,
typename... Rest>
233struct TakeFrontImpl<N, TypeList<Done...>, First, Rest...> : TakeFrontImpl<N - 1, TypeList<Done..., First>, Rest...>
237template <std::size_t N,
typename... T>
238using TakeFront =
typename TakeFrontImpl<N, TypeList<>, T...>::type;
243template <
int Size,
int MaxSize,
typename Indices,
typename Target>
244[[nodiscard]] IndexVector<Size, MaxSize>
245positionsIn(Indices
const & indices, Target
const & target)
247 auto result = IndexVector<Size, MaxSize>{};
248 result.resize(Eigen::Index(indices.size()));
249 for (Eigen::Index i = 0; i < result.size(); ++i)
251 auto const found = std::ranges::find(target, indices[i]);
252 EMRYS_FILTER_ASSERT(found != std::ranges::end(target) &&
"a factor's coordinate is missing from the result");
253 result(i) = Eigen::Index(found - std::ranges::begin(target));
260struct ConditionalValueOf
267template <
typename T,
typename E>
268struct ConditionalValueOf<std::expected<T, E>>
278using ConditionalValue =
typename ConditionalValueOf<R>::type;
284struct ConditionalErrorOf
291template <
typename T,
typename E>
292struct ConditionalErrorOf<std::expected<T, E>>
299template <CheckedParams R>
300struct ConditionalErrorOf<R>
303 using type =
typename decltype(std::declval<R const &>().toDensity())::error_type;
308using ConditionalError =
typename ConditionalErrorOf<R>::type;
323 typename Replacement,
325 typename Sequence = std::make_index_sequence<std::tuple_size_v<Factors_>>>
326struct ReplacedProductOf;
329template <
typename Scalar,
typename Space, std::size_t K,
typename Replacement,
typename... Factors_, std::size_t... J>
330struct ReplacedProductOf<Scalar,
Space, K, Replacement, std::tuple<Factors_...>, std::index_sequence<J...>>
337template <
typename Scalar,
typename Space, std::
size_t K,
typename Replacement,
typename Factors_>
338using ReplacedProduct =
typename ReplacedProductOf<Scalar, Space, K, Replacement, Factors_>::type;
356template <ProductFactor F, Space BlockSpace>
360 requires {
typename BlockSpace::BlockType; } && BlockSpace::FixedValueDimension == 0,
361 "onEach<Path>() places a factor on a repeated block"
365 static constexpr int Step = BlockSpace::ValueDimensionStep;
368 static constexpr bool MomentsMayFail = internal::momentsMayFail<F>;
386 : m_factor{std::move(
factor)}
387 , m_space{std::move(
space)}
390 Emrys::valueDimension(m_factor.space()) == Step &&
"the factor must cover one repetition of the block"
394 [[maybe_unused]]
bool const checked = m_factor.toDensity().has_value();
395 EMRYS_FILTER_ASSERT(checked &&
"a factor failed its check; call its toDensity() first to handle this");
400 [[nodiscard]] F
const &
407 [[nodiscard]] BlockSpace
const &
417 return m_space.count();
430 template <
typename Derived>
434 static_assert(Derived::IsVectorAtCompileTime,
"logDensity() expects a vector");
436 decltype(
auto) density = internal::densityOf(m_factor);
440 result +=
Scalar(density.logDensity(x.derived().template segment<Step>(k * Step)));
451 decltype(
auto) density = internal::densityOf(m_factor);
452 auto const & one = density.moments();
453 auto const place = [&](
auto const &
moments) {
455 result.mean().setZero();
456 result.covarianceLower().setZero();
459 result.mean().template segment<Step>(k * Step) =
moments.mean();
461 moments.covarianceLower().template selfadjointView<Eigen::Lower>();
465 if constexpr (MomentsMayFail)
469 return std::unexpected{one.error()};
489template <
typename F,
typename BlockSpace, std::uniform_random_bit_generator G>
493 EMRYS_FILTER_ASSERT(n >= 0);
494 constexpr int Step = BlockSpace::ValueDimensionStep;
496 decltype(
auto) density = internal::densityOf(each.
factor());
497 for (Eigen::Index k = 0; k < each.
count(); ++k)
499 samples.template middleRows<Step>(k * Step) =
drawSamples(density, n, rng);
507template <
typename F,
typename BlockSpace, std::uniform_random_bit_generator G>
511 constexpr int Step = BlockSpace::ValueDimensionStep;
514 decltype(
auto) density = internal::densityOf(each.
factor());
515 for (Eigen::Index k = 0; k < each.
count(); ++k)
526template <
typename F,
typename BlockSpace, std::uniform_random_bit_generator G>
527[[nodiscard]] SamplesWithLogDensity<BlockSpace, typename F::Scalar>
530 EMRYS_FILTER_ASSERT(n >= 0);
531 using Scalar =
typename F::Scalar;
532 constexpr int Step = BlockSpace::ValueDimensionStep;
535 Eigen::Array<Scalar, Eigen::Dynamic, 1>::Zero(n)
537 decltype(
auto) density = internal::densityOf(each.
factor());
538 for (Eigen::Index k = 0; k < each.
count(); ++k)
541 result.samples.template middleRows<Step>(k * Step) = draws.samples;
542 result.logDensity += draws.logDensity;
551template <
typename F,
typename BlockSpace, std::uniform_random_bit_generator G>
552[[nodiscard]] SampleWithLogDensity<BlockSpace, typename F::Scalar>
555 constexpr int Step = BlockSpace::ValueDimensionStep;
558 decltype(
auto) density = internal::densityOf(each.
factor());
559 for (Eigen::Index k = 0; k < each.
count(); ++k)
562 result.sample.template segment<Step>(k * Step) = draw.sample;
563 result.logDensity += draw.logDensity;
572template <
typename Space,
typename Path>
576 using type = PathSubspaceType<Space, Path>;
579 [[nodiscard]]
static type
580 in(Space
const & space)
582 return pathSubspace<Path>(space);
586 [[nodiscard]]
static auto
587 indicesIn(Space
const & space)
594template <
typename Space>
595struct EachBlockOf<Space, WholeSpace>
601 [[nodiscard]]
static Space
const &
602 in(Space
const & space)
608 [[nodiscard]]
static auto
609 indicesIn(Space
const & space)
611 return asIndexSet(Eigen::seqN(Eigen::Index{0},
valueDimension(space)));
618template <ProductFactor F,
typename Path>
619struct PlacedFactor<OnEach<F, Path>>
622 template <
typename Space>
623 using TypeIn = EachRepetition<F, typename EachBlockOf<Space, Path>::type>;
626 template <
typename Space>
627 [[nodiscard]]
static TypeIn<Space>
628 factorIn(OnEach<F, Path> && placed, Space
const & space)
630 return {std::move(placed.value), EachBlockOf<Space, Path>::in(space)};
634 template <
typename Space>
635 [[nodiscard]]
static auto
636 indicesIn(OnEach<F, Path>
const &, Space
const & space)
638 return EachBlockOf<Space, Path>::indicesIn(space);
644 template <
typename Space>
645 static constexpr bool fitsIn = [] {
646 using Block =
typename EachBlockOf<Space, Path>::type;
647 if constexpr (
requires {
typename Block::BlockType; })
649 return factorFits<typename F::SpaceType, typename Block::BlockType>;
660inline constexpr bool isPlacedFactor =
false;
663template <ProductFactor F,
typename Path>
664inline constexpr bool isPlacedFactor<OnPath<F, Path>>{
true};
666template <ProductFactor F,
typename Path>
667inline constexpr bool isPlacedFactor<OnEach<F, Path>>{
true};
691template <
typename... Placed>
694 static_assert(
sizeof...(Placed) > 0,
"a product needs at least one factor");
696 (internal::isPlacedFactor<Placed> && ...),
697 "each factor is placed by tag path, with on<Path>() or onEach<Path>()"
704 : m_placed{std::move(
placed)...}
708 [[nodiscard]] std::tuple<Placed...>
const &
716 std::tuple<Placed...> m_placed;
724inline constexpr bool isFactors =
false;
727template <
typename... Placed>
728inline constexpr bool isFactors<Factors<Placed...>>{
true};
773 static_assert(
sizeof...(Factors_) > 0,
"a product needs at least one factor");
775 (std::is_same_v<typename Factors_::Scalar, Scalar_> && ...),
776 "every factor must have the same scalar"
780 static constexpr bool MomentsMayFail = (internal::momentsMayFail<Factors_> || ...);
806 internal::hasEqualSizes<Space_>,
807 "a product places its factors by coordinate, so its space's values and differences must have the "
812 template <std::
size_t K>
813 using FactorType = std::tuple_element_t<K, std::tuple<Factors_...>>;
818 template <
typename... Placed>
819 requires(
sizeof...(Placed) ==
sizeof...(Factors_)
820 && (std::is_same_v<typename internal::PlacedFactor<Placed>::template TypeIn<Space_>, Factors_> && ...))
822 : m_space{std::move(
space)}
823 , m_indices{resolve<Factors_>(placed)...}
824 , m_factors{internal::PlacedFactor<Placed>::factorIn(std::move(placed), m_space)...}
827 (internal::PlacedFactor<Placed>::template fitsIn<Space_> && ...),
828 "a factor's space must be the space of the block it covers"
830 EMRYS_FILTER_ASSERT(sizesMatch() &&
"a factor's dimension must match the number of coordinates it covers");
831 EMRYS_FILTER_ASSERT(partitionsSpace() &&
"the factors' indices must partition the space");
833 [](
auto const &... factors) {
834 (checkParams(factors), ...);
841 template <
typename... Placed>
843 :
Product{std::move(
space), factors, std::index_sequence_for<Placed...>{}}
861 [[nodiscard]] Space_
const &
868 template <std::
size_t K>
869 [[nodiscard]] FactorType<K>
const &
872 return std::get<K>(m_factors);
876 template <std::
size_t K>
877 [[nodiscard]]
auto const &
880 return std::get<K>(m_indices);
886 template <
typename Fn>
890 [&]<std::size_t... K>(std::index_sequence<K...>) {
891 (fn(internal::densityOf(std::get<K>(m_factors)), std::get<K>(m_indices)), ...);
892 }(std::index_sequence_for<Factors_...>{});
896 template <
typename Derived>
900 static_assert(Derived::IsVectorAtCompileTime,
"logDensity() expects a vector");
913 template <
typename Derived>
915 density(Eigen::MatrixBase<Derived>
const & x)
const
928 result.mean().setZero();
929 result.covarianceLower().setZero();
930 auto error = std::optional<MomentsError>{};
931 auto const place = [&](
auto const &
moments,
auto const &
indices) {
932 using FactorMatrix = std::remove_cvref_t<
decltype(
moments.covarianceLower())>;
935 FactorMatrix{
moments.covarianceLower().template selfadjointView<Eigen::Lower>()};
942 auto const & factorMoments =
density.moments();
943 if constexpr (internal::isExpected<std::remove_cvref_t<
decltype(factorMoments)>>)
947 error = factorMoments.error();
951 place(*factorMoments,
indices);
959 if constexpr (MomentsMayFail)
963 return std::unexpected{*error};
977 template <
typename Path>
978 [[nodiscard]]
decltype(
auto)
981 return internal::withPathTags<Path>([&]<
typename... Tags>() ->
decltype(
auto) {
982 return marginalAlong<Tags...>();
987 template <
typename Path>
1003 template <typename GivenPath, typename Derived>
1007 return internal::withPathTags<GivenPath>([&]<
typename... Tags>() {
1008 return conditionalAlong<Tags...>(values);
1015 template <
typename... Placed, std::size_t... K>
1017 :
Product{std::move(space), std::get<K>(factors.placed())...}
1021 template <
typename... Path>
1022 [[nodiscard]]
decltype(
auto)
1023 marginalAlong()
const
1025 using Match = MatchType<Path...>;
1026 if constexpr (Match::value.factor != None)
1028 assertOnOwnBlock<Match::value.factor>(OwnBlockPath<Match::value, Path...>{});
1029 if constexpr (Match::value.whole)
1031 return std::get<Match::value.factor>(m_factors);
1035 return factorMarginal(
1036 std::get<Match::value.factor>(m_factors),
1037 internal::DropFront<Match::value.start, Path...>{}
1044 std::ranges::count(withinOf<Path...>(),
true) > 0,
1045 "the path neither reaches into a factor nor contains one"
1047 auto const target = internal::resolveIndices<ValueDimensionAtCompileTime, MaxValueDimensionAtCompileTime>(
1051 EMRYS_FILTER_ASSERT(
1052 coversExactly(withinOf<Path...>(), target) &&
"the path's block must be made of whole factors"
1054 return keepOnly<withinOf<Path...>()>(target, internal::subspace<Space_, Path...>(m_space));
1059 template <
typename... GivenPath,
typename Derived>
1061 conditionalAlong(Eigen::MatrixBase<Derived>
const & values)
const
1063 return internal::tagConditional<
TagPath<GivenPath...>>(
1065 [&](
auto const & targetCoordinates,
auto const & givenCoordinates,
auto targetSpace,
auto const &) {
1067 auto const & target = targetCoordinates.values;
1068 auto const &
given = givenCoordinates.values;
1069 EMRYS_FILTER_ASSERT(values.size() ==
given.size());
1070 using Match = MatchType<GivenPath...>;
1071 if constexpr (Match::value.factor != None && !Match::value.whole)
1073 assertOnOwnBlock<Match::value.factor>(OwnBlockPath<Match::value, GivenPath...>{});
1074 return replaceFactor<Match::value.factor>(
1077 std::move(targetSpace),
1078 internal::DropFront<Match::value.start, GivenPath...>{},
1085 std::ranges::count(droppedOf<GivenPath...>(),
true) > 0,
1086 "the path neither reaches into a factor nor contains one"
1089 std::ranges::count(droppedOf<GivenPath...>(),
true) < std::ptrdiff_t(FactorCount),
1090 "conditioning on every factor leaves nothing"
1092 EMRYS_FILTER_ASSERT(
1093 coversExactly(droppedOf<GivenPath...>(),
given)
1094 &&
"the given block must be made of whole factors"
1096 return keepOnly<complement(droppedOf<GivenPath...>())>(target, std::move(targetSpace));
1102 static constexpr std::size_t None = FactorCount;
1109 std::size_t factor = None;
1110 std::size_t start = 0;
1118 template <PathMatch Match,
typename... Path>
1119 using OwnBlockPath = std::conditional_t<
1121 internal::TakeFront<Match.start + 1, Path...>,
1122 internal::TypeList<
typename FactorType<Match.factor>::SpaceType>>;
1125 template <
typename T>
1126 static consteval std::size_t
1129 constexpr auto same = std::array<bool, FactorCount>{std::is_same_v<T, typename Factors_::SpaceType>...};
1130 static_assert(std::ranges::count(same,
true) <= 1,
"two factors share this space type, so it names neither");
1131 auto const found = std::ranges::find(same,
true);
1132 return found == same.end() ? None : std::size_t(found - same.begin());
1136 template <
typename T>
1137 static consteval std::size_t
1140 constexpr auto inside =
1141 std::array<bool, FactorCount>{(internal::countTag<T, typename Factors_::SpaceType>() > 0)...};
1142 static_assert(std::ranges::count(inside,
true) <= 1,
"this tag lies in more than one factor's space");
1143 auto const found = std::ranges::find(inside,
true);
1144 return found == inside.end() ? None : std::size_t(found - inside.begin());
1148 template <
typename T>
1149 static consteval std::array<bool, FactorCount>
1152 return {(internal::countTag<typename Factors_::SpaceType, T>() > 0)...};
1158 template <
typename... Path>
1159 static consteval PathMatch
1162 constexpr auto named = std::array<std::size_t,
sizeof...(Path)>{factorNamed<Path>()...};
1163 for (std::size_t j = 0; j < named.size(); ++j)
1165 if (named[j] != None)
1167 return {named[j], j, j + 1 == named.size(),
true};
1170 return {factorContaining<std::tuple_element_t<0, std::tuple<Path...>>>(), 0,
false};
1176 template <PathMatch Match,
typename Last>
1177 static consteval std::array<bool, FactorCount>
1180 if constexpr (Match.factor != None)
1182 auto result = std::array<bool, FactorCount>{};
1183 result[Match.factor] =
true;
1188 return factorsWithin<Last>();
1196 template <
typename... Path>
1197 using MatchType = std::integral_constant<PathMatch, matchPath<Path...>()>;
1200 template <
typename... Path>
1201 using LastTag = std::tuple_element_t<
sizeof...(Path) - 1, std::tuple<Path...>>;
1204 template <
typename... Path>
1205 static consteval std::array<bool, FactorCount>
1208 return factorsWithin<LastTag<Path...>>();
1212 template <
typename... Path>
1213 static consteval std::array<bool, FactorCount>
1216 return droppedBy<MatchType<Path...>::value, LastTag<Path...>>();
1220 static consteval std::array<bool, FactorCount>
1221 complement(std::array<bool, FactorCount> mask)
1223 for (
bool & b : mask)
1231 template <std::array<
bool, FactorCount> Mask>
1232 static consteval auto
1235 auto result = std::array<std::size_t, std::size_t(std::ranges::count(Mask,
true))>{};
1236 std::size_t out = 0;
1237 for (std::size_t k = 0; k < FactorCount; ++k)
1250 template <
typename Factor>
1252 checkParams(Factor
const & factor)
1256 [[maybe_unused]]
bool const checked = factor.toDensity().has_value();
1257 EMRYS_FILTER_ASSERT(checked &&
"a factor failed its check; call its toDensity() first to handle this");
1264 template <
typename Factor,
typename Placed>
1265 [[nodiscard]] internal::IndexVector<Factor::ValueDimensionAtCompileTime, Factor::MaxValueDimensionAtCompileTime>
1266 resolve(Placed
const & placed)
const
1268 return internal::IndexVector<Factor::ValueDimensionAtCompileTime, Factor::MaxValueDimensionAtCompileTime>{
1269 internal::resolveIndices<ValueDimensionAtCompileTime, MaxValueDimensionAtCompileTime>(
1271 internal::PlacedFactor<Placed>::indicesIn(placed, m_space)
1277 template <
typename Fn>
1279 forEachStored(Fn && fn)
const
1281 [&]<std::size_t... K>(std::index_sequence<K...>) {
1282 (fn(std::get<K>(m_factors), std::get<K>(m_indices)), ...);
1283 }(std::index_sequence_for<Factors_...>{});
1291 forEachStored([&](
auto const & factor,
auto const & indices) {
1299 partitionsSpace()
const
1302 forEachStored([&](
auto const &,
auto const & indices) {
1303 total += indices.size();
1305 bool const distinct = std::apply(
1306 [](
auto const &... indices) {
1307 return internal::distinctIndices(indices...);
1317 template <std::size_t K,
typename... Path>
1319 assertOnOwnBlock(internal::TypeList<Path...>)
const
1321 [[maybe_unused]]
auto const block =
1322 internal::resolveIndices<ValueDimensionAtCompileTime, MaxValueDimensionAtCompileTime>(
1326 EMRYS_FILTER_ASSERT(
1327 std::equal(
block.begin(),
block.end(), std::get<K>(m_indices).begin(), std::get<K>(m_indices).end())
1328 &&
"a factor reached by a tag path must be placed on that tag's block"
1335 template <
typename Block>
1337 coversExactly(std::array<bool, FactorCount>
const & mask, Block
const &
block)
const
1340 std::size_t covered = 0;
1341 bool inBlock =
true;
1342 forEachStored([&](
auto const &,
auto const & indices) {
1345 covered += std::size_t(indices.size());
1346 for (Index
const i : indices)
1348 inBlock = inBlock && std::ranges::find(
block, i) != std::ranges::end(
block);
1352 return inBlock && covered == std::size_t(std::ranges::size(
block));
1358 template <
typename Factor,
typename... Path>
1359 [[nodiscard]]
static auto
1360 factorMarginal(Factor
const & factor, internal::TypeList<Path...>)
1363 requires { factor.template marginal<
TagPath<Path...>>(); },
1364 "this factor has no marginal<Path>()"
1366 return factor.template marginal<
TagPath<Path...>>();
1372 template <std::array<
bool, FactorCount> Keep,
typename Target,
typename SubSpace>
1373 [[nodiscard]]
decltype(
auto)
1374 keepOnly(Target
const & target, SubSpace space)
const
1376 constexpr auto kept = maskedFactors<Keep>();
1377 if constexpr (kept.size() == 1)
1379 return std::get<kept[0]>(m_factors);
1383 return [&]<std::size_t... J>(std::index_sequence<J...>) {
1386 internal::placedAt(positionsOf<kept[J]>(target), std::get<kept[J]>(m_factors))...
1388 }(std::make_index_sequence<kept.size()>{});
1393 template <std::
size_t K,
typename Target>
1395 positionsOf(Target
const & target)
const
1397 using Factor = FactorType<K>;
1398 return internal::positionsIn<Factor::ValueDimensionAtCompileTime, Factor::MaxValueDimensionAtCompileTime>(
1399 std::get<K>(m_indices),
1407 template <std::size_t K,
typename Target,
typename Given,
typename SubSpace,
typename... Path,
typename Derived>
1410 Target
const & target,
1411 Given
const &
given,
1413 internal::TypeList<Path...>,
1414 Eigen::MatrixBase<Derived>
const & values
1417 auto const & factor = std::get<K>(m_factors);
1419 requires { factor.template conditional<
TagPath<Path...>>(values); },
1420 "this factor has no conditional<Path>()"
1422 if constexpr (FactorCount == 1)
1424 return factor.template conditional<
TagPath<Path...>>(values);
1428 using Raw =
decltype(factor.template conditional<
TagPath<Path...>>(values));
1429 using Replacement = internal::ConditionalValue<Raw>;
1430 using Error = internal::ConditionalError<Raw>;
1432 using Result = internal::ReplacedProduct<Scalar, SubSpace, K, Replacement, std::tuple<Factors_...>>;
1434 auto const build = [&](Replacement replacement) {
1436 auto const & own = std::get<K>(m_indices);
1437 auto const isRemaining = [&](Index i) {
1438 return std::ranges::find(
given, i) == std::ranges::end(
given);
1440 auto remaining = internal::IndexVector<
1441 Replacement::ValueDimensionAtCompileTime,
1442 Replacement::MaxValueDimensionAtCompileTime>{};
1443 remaining.resize(Index(std::ranges::count_if(own, isRemaining)));
1445 for (Index
const i : own)
1452 auto positions = internal::positionsIn<
1453 Replacement::ValueDimensionAtCompileTime,
1454 Replacement::MaxValueDimensionAtCompileTime>(remaining, target);
1455 return [&]<std::size_t... J>(std::index_sequence<J...>) {
1456 return Result{std::move(space), placeFactor<J, K>(target, positions, replacement)...};
1457 }(std::index_sequence_for<Factors_...>{});
1460 auto raw = factor.template conditional<
TagPath<Path...>>(values);
1461 if constexpr (std::is_void_v<Error>)
1463 return build(std::move(raw));
1467 using Return = std::expected<Result, Error>;
1468 if constexpr (internal::isExpected<Raw>)
1472 return Return{std::unexpect, raw.error()};
1474 return Return{build(std::move(*raw))};
1478 if (
auto checked = raw.toDensity(); !checked)
1480 return Return{std::unexpect, checked.error()};
1482 return Return{build(std::move(raw))};
1491 template <std::
size_t J, std::
size_t K,
typename Target,
typename Positions,
typename Replacement>
1493 placeFactor(Target
const & target, Positions
const & positions, Replacement & replacement)
const
1495 if constexpr (J == K)
1497 return internal::placedAt(positions, std::move(replacement));
1501 return internal::placedAt(positionsOf<J>(target), std::get<J>(m_factors));
1509 internal::IndexVector<Factors_::ValueDimensionAtCompileTime, Factors_::MaxValueDimensionAtCompileTime>...>
1512 std::tuple<Factors_...> m_factors;
1516template <
typename Space,
typename First,
typename... Rest>
1517Product(Space, First, Rest...) -> Product<
1519 typename internal::PlacedFactor<First>::template TypeIn<Space>::Scalar,
1520 typename internal::PlacedFactor<First>::template TypeIn<Space>,
1521 typename internal::PlacedFactor<Rest>::template TypeIn<Space>...>;
1523template <
typename Space,
typename First,
typename... Rest>
1524Product(Space, Factors<First, Rest...>) -> Product<
1526 typename internal::PlacedFactor<First>::template TypeIn<Space>::Scalar,
1527 typename internal::PlacedFactor<First>::template TypeIn<Space>,
1528 typename internal::PlacedFactor<Rest>::template TypeIn<Space>...>;
1538template <
typename Scalar,
typename Space,
typename... Factors_, std::uniform_random_bit_generator G>
1539[[nodiscard]] SampleSet<Space, Scalar>
1542 EMRYS_FILTER_ASSERT(n >= 0);
1544 product.
forEachFactor([&](
auto const & density,
auto const & indices) {
1545 samples(indices, Eigen::placeholders::all) =
drawSamples(density, n, rng);
1554template <
typename Scalar,
typename Space,
typename... Factors_, std::uniform_random_bit_generator G>
1555[[nodiscard]]
typename Moments<Space, Scalar>::VectorType
1560 product.
forEachFactor([&](
auto const & density,
auto const & indices) {
1572template <
typename Scalar,
typename Space,
typename... Factors_, std::uniform_random_bit_generator G>
1573[[nodiscard]] SamplesWithLogDensity<Space, Scalar>
1576 EMRYS_FILTER_ASSERT(n >= 0);
1579 Eigen::Array<Scalar, Eigen::Dynamic, 1>::Zero(n)
1581 product.
forEachFactor([&](
auto const & density,
auto const & indices) {
1583 result.samples(indices, Eigen::placeholders::all) = draws.samples;
1584 result.logDensity += draws.logDensity;
1594template <
typename Scalar,
typename Space,
typename... Factors_, std::uniform_random_bit_generator G>
1595[[nodiscard]] SampleWithLogDensity<Space, Scalar>
1600 product.
forEachFactor([&](
auto const & density,
auto const & indices) {
1602 result.sample(indices) = draw.sample;
1603 result.logDensity += draw.logDensity;
What marginals and conditionals are built from: resolving Eigen index sets against a space; the share...
The macros every header includes first.
Mathematical constants and scalar functions that work in every scalar type the library accepts,...
Moments: the mean and covariance that a Gaussian carries and that a mixture or a sample set is moment...
NumericError, the reasons a factorization or a normalization can fail, and its two names,...
SampleSet: a matrix whose columns are samples in a space, which the samplers return and the unscented...
Drawing samples: SamplesWithLogDensity and SampleWithLogDensity, the Gaussian draws drawSamples(),...
The Space concept and what every continuous space shares (decisions.md [sizes-and-dimensions]): the t...
Subspaces, and growing and shrinking blocks (decisions.md [several-resizable-blocks]).
Tag paths and the index utilities (decisions.md [tag-addressing], [index-names]): TagPath and TagPath...
One factor on every repetition of a repeated block: the product of independent copies of a density,...
Definition Product.h:358
Eigen::Index Index
Eigen's index type.
Definition Product.h:373
BlockSpace SpaceType
the space the values live in
Definition Product.h:374
Moments< BlockSpace, Scalar > MomentsType
a mean and covariance together
Definition Product.h:375
typename MomentsType::VectorType VectorType
a value
Definition Product.h:376
EachRepetition(F factor, BlockSpace space)
factor on each repetition of space.
Definition Product.h:385
Scalar logDensity(Eigen::MatrixBase< Derived > const &x) const
Definition Product.h:432
auto moments() const -> std::conditional_t< MomentsMayFail, std::expected< MomentsType, MomentsError >, MomentsType >
Definition Product.h:449
typename F::Scalar Scalar
the scalar type
Definition Product.h:372
static constexpr int MaxValueDimensionAtCompileTime
Definition Product.h:382
static constexpr int ValueDimensionAtCompileTime
Definition Product.h:379
F const & factor() const
Definition Product.h:401
Index valueDimension() const
Definition Product.h:422
Index count() const
Definition Product.h:415
BlockSpace const & space() const
Definition Product.h:408
The factors of a product, each placed by tag path with on() or onEach(), in no space yet: a Product o...
Definition Product.h:693
Factors(Placed... placed)
The factors placed.
Definition Product.h:703
std::tuple< Placed... > const & placed() const
Definition Product.h:709
First and second moments (mean and covariance) of a distribution.
Definition Moments.h:55
DifferenceMatrix< Space_, Space_, Scalar > MatrixType
Definition Moments.h:76
ValueVector< Space_, Scalar > VectorType
Definition Moments.h:74
static constexpr int MaxDifferenceDimensionAtCompileTime
Definition Moments.h:72
void resize(Index valueDimension, Index differenceDimension)
Resizes the mean to valueDimension coordinates and the covariance to differenceDimension rows and col...
Definition Moments.h:126
static constexpr int DifferenceDimensionAtCompileTime
Definition Moments.h:69
static constexpr int MaxValueDimensionAtCompileTime
Definition Moments.h:66
static constexpr int ValueDimensionAtCompileTime
Definition Moments.h:63
The product of independent densities, each on its own coordinates of a space.
Definition Product.h:772
auto moments() const -> std::conditional_t< MomentsMayFail, std::expected< MomentsType, MomentsError >, MomentsType >
Definition Product.h:925
Moments< Space_, Scalar_ > MomentsType
Definition Product.h:787
auto conditional(Eigen::MatrixBase< Derived > const &values) const
Definition Product.h:1005
auto const & indices() const
Definition Product.h:878
Index differenceDimension() const
Definition Product.h:855
typename MomentsType::MatrixType MatrixType
Definition Product.h:789
void forEachFactor(Fn &&fn) const
Calls fn(density, indices) for each factor in order, with its density (a view, for parameters) and th...
Definition Product.h:888
Scalar logDensity(Eigen::MatrixBase< Derived > const &x) const
Definition Product.h:898
Product(Space_ space, Placed... placed)
The product of the factors placed, made by on() or onEach(), in space.
Definition Product.h:821
std::tuple_element_t< K, std::tuple< Factors_... > > FactorType
Definition Product.h:813
static constexpr int MaxDifferenceDimensionAtCompileTime
Definition Product.h:801
decltype(auto) marginal() const &
Definition Product.h:979
typename MomentsType::VectorType VectorType
Definition Product.h:788
Scalar density(Eigen::MatrixBase< Derived > const &x) const
Definition Product.h:915
Index valueDimension() const
Definition Product.h:848
static constexpr int ValueDimensionAtCompileTime
Definition Product.h:792
FactorType< K > const & factor() const
Definition Product.h:870
Eigen::Index Index
Definition Product.h:785
Space_ const & space() const
Definition Product.h:862
Scalar_ Scalar
Definition Product.h:784
static constexpr int DifferenceDimensionAtCompileTime
Definition Product.h:798
static constexpr std::size_t FactorCount
Definition Product.h:803
static constexpr int MaxValueDimensionAtCompileTime
Definition Product.h:795
void marginal() const &&=delete
A marginal of a temporary would outlive it.
Product(Space_ space, Factors< Placed... > const &factors)
The product of factors placed in space (see Factors).
Definition Product.h:842
Space_ SpaceType
Definition Product.h:786
A density: a type that evaluates its log-density at a value in its space, such as a Gaussian,...
Definition Product.h:40
What a Product takes as a factor: a density (HasLogDensity), or parameters that toDensity() checks,...
Definition Product.h:79
A type usable as the scalar of a distribution: a real number type such as float, double,...
Definition Math.h:80
A type usable as the space of a distribution.
Definition Space.h:186
#define EMRYS_FILTER_NO_UNIQUE_ADDRESS
Assertion used for programmer errors (misuse of the API).
Definition Macros.h:38
MomentsError
Reasons a distribution's moments() can fail.
Definition Moments.h:32
SampleWithLogDensity< Space, Scalar > drawSampleWithLogDensity(Gamma< Space, Scalar > const &gamma, G &rng)
Definition Gamma.h:546
Eigen::Matrix< Scalar, valueDimensionAtCompileTime< Space >, Eigen::Dynamic,(maxValueDimensionAtCompileTime< Space >==1 ? Eigen::RowMajor :Eigen::ColMajor), maxValueDimensionAtCompileTime< Space >, Eigen::Dynamic > SampleSet
A matrix whose columns are samples in Space (see Spaces), with the space's size and storage bound.
Definition SampleSet.h:33
Eigen::Index drawSample(Categorical< Space, Scalar > const &distribution, G &rng)
Definition Categorical.h:1111
std::vector< Eigen::Index > drawSamples(Categorical< Space, Scalar > const &distribution, Eigen::Index n, G &rng)
Definition Categorical.h:1087
SamplesWithLogDensity< Space, Scalar > drawSamplesWithLogDensity(Gamma< Space, Scalar > const &gamma, Eigen::Index n, G &rng)
Definition Gamma.h:529
GivenBlock< Space, P, Value > given(Space const &space, Value const &value)
Definition Measurement.h:917
Sample< std::remove_cvref_t< G > > sample(G &&function)
Definition Policies.h:665
Eigen::Index valueDimension(S const &space)
Definition Space.h:272
auto block(Space auto const &space, X &&x)
Definition TagPath.h:979
Eigen::Index differenceDimension(S const &space)
Definition Space.h:284
constexpr bool isLinear
Whether S is linear: its values and its differences are both plain vectors.
Definition Space.h:321
constexpr auto idx()
Definition TagPath.h:658
One sample in Space, in a vector sized by the space, together with the log of the density it was draw...
Definition Sampling.h:50
Moments< Space, Scalar >::VectorType sample
the sample
Definition Sampling.h:51
Samples in Space together with the log of the density they were drawn from, evaluated at each.
Definition Sampling.h:36
A path of tags, each naming a block inside the one before: TagPath<Ownship, Position> is the Position...
Definition TagPath.h:353