EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
Hybrid.h
Go to the documentation of this file.
1#pragma once
2
13
14#include <concepts>
15#include <cstddef>
16#include <expected>
17#include <memory>
18#include <utility>
19#include <vector>
20
34
35namespace Emrys
36{
37
38template <internal::ComponentOrInfoForm Component_, DiscreteSpace ModeSpace_, typename Allocator_ = DefaultAllocator>
39class Hybrid;
40
84template <internal::ComponentOrInfoForm Component_, DiscreteSpace ModeSpace_, typename Allocator_ = DefaultAllocator>
86{
87 static_assert(
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])"
91 );
92
93public:
94
96 using Scalar = typename ComponentType::Scalar;
97 using SpaceType = typename ComponentType::SpaceType;
98 using ModeSpaceType = ModeSpace_;
100 using MomentsType = typename ComponentType::MomentsType;
101 using allocator_type = Allocator_;
103
105 using ConditionalsType = internal::Buffer<ComponentType, Allocator_>;
106
108 static constexpr int ValueDimensionAtCompileTime = ComponentType::ValueDimensionAtCompileTime;
109
111 static constexpr int MaxValueDimensionAtCompileTime = ComponentType::MaxValueDimensionAtCompileTime;
112
114 static constexpr int DifferenceDimensionAtCompileTime = ComponentType::DifferenceDimensionAtCompileTime;
115
117 static constexpr int MaxDifferenceDimensionAtCompileTime = ComponentType::MaxDifferenceDimensionAtCompileTime;
118
119 static constexpr bool IsParams = true;
120
122 HybridParams(ModesType modes, ComponentType const & conditional, Allocator_ const & allocator = {})
123 : m_modes{std::move(modes)}
124 , m_conditionals(std::size_t(m_modes.cardinality()), conditional, ComponentAllocator(allocator))
125 {}
126
129 : m_modes{std::move(modes)}
130 , m_conditionals{std::move(conditionals)}
131 {
132 check();
133 }
134
136 template <typename Conditionals>
137 HybridParams(ModesType modes, Conditionals const & conditionals, Allocator_ const & allocator)
138 : m_modes{std::move(modes)}
139 , m_conditionals(conditionals.begin(), conditionals.end(), ComponentAllocator(allocator))
140 {
141 check();
142 }
143
145 HybridParams(HybridParams const & other, Allocator_ const & allocator)
146 : m_modes{other.m_modes}
147 , m_conditionals{other.m_conditionals, ComponentAllocator(allocator)}
148 {}
149
151 HybridParams(HybridParams && other, Allocator_ const & allocator)
152 : m_modes{std::move(other.m_modes)}
153 , m_conditionals{std::move(other.m_conditionals), ComponentAllocator(allocator)}
154 {
155 other.m_stamp.touchShape();
156 }
157
158 HybridParams(HybridParams const &) = default;
159 HybridParams(HybridParams &&) noexcept = default;
160
163 operator=(HybridParams const &) = default;
164
167 operator=(HybridParams &&) noexcept = default;
168
169 ~HybridParams() = default;
170
172 [[nodiscard]] allocator_type
174 {
175 return allocator_type(m_conditionals.get_allocator());
176 }
177
179 [[nodiscard]] SpaceType const &
180 space() const
181 {
182 return m_conditionals.front().space();
183 }
184
186 [[nodiscard]] ModeSpace_ const &
187 modeSpace() const
188 {
189 return m_modes.space();
190 }
191
193 [[nodiscard]] Eigen::Index
194 size() const
195 {
196 return m_modes.cardinality();
197 }
198
200 [[nodiscard]] Eigen::Index
202 {
203 return m_conditionals.front().valueDimension();
204 }
205
207 [[nodiscard]] Eigen::Index
209 {
210 return m_conditionals.front().differenceDimension();
211 }
212
214 [[nodiscard]] ModesType const &
215 modes() const
216 {
217 return m_modes;
218 }
219
221 void
223 {
224 EMRYS_FILTER_ASSERT(modes.space() == modeSpace() && "the modes are on a different space");
225 m_stamp.touchValues();
226 m_modes = std::move(modes);
227 }
228
230 [[nodiscard]] ComponentType const &
231 conditional(Eigen::Index mode) const &
232 {
233 EMRYS_FILTER_ASSERT(mode >= 0 && mode < size() && "the mode is out of range");
234 return m_conditionals[std::size_t(mode)];
235 }
236
238 void
239 conditional(Eigen::Index mode) const && = delete;
240
244 void
245 setConditional(Eigen::Index mode, ComponentType const & component)
246 {
247 conditionalToSet(mode, component) = component;
248 }
249
251 void
252 setConditional(Eigen::Index mode, ComponentType && component)
253 {
254 conditionalToSet(mode, component) = std::move(component);
255 }
256
260 template <typename F>
261 requires std::invocable<F &, ComponentType &>
262 decltype(auto)
263 updateConditional(Eigen::Index mode, F && f)
264 {
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);
268 }
269
274 template <typename... Values, typename... Paths, std::size_t... N>
275 requires(sizeof...(Values) + sizeof...(Paths) > 0)
276 [[nodiscard]] ComponentType const &
277 conditional(AxisIndex<Paths, N> const &... indices) const &
278 {
279 return conditional(valueOf<Values...>(modeSpace(), indices...));
280 }
281
283 template <typename... Values, typename... Paths, std::size_t... N>
284 requires(sizeof...(Values) + sizeof...(Paths) > 0)
285 void
286 conditional(AxisIndex<Paths, N> const &...) const && = delete;
287
291 void
293 {
294 EMRYS_FILTER_ASSERT(Eigen::Index(conditionals.size()) == size() && "give one component per mode");
295 EMRYS_FILTER_ASSERT(
296 conditionals.get_allocator() == m_conditionals.get_allocator()
297 && "the components must come from an equal allocator"
298 );
299 m_stamp.touchShape();
300 m_conditionals.swap(conditionals);
301 }
302
310 template <typename Path>
311 [[nodiscard]] auto
312 marginal() const &
313 {
314 return internal::tagMarginal<MixtureMarginal, Path>(*this);
315 }
316
318 template <typename Path>
319 void
320 marginal() const && = delete;
321
323 template <typename Path>
324 [[nodiscard]] auto
325 marginal(Eigen::Index element) const &
326 {
327 return internal::elementMarginal<MixtureMarginal, Path>(*this, element);
328 }
329
331 template <typename Path>
332 void
333 marginal(Eigen::Index element) const && = delete;
334
339 toMixture() const
340 {
342 mixture.reserve(size());
343 for (Eigen::Index m = 0; m < size(); ++m)
344 {
345 mixture.add(m_modes.logWeight(m), m_conditionals[std::size_t(m)]);
346 }
347 return mixture;
348 }
349
360 [[nodiscard]] std::expected<void, NumericError>
361 factorize() const
362 {
363 if (auto const total = m_modes.logTotalWeight(); !total)
364 {
365 return std::unexpected{total.error()};
366 }
367 for (auto const & conditional : m_conditionals)
368 {
369 if (auto result = conditional.factorize(); !result)
370 {
371 return std::unexpected{result.error()};
372 }
373 }
374 return {};
375 }
376
386 template <typename R>
387 [[nodiscard]] std::expected<void, NumericError>
388 factorize(R const & repair)
389 {
390 m_stamp.touchValues();
391 if (auto const total = m_modes.logTotalWeight(); !total)
392 {
393 return std::unexpected{total.error()};
394 }
395 // Every repair is tried on a copy of a component that needs one before any is kept. Repairs
396 // are rare, so the copies are too; a component that factorizes is cached for the loop after.
397 for (auto const & conditional : m_conditionals)
398 {
399 if (!conditional.factorize())
400 {
401 auto trial = ComponentType{conditional};
402 if (auto result = trial.factorize(repair); !result)
403 {
404 return std::unexpected{result.error()};
405 }
406 }
407 }
408 for (auto & conditional : m_conditionals)
409 {
410 if (auto result = conditional.factorize(repair); !result)
411 {
412 return std::unexpected{result.error()};
413 }
414 }
415 return {};
416 }
417
422 [[nodiscard]] std::expected<DensityType, NumericError>
423 toDensity() const &
424 {
425 if (auto result = factorize(); !result)
426 {
427 return std::unexpected{result.error()};
428 }
429 return DensityType{*this};
430 }
431
433 void
434 toDensity() const && = delete;
435
441 template <typename R>
442 [[nodiscard]] std::expected<DensityType, NumericError>
443 toDensity(R const & repair) &
444 {
445 if (auto result = factorize(repair); !result)
446 {
447 return std::unexpected{result.error()};
448 }
449 return DensityType{*this};
450 }
451
453 template <typename R>
454 void
455 toDensity(R const &) && = delete;
456
457private:
458
460 template <typename>
461 friend class internal::ValuesCheck;
462
464 template <typename>
465 friend class internal::ShapeCheck;
466
467 using ComponentAllocator = internal::ReBound<Allocator_, ComponentType>;
468
472 [[nodiscard]] ComponentType &
473 conditionalToSet(Eigen::Index mode, [[maybe_unused]] ComponentType const & component)
474 {
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)];
479 }
480
482 void
483 check() const
484 {
485 EMRYS_FILTER_ASSERT(
486 Eigen::Index(m_conditionals.size()) == m_modes.cardinality() && "give one component per mode"
487 );
488 for (auto const & conditional : m_conditionals)
489 {
490 EMRYS_FILTER_ASSERT(
491 conditional.space() == m_conditionals.front().space()
492 && "every mode's component must be on the same space"
493 );
494 }
495 }
496
497 ModesType m_modes;
498 ConditionalsType m_conditionals;
499 internal::Stamp m_stamp;
500};
501
526template <internal::ComponentOrInfoForm Component_, DiscreteSpace ModeSpace_, typename Allocator_>
527class Hybrid
528{
529public:
530
533 using Scalar = typename ParamsType::Scalar;
535 using ModeSpaceType = ModeSpace_;
538 using allocator_type = Allocator_;
539
542
545
548
551
552 static constexpr bool IsParams = false;
553
555 [[nodiscard]] SpaceType const &
556 space() const
557 {
558 return source().space();
559 }
560
562 [[nodiscard]] ModeSpace_ const &
563 modeSpace() const
564 {
565 return source().modeSpace();
566 }
567
569 [[nodiscard]] Eigen::Index
570 size() const
571 {
572 return source().size();
573 }
574
576 [[nodiscard]] Eigen::Index
578 {
579 return source().valueDimension();
580 }
581
583 [[nodiscard]] Eigen::Index
585 {
586 return source().differenceDimension();
587 }
588
590 [[nodiscard]] allocator_type
592 {
593 return source().get_allocator();
594 }
595
597 [[nodiscard]] ModesType const &
598 modes() const
599 {
600 return source().modes();
601 }
602
604 [[nodiscard]] ComponentType const &
605 conditional(Eigen::Index mode) const
606 {
607 return source().conditional(mode);
608 }
609
613 template <typename Derived>
614 [[nodiscard]] Scalar
615 logDensity(Eigen::MatrixBase<Derived> const & x) const
616 {
617 return ComponentTraits<ParamsType>::logDensity(source(), x);
618 }
619
621 template <typename Derived>
622 [[nodiscard]] Scalar
623 density(Eigen::MatrixBase<Derived> const & x) const
624 {
625 return Eigen::numext::exp(logDensity(x));
626 }
627
631 [[nodiscard]] MomentsType
632 moments() const
633 {
635 }
636
640 [[nodiscard]] ComponentType
641 collapsed() const
642 {
644 }
645
651 template <typename P>
652 [[nodiscard]] auto
653 collapse() const
654 {
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);
665 };
666 for (Eigen::Index value = 0; value < count; ++value)
667 {
668 LogWeights logWeights = hybrid.modes().logWeights();
669 for (Eigen::Index m = 0; m < size(); ++m)
670 {
671 if ((m / stride) % count != value)
672 {
673 logWeights(m) = -Eigen::NumTraits<Scalar>::infinity();
674 }
675 }
676 // A value of probability zero keeps the components' plain average, which is never used.
677 if (!internal::logTotalWeight<Scalar>(logWeights))
678 {
679 logWeights = LogWeights::Constant(size(), -Eigen::NumTraits<Scalar>::infinity());
680 for (Eigen::Index m = 0; m < size(); ++m)
681 {
682 if ((m / stride) % count == value)
683 {
684 logWeights(m) = Scalar(0);
685 }
686 }
687 }
688 grouped.push_back(ComponentTraits<ComponentType>::collapse(size(), componentAt, [&](Eigen::Index m) {
689 return logWeights(m);
690 }));
691 }
692 return Result{hybrid.modes().template marginal<P>(), std::move(grouped)};
693 }
694
695private:
696
697 friend ParamsType;
698
702 explicit Hybrid(ParamsType const & source)
703 : m_check{source}
704 {}
705
707 [[nodiscard]] ParamsType const &
708 source() const
709 {
710 return m_check.get();
711 }
712
713 internal::ValuesCheck<ParamsType> m_check;
714};
715
717template <typename Scalar, typename ModeSpace, typename C>
718 requires Component<Density<C>> && std::same_as<Scalar, typename C::Scalar>
720
721template <typename Scalar, typename ModeSpace, typename C, typename Allocator>
722 requires Component<Density<C>> && std::same_as<Scalar, typename C::Scalar>
723HybridParams(CategoricalParams<ModeSpace, Scalar>, C, Allocator) -> HybridParams<Density<C>, ModeSpace, Allocator>;
724
725template <typename Scalar, typename ModeSpace, typename C, typename ComponentAllocator>
726 requires Component<Density<C>> && std::same_as<Scalar, typename C::Scalar>
727HybridParams(CategoricalParams<ModeSpace, Scalar>, std::vector<C, ComponentAllocator>)
728 -> HybridParams<Density<C>, ModeSpace, internal::ReBound<ComponentAllocator, std::byte>>;
730
741template <Space Space_, DiscreteSpace ModeSpace_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
742using HybridGaussian = Hybrid<Gaussian<Space_, Scalar_>, ModeSpace_, Allocator_>;
743
753template <Space Space_, DiscreteSpace ModeSpace_, RealScalar Scalar_ = double, typename Allocator_ = DefaultAllocator>
755
757template <Component Component_, DiscreteSpace ModeSpace_, typename Allocator_>
758struct ComponentTraits<HybridParams<Component_, ModeSpace_, Allocator_>>
759{
761 using Scalar = typename Component_::Scalar;
762
766 template <typename Selection, typename SubSpace>
768
773 template <typename Derived>
774 [[nodiscard]] static Scalar
775 logDensity(Type const & hybrid, Eigen::MatrixBase<Derived> const & x)
776 {
777 auto sum = LogSumExp<Scalar>{};
778 auto total = LogSumExp<Scalar>{};
779 for (Eigen::Index m = 0; m < hybrid.size(); ++m)
780 {
781 Scalar const logWeight = hybrid.modes().logWeight(m);
782 if (logWeight == -Eigen::NumTraits<Scalar>::infinity())
783 {
784 continue;
785 }
786 total.add(logWeight);
787 sum.add(logWeight + ComponentTraits<Params<Component_>>::logDensity(hybrid.conditional(m), x));
788 }
789 return sum.value() - total.value();
790 }
791
801 template <typename ComponentAt, typename LogWeightAt>
802 [[nodiscard]] static Type
803 collapse(Eigen::Index count, ComponentAt componentAt, LogWeightAt logWeightAt)
804 {
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)
811 {
812 auto sum = LogSumExp<Scalar>{};
813 for (Eigen::Index c = 0; c < count; ++c)
814 {
815 EMRYS_FILTER_ASSERT(
816 componentAt(c).modeSpace() == first.modeSpace() && "every hybrid must be on one mode space"
817 );
818 sum.add(Scalar(logWeightAt(c)) + modeLogProbability(componentAt(c), m));
819 }
820 logModes(m) = sum.value();
821 }
822 typename Type::ConditionalsType conditionals(
823 internal::ReBound<Allocator_, Params<Component_>>(first.get_allocator())
824 );
825 conditionals.reserve(std::size_t(modes));
826 for (Eigen::Index m = 0; m < modes; ++m)
827 {
828 if (logModes(m) == -Eigen::NumTraits<Scalar>::infinity())
829 {
830 conditionals.push_back(first.conditional(m));
831 continue;
832 }
833 conditionals.push_back(
835 count,
836 [&](Eigen::Index c) -> Params<Component_> const & {
837 return componentAt(c).conditional(m);
838 },
839 [&](Eigen::Index c) {
840 return Scalar(logWeightAt(c)) + modeLogProbability(componentAt(c), m);
841 }
842 )
843 );
844 }
845 auto collapsedModes = typename Type::ModesType{first.modeSpace(), logModes};
846 // Weights that fail to normalize are kept as they are, for the next factorize() to report.
847 static_cast<void>(collapsedModes.normalize());
848 return Type{std::move(collapsedModes), std::move(conditionals)};
849 }
850
854 [[nodiscard]] static Params<Component_>
855 collapseModes(Type const & hybrid)
856 {
858 hybrid.size(),
859 [&](Eigen::Index m) -> Params<Component_> const & {
860 return hybrid.conditional(m);
861 },
862 [&](Eigen::Index m) {
863 return hybrid.modes().logWeight(m);
864 }
865 );
866 }
867
871 [[nodiscard]] static typename Type::MomentsType
872 moments(Type const & hybrid)
873 {
875 }
876
881 [[nodiscard]] static Scalar
882 modeLogProbability(Type const & hybrid, Eigen::Index m)
883 {
884 auto const total = hybrid.modes().logTotalWeight();
885 EMRYS_FILTER_ASSERT(total && "a hybrid's mode weights must define a distribution to collapse it");
886 return Scalar(hybrid.modes().logWeight(m) - *total);
887 }
888};
889
890namespace internal
891{
892
894template <Component Component_, DiscreteSpace ModeSpace_, typename Allocator_>
895struct ElementsOf<HybridParams<Component_, ModeSpace_, Allocator_>>
896{
897 using Type = HybridParams<Component_, ModeSpace_, Allocator_>;
898
900 template <typename ComponentParams>
901 using CopyType = HybridParams<Density<ComponentParams>, ModeSpace_, Allocator_>;
902
904 [[nodiscard]] static auto
905 logWeight(Type const & hybrid, Eigen::Index m)
906 {
907 return hybrid.modes().logWeight(m);
908 }
909
911 [[nodiscard]] static auto const &
912 component(Type const & hybrid, Eigen::Index m)
913 {
914 return hybrid.conditional(m);
915 }
916
920 template <typename Marginal>
921 [[nodiscard]] static auto
922 copy(Type const & hybrid, Marginal const & marginal, Allocator_ const & allocator)
923 {
924 using Result = CopyType<typename Marginal::ComponentMarginalType::ParamsType>;
925 auto conditionals =
926 typename Result::ConditionalsType(ReBound<Allocator_, typename Result::ComponentType>(allocator));
927 conditionals.reserve(std::size_t(marginal.size()));
928 for (auto const & element : marginal)
929 {
930 conditionals.push_back(element.component.copy());
931 }
932 return Result{hybrid.modes(), std::move(conditionals)};
933 }
934};
935
936} // namespace internal
937
938} // namespace Emrys
939
940#ifndef EMRYS_FILTER_NO_IO
941
942namespace Emrys
943{
944
945namespace internal
946{
947
952template <typename Component_, typename ModeSpace_, typename Allocator_>
953void
954describe(std::ostream & stream, HybridParams<Component_, ModeSpace_, Allocator_> const & hybrid, Indent indent)
955{
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();
960 if (total)
961 {
962 printMoments(
963 stream,
964 indent.deeper(),
965 ComponentTraits<HybridParams<Component_, ModeSpace_, Allocator_>>::moments(hybrid)
966 );
967 }
968 else
969 {
970 stream << '\n';
971 describe(stream, total.error(), indent.deeper());
972 }
973 for (Eigen::Index mode = 0; mode < hybrid.size(); ++mode)
974 {
975 auto const logWeight = hybrid.modes().logWeight(mode);
976 stream << '\n' << indent.deeper() << "mode " << mode;
977 if (total)
978 {
979 stream << ", probability " << Eigen::numext::exp(logWeight - *total) << ":\n";
980 }
981 else
982 {
983 stream << ", log-weight " << logWeight << ":\n";
984 }
985 describe(stream, hybrid.conditional(mode), indent.deeper().deeper());
986 }
987}
988
989} // namespace internal
990
991} // namespace Emrys
992
993#endif // EMRYS_FILTER_NO_IO
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