38template <
internal::ComponentOrInfoForm Component_, DiscreteSpace ModeSpace_,
typename Allocator_ = DefaultAllocator>
84template <
internal::ComponentOrInfoForm Component_, DiscreteSpace ModeSpace_,
typename Allocator_ = DefaultAllocator>
89 "a Gaussian in an information form is not a hybrid's conditional, having no collapse; convert each "
90 "with toGaussian() or toSqrt() and hold a Gaussian or a SqrtGaussian (decisions.md [gaussian-forms])"
96 using Scalar =
typename ComponentType::Scalar;
97 using SpaceType =
typename ComponentType::SpaceType;
123 : m_modes{std::move(
modes)}
124 , m_conditionals(std::size_t(m_modes.cardinality()),
conditional, ComponentAllocator(allocator))
129 : m_modes{std::move(
modes)}
130 , m_conditionals{std::move(conditionals)}
136 template <
typename Conditionals>
138 : m_modes{std::move(
modes)}
139 , m_conditionals(conditionals.begin(), conditionals.end(), ComponentAllocator(allocator))
146 : m_modes{other.m_modes}
147 , m_conditionals{other.m_conditionals, ComponentAllocator(allocator)}
152 : m_modes{std::move(other.m_modes)}
153 , m_conditionals{std::move(other.m_conditionals), ComponentAllocator(allocator)}
155 other.m_stamp.touchShape();
182 return m_conditionals.front().space();
186 [[nodiscard]] ModeSpace_
const &
189 return m_modes.space();
193 [[nodiscard]] Eigen::Index
196 return m_modes.cardinality();
200 [[nodiscard]] Eigen::Index
203 return m_conditionals.front().valueDimension();
207 [[nodiscard]] Eigen::Index
210 return m_conditionals.front().differenceDimension();
225 m_stamp.touchValues();
226 m_modes = std::move(
modes);
233 EMRYS_FILTER_ASSERT(mode >= 0 && mode <
size() &&
"the mode is out of range");
234 return m_conditionals[std::size_t(mode)];
247 conditionalToSet(mode, component) = component;
254 conditionalToSet(mode, component) = std::move(component);
260 template <
typename F>
261 requires std::invocable<F &, ComponentType &>
265 EMRYS_FILTER_ASSERT(mode >= 0 && mode <
size() &&
"the mode is out of range");
266 m_stamp.touchValues();
267 return internal::keepingSpace(m_conditionals[std::size_t(mode)], f);
274 template <
typename... Values,
typename... Paths, std::size_t... N>
275 requires(
sizeof...(Values) +
sizeof...(Paths) > 0)
283 template <
typename... Values,
typename... Paths, std::size_t... N>
284 requires(
sizeof...(Values) +
sizeof...(Paths) > 0)
294 EMRYS_FILTER_ASSERT(Eigen::Index(conditionals.size()) ==
size() &&
"give one component per mode");
296 conditionals.get_allocator() == m_conditionals.get_allocator()
297 &&
"the components must come from an equal allocator"
299 m_stamp.touchShape();
300 m_conditionals.swap(conditionals);
310 template <
typename Path>
314 return internal::tagMarginal<MixtureMarginal, Path>(*
this);
318 template <
typename Path>
323 template <typename Path>
327 return internal::elementMarginal<MixtureMarginal, Path>(*
this, element);
331 template <
typename Path>
343 for (Eigen::Index m = 0; m <
size(); ++m)
345 mixture.add(m_modes.logWeight(m), m_conditionals[std::size_t(m)]);
360 [[nodiscard]] std::expected<void, NumericError>
363 if (
auto const total = m_modes.logTotalWeight(); !total)
365 return std::unexpected{total.error()};
369 if (
auto result =
conditional.factorize(); !result)
371 return std::unexpected{result.error()};
386 template <
typename R>
387 [[nodiscard]] std::expected<void, NumericError>
390 m_stamp.touchValues();
391 if (
auto const total = m_modes.logTotalWeight(); !total)
393 return std::unexpected{total.error()};
402 if (
auto result = trial.factorize(repair); !result)
404 return std::unexpected{result.error()};
410 if (
auto result =
conditional.factorize(repair); !result)
412 return std::unexpected{result.error()};
422 [[nodiscard]] std::expected<DensityType, NumericError>
427 return std::unexpected{result.error()};
441 template <typename R>
445 if (
auto result =
factorize(repair); !result)
447 return std::unexpected{result.error()};
453 template <
typename R>
461 friend class internal::ValuesCheck;
465 friend class internal::ShapeCheck;
467 using ComponentAllocator = internal::ReBound<Allocator_, ComponentType>;
473 conditionalToSet(Eigen::Index mode, [[maybe_unused]]
ComponentType const & component)
475 EMRYS_FILTER_ASSERT(mode >= 0 && mode <
size() &&
"the mode is out of range");
476 EMRYS_FILTER_ASSERT(component.space() ==
space() &&
"the component must be in the hybrid's space");
477 m_stamp.touchValues();
478 return m_conditionals[std::size_t(mode)];
486 Eigen::Index(m_conditionals.size()) == m_modes.
cardinality() &&
"give one component per mode"
491 conditional.space() == m_conditionals.front().space()
492 &&
"every mode's component must be on the same space"
499 internal::Stamp m_stamp;
526template <
internal::ComponentOrInfoForm Component_, DiscreteSpace ModeSpace_,
typename Allocator_>
558 return source().space();
562 [[nodiscard]] ModeSpace_
const &
565 return source().modeSpace();
569 [[nodiscard]] Eigen::Index
572 return source().size();
576 [[nodiscard]] Eigen::Index
579 return source().valueDimension();
583 [[nodiscard]] Eigen::Index
586 return source().differenceDimension();
593 return source().get_allocator();
600 return source().modes();
607 return source().conditional(mode);
613 template <
typename Derived>
621 template <
typename Derived>
623 density(Eigen::MatrixBase<Derived>
const & x)
const
651 template <
typename P>
655 ParamsType
const & hybrid = source();
656 auto const [stride, axis] = internal::locateAxisByPath<P>(
modeSpace());
657 using Axis = std::remove_cvref_t<
decltype(*axis)>;
659 using LogWeights =
typename ModesType::ArrayType;
660 Eigen::Index
const count = axis->cardinality();
661 typename Result::ConditionalsType grouped(internal::ReBound<Allocator_, ComponentType>(hybrid.get_allocator()));
662 grouped.reserve(std::size_t(count));
663 auto const componentAt = [&](Eigen::Index m) ->
ComponentType const & {
664 return hybrid.conditional(m);
666 for (Eigen::Index value = 0; value < count; ++value)
668 LogWeights logWeights = hybrid.modes().logWeights();
669 for (Eigen::Index m = 0; m <
size(); ++m)
671 if ((m / stride) % count != value)
673 logWeights(m) = -Eigen::NumTraits<Scalar>::infinity();
677 if (!internal::logTotalWeight<Scalar>(logWeights))
679 logWeights = LogWeights::Constant(
size(), -Eigen::NumTraits<Scalar>::infinity());
680 for (Eigen::Index m = 0; m <
size(); ++m)
682 if ((m / stride) % count == value)
684 logWeights(m) =
Scalar(0);
689 return logWeights(m);
692 return Result{hybrid.modes().template marginal<P>(), std::move(grouped)};
710 return m_check.get();
713 internal::ValuesCheck<ParamsType> m_check;
717template <
typename Scalar,
typename ModeSpace,
typename C>
721template <
typename Scalar,
typename ModeSpace,
typename C,
typename Allocator>
725template <
typename Scalar,
typename ModeSpace,
typename C,
typename ComponentAllocator>
741template <Space Space_, DiscreteSpace ModeSpace_, RealScalar Scalar_ =
double,
typename Allocator_ = DefaultAllocator>
753template <Space Space_, DiscreteSpace ModeSpace_, RealScalar Scalar_ =
double,
typename Allocator_ = DefaultAllocator>
757template <Component Component_, DiscreteSpace ModeSpace_,
typename Allocator_>
761 using Scalar =
typename Component_::Scalar;
766 template <
typename Selection,
typename SubSpace>
773 template <
typename Derived>
774 [[nodiscard]]
static Scalar
779 for (Eigen::Index m = 0; m < hybrid.
size(); ++m)
782 if (logWeight == -Eigen::NumTraits<Scalar>::infinity())
786 total.add(logWeight);
789 return sum.
value() - total.value();
801 template <
typename ComponentAt,
typename LogWeightAt>
802 [[nodiscard]]
static Type
803 collapse(Eigen::Index count, ComponentAt componentAt, LogWeightAt logWeightAt)
805 EMRYS_FILTER_ASSERT(count > 0 &&
"a collapse needs a component");
806 Type const & first = componentAt(0);
807 Eigen::Index
const modes = first.
size();
808 auto logModes =
typename Type::ModesType::ArrayType{};
809 logModes.resize(modes);
810 for (Eigen::Index m = 0; m < modes; ++m)
813 for (Eigen::Index c = 0; c < count; ++c)
816 componentAt(c).modeSpace() == first.
modeSpace() &&
"every hybrid must be on one mode space"
820 logModes(m) = sum.
value();
825 conditionals.reserve(std::size_t(modes));
826 for (Eigen::Index m = 0; m < modes; ++m)
828 if (logModes(m) == -Eigen::NumTraits<Scalar>::infinity())
833 conditionals.push_back(
837 return componentAt(c).conditional(m);
839 [&](Eigen::Index c) {
847 static_cast<void>(collapsedModes.normalize());
848 return Type{std::move(collapsedModes), std::move(conditionals)};
860 return hybrid.conditional(m);
862 [&](Eigen::Index m) {
863 return hybrid.modes().logWeight(m);
871 [[nodiscard]]
static typename Type::MomentsType
881 [[nodiscard]]
static Scalar
885 EMRYS_FILTER_ASSERT(total &&
"a hybrid's mode weights must define a distribution to collapse it");
894template <Component Component_, DiscreteSpace ModeSpace_,
typename Allocator_>
895struct ElementsOf<HybridParams<Component_, ModeSpace_, Allocator_>>
897 using Type = HybridParams<Component_, ModeSpace_, Allocator_>;
900 template <
typename ComponentParams>
901 using CopyType = HybridParams<Density<ComponentParams>, ModeSpace_, Allocator_>;
904 [[nodiscard]]
static auto
905 logWeight(Type
const & hybrid, Eigen::Index m)
907 return hybrid.modes().logWeight(m);
911 [[nodiscard]]
static auto const &
912 component(Type
const & hybrid, Eigen::Index m)
914 return hybrid.conditional(m);
920 template <
typename Marginal>
921 [[nodiscard]]
static auto
922 copy(Type
const & hybrid, Marginal
const & marginal, Allocator_
const & allocator)
924 using Result = CopyType<typename Marginal::ComponentMarginalType::ParamsType>;
926 typename Result::ConditionalsType(ReBound<Allocator_, typename Result::ComponentType>(allocator));
927 conditionals.reserve(std::size_t(marginal.size()));
928 for (
auto const & element : marginal)
930 conditionals.push_back(element.component.copy());
932 return Result{hybrid.modes(), std::move(conditionals)};
940#ifndef EMRYS_FILTER_NO_IO
952template <
typename Component_,
typename ModeSpace_,
typename Allocator_>
954describe(std::ostream & stream, HybridParams<Component_, ModeSpace_, Allocator_>
const & hybrid, Indent indent)
956 stream << indent <<
"hybrid of ";
957 printCount(stream, hybrid.size(),
"mode");
958 printDimension(stream, hybrid.valueDimension(), hybrid.differenceDimension());
959 auto const total = hybrid.modes().logTotalWeight();
965 ComponentTraits<HybridParams<Component_, ModeSpace_, Allocator_>>::moments(hybrid)
971 describe(stream, total.error(), indent.deeper());
973 for (Eigen::Index mode = 0; mode < hybrid.size(); ++mode)
975 auto const logWeight = hybrid.modes().logWeight(mode);
976 stream <<
'\n' << indent.deeper() <<
"mode " << mode;
979 stream <<
", probability " << Eigen::numext::exp(logWeight - *total) <<
":\n";
983 stream <<
", log-weight " << logWeight <<
":\n";
985 describe(stream, hybrid.conditional(mode), indent.deeper().deeper());
The allocator conventions of decisions.md [allocation]: DefaultAllocator, Capacity,...
The distribution over a discrete space (decisions.md [discrete-spaces], [params-and-density]): Catego...
What a container of several Gaussians needs of each one (decisions.md [component-first]): the Compone...
Discrete spaces (decisions.md [discrete-spaces]): the DiscreteSpace concept; Finite,...
The Gaussian: its parameters GaussianParams, the Gaussian that evaluates the density,...
The macros every header includes first.
Mathematical constants and scalar functions that work in every scalar type the library accepts,...
The mixture: the parameters MixtureParams of weighted components of one type (decisions....
Printing: operator<< and std::formatter for every distribution, every filter (which prints its name a...
The Space concept and what every continuous space shares (decisions.md [sizes-and-dimensions]): the t...
What parameters and their views share (decisions.md [view-stamp], [params-and-density]): Stamp,...
Weighted statistics over points, all in internal, which the containers of weighted elements (Gaussian...
Log-weights: the WeightError a normalization can fail with (NumericError.h), and the streaming log-su...
The parameters of a probability distribution over a discrete space: one weight per value.
Definition Categorical.h:257
Space_ const & space() const
Definition Categorical.h:330
Eigen::Index cardinality() const
Definition Categorical.h:337
Scalar logWeight(Eigen::Index value) const
Definition Categorical.h:351
std::expected< Scalar, WeightError > logTotalWeight() const
Definition Categorical.h:361
The parameters of a hybrid state: a discrete mode, and a component conditioned on each mode.
Definition Hybrid.h:86
Allocator_ allocator_type
the allocator the components come from
Definition Hybrid.h:101
void setConditional(Eigen::Index mode, ComponentType const &component)
Replaces the component given the mode with flat index mode with component, which must be in the hybri...
Definition Hybrid.h:245
std::expected< void, NumericError > factorize() const
Checks the mode weights and factorizes every component that has changed, so that the state's log-dens...
Definition Hybrid.h:361
HybridParams(ModesType modes, ComponentType const &conditional, Allocator_ const &allocator={})
Mode weights modes, with conditional as the component in every mode.
Definition Hybrid.h:122
ModeSpace_ const & modeSpace() const
Definition Hybrid.h:187
HybridParams(HybridParams const &)=default
copies the modes and components
void conditional(AxisIndex< Paths, N > const &...) const &&=delete
A component of a temporary would outlive it.
static constexpr int MaxDifferenceDimensionAtCompileTime
Definition Hybrid.h:117
allocator_type get_allocator() const
Definition Hybrid.h:173
HybridParams(ModesType modes, ConditionalsType conditionals)
Mode weights modes, and conditionals, one component per mode in flat-index order.
Definition Hybrid.h:128
auto marginal() const &
Definition Hybrid.h:312
static constexpr int ValueDimensionAtCompileTime
Definition Hybrid.h:108
void conditional(Eigen::Index mode) const &&=delete
A component of a temporary would outlive it; copy it from a named hybrid instead.
HybridParams(HybridParams &&other, Allocator_ const &allocator)
Moves the modes and components into storage from allocator.
Definition Hybrid.h:151
ModeSpace_ ModeSpaceType
the discrete mode space
Definition Hybrid.h:98
Eigen::Index differenceDimension() const
Definition Hybrid.h:208
void toDensity() const &&=delete
A density of a temporary would outlive it.
HybridParams(ModesType modes, Conditionals const &conditionals, Allocator_ const &allocator)
As above, with the components copied into storage from allocator.
Definition Hybrid.h:137
void setConditional(Eigen::Index mode, ComponentType &&component)
As above, moving component in.
Definition Hybrid.h:252
void swapConditionals(ConditionalsType &conditionals)
Exchanges the components with conditionals, one per mode on the same space, which must come from an e...
Definition Hybrid.h:292
typename ComponentType::Scalar Scalar
the scalar type
Definition Hybrid.h:96
Eigen::Index size() const
Definition Hybrid.h:194
Eigen::Index valueDimension() const
Definition Hybrid.h:201
static constexpr int DifferenceDimensionAtCompileTime
Definition Hybrid.h:114
void marginal(Eigen::Index element) const &&=delete
A marginal of a temporary would outlive it.
Hybrid< Component_, ModeSpace_, Allocator_ > DensityType
the view toDensity() returns
Definition Hybrid.h:102
typename ComponentType::SpaceType SpaceType
the continuous state space
Definition Hybrid.h:97
MixtureParams< Component_, Allocator_ > toMixture() const
Definition Hybrid.h:339
Params< Component_ > ComponentType
the component given one mode
Definition Hybrid.h:95
HybridParams(HybridParams const &other, Allocator_ const &allocator)
Copies the modes and components into storage from allocator.
Definition Hybrid.h:145
ComponentType const & conditional(Eigen::Index mode) const &
Definition Hybrid.h:231
ModesType const & modes() const
Definition Hybrid.h:215
void marginal() const &&=delete
A marginal of a temporary would outlive it.
typename ComponentType::MomentsType MomentsType
a mean and covariance together
Definition Hybrid.h:100
std::expected< void, NumericError > factorize(R const &repair)
factorize(), repairing each covariance that is not positive definite by repair (see GaussianParams::f...
Definition Hybrid.h:388
decltype(auto) updateConditional(Eigen::Index mode, F &&f)
Definition Hybrid.h:263
void setModes(ModesType modes)
Replaces the mode weights.
Definition Hybrid.h:222
internal::Buffer< ComponentType, Allocator_ > ConditionalsType
The components, one per mode in flat-index order.
Definition Hybrid.h:105
HybridParams(HybridParams &&) noexcept=default
moves the modes and components
ComponentType const & conditional(AxisIndex< Paths, N > const &... indices) const &
Definition Hybrid.h:277
CategoricalParams< ModeSpace_, Scalar > ModesType
the weights of the modes
Definition Hybrid.h:99
static constexpr bool IsParams
Definition Hybrid.h:119
std::expected< DensityType, NumericError > toDensity() const &
Checks the mode weights and factorizes every component that has changed (factorize()).
Definition Hybrid.h:423
void toDensity(R const &) &&=delete
A density of a temporary would outlive it.
SpaceType const & space() const
Definition Hybrid.h:180
static constexpr int MaxValueDimensionAtCompileTime
Definition Hybrid.h:111
The density of a hybrid state, a checked view of its HybridParams (decisions.md [params-and-density],...
Definition Hybrid.h:528
SpaceType const & space() const
Definition Hybrid.h:556
Allocator_ allocator_type
the parameters' allocator
Definition Hybrid.h:538
Eigen::Index size() const
Definition Hybrid.h:570
static constexpr bool IsParams
Definition Hybrid.h:552
typename ParamsType::ModesType ModesType
the weights of the modes
Definition Hybrid.h:536
static constexpr int DifferenceDimensionAtCompileTime
Definition Hybrid.h:547
Scalar logDensity(Eigen::MatrixBase< Derived > const &x) const
Definition Hybrid.h:615
MomentsType moments() const
Definition Hybrid.h:632
typename ParamsType::Scalar Scalar
the scalar type
Definition Hybrid.h:533
Eigen::Index valueDimension() const
Definition Hybrid.h:577
typename ParamsType::SpaceType SpaceType
the continuous state space
Definition Hybrid.h:534
ModeSpace_ ModeSpaceType
the discrete mode space
Definition Hybrid.h:535
auto collapse() const
Definition Hybrid.h:653
ComponentType collapsed() const
Definition Hybrid.h:641
ModeSpace_ const & modeSpace() const
Definition Hybrid.h:563
allocator_type get_allocator() const
Definition Hybrid.h:591
ComponentType const & conditional(Eigen::Index mode) const
Definition Hybrid.h:605
Scalar density(Eigen::MatrixBase< Derived > const &x) const
Definition Hybrid.h:623
ModesType const & modes() const
Definition Hybrid.h:598
static constexpr int MaxValueDimensionAtCompileTime
Definition Hybrid.h:544
HybridParams< Component_, ModeSpace_, Allocator_ > ParamsType
the parameters it reads
Definition Hybrid.h:531
static constexpr int ValueDimensionAtCompileTime
Definition Hybrid.h:541
static constexpr int MaxDifferenceDimensionAtCompileTime
Definition Hybrid.h:550
typename ParamsType::MomentsType MomentsType
a mean and covariance together
Definition Hybrid.h:537
Eigen::Index differenceDimension() const
Definition Hybrid.h:584
typename ParamsType::ComponentType ComponentType
the component given one mode
Definition Hybrid.h:532
Streaming log-sum-exp: accumulates without overflow.
Definition Weights.h:46
Scalar value() const
Definition Weights.h:133
Read-only view of a subset of the coordinates of every component of a mixture or a hybrid,...
Definition Mixture.h:2423
A weighted sum of components of one type, all in one space.
Definition Mixture.h:579
void reserve(Index n)
Reserves room for n components without setting a capacity.
Definition Mixture.h:1080
The distribution that a container of several holds one of per element (decisions.md [component-first]...
Definition Component.h:299
NumericError
Reasons a computation from parameters the caller gave can fail: a matrix that does not factorize or a...
Definition NumericError.h:30
constexpr Eigen::Index valueOf(S const &space, AxisIndex< Paths, N > const &... indices)
Definition Discrete.h:1112
HybridParams< Gaussian< Space_, Scalar_ >, ModeSpace_, Allocator_ > HybridGaussianParams
The HybridParams of Gaussians in covariance form: the parameters of a HybridGaussian,...
Definition Hybrid.h:754
Hybrid< Gaussian< Space_, Scalar_ >, ModeSpace_, Allocator_ > HybridGaussian
The Hybrid of Gaussians in covariance form, the spelling for the common case (decisions....
Definition Hybrid.h:742
typename ParamsOf< D >::type Params
The parameters of the density D: GaussianParams for a Gaussian, and D itself for a distribution whose...
Definition Params.h:42
An index in each leaf axis of the axis named by the path Path (a tag or a TagPath),...
Definition Discrete.h:1059
static Type::MomentsType moments(Type const &hybrid)
Definition Hybrid.h:872
static Scalar logDensity(Type const &hybrid, Eigen::MatrixBase< Derived > const &x)
Definition Hybrid.h:775
static Type collapse(Eigen::Index count, ComponentAt componentAt, LogWeightAt logWeightAt)
Definition Hybrid.h:803
HybridParams< Component_, ModeSpace_, Allocator_ > Type
the component
Definition Hybrid.h:760
MixtureMarginal< Type, Selection, SubSpace > MarginalType
A marginal of one hybrid in a mixture, a range over its modes, which borrows the selection the mixtur...
Definition Hybrid.h:767
static Scalar modeLogProbability(Type const &hybrid, Eigen::Index m)
Definition Hybrid.h:882
static Params< Component_ > collapseModes(Type const &hybrid)
Definition Hybrid.h:855
typename Component_::Scalar Scalar
the scalar type
Definition Hybrid.h:761
What a container does with a component beyond the component's own members (decisions....
Definition Component.h:104