24#include "pybind11/pybind11.h"
25#include "pybind11/eigen.h"
26#include "pybind11/stl.h"
30#include "ndarray/pybind11.h"
31#include "ndarray/eigen.h"
37using namespace pybind11::literals;
44using PyMixtureComponent = py::class_<MixtureComponent>;
45using PyMixtureUpdateRestriction =
46 py::class_<MixtureUpdateRestriction, std::shared_ptr<MixtureUpdateRestriction>>;
47using PyMixture = py::class_<Mixture, std::shared_ptr<Mixture>>;
49static PyMixtureComponent declareMixtureComponent(py::module &mod) {
50 PyMixtureComponent
cls(mod,
"MixtureComponent");
61 cls.def(py::init<int>(),
"dim"_a);
62 cls.def(py::init<Scalar, Vector const &, Matrix const &>(),
"weight"_a,
"mu"_a,
"sigma"_a);
63 utils::python::addOutputOp(cls,
"__str__");
64 utils::python::addOutputOp(cls,
"__repr__");
68static PyMixtureUpdateRestriction declareMixtureUpdateRestriction(py::module &mod) {
69 PyMixtureUpdateRestriction
cls(mod,
"MixtureUpdateRestriction");
71 cls.def(py::init<int>(),
"dim"_a);
76static PyMixture declareMixture(py::module &mod) {
77 PyMixture
cls(mod,
"Mixture");
78 afw::table::io::python::addPersistableMethods<Mixture>(cls);
79 cls.def(
"__iter__", [](Mixture &self) {
return py::make_iterator(self.begin(), self.end()); },
80 py::keep_alive<0, 1>());
81 cls.def(
"__getitem__",
82 [](Mixture &self,
std::ptrdiff_t i) {
return self[utils::python::cppIndex(self.size(), i)]; },
83 py::return_value_policy::reference_internal);
97 [](Mixture
const &self, MixtureComponent
const &component,
98 ndarray::Array<Scalar, 1, 0>
const &array) ->
Scalar {
99 return self.evaluate(component, ndarray::asEigenMatrix(array));
101 "component"_a,
"x"_a);
103 [](Mixture
const &self, ndarray::Array<Scalar, 1, 0>
const &array) ->
Scalar {
104 return self.evaluate(ndarray::asEigenMatrix(array));
107 cls.def(
"evaluate", (
void (Mixture::*)(ndarray::Array<Scalar const, 2, 1>
const &,
108 ndarray::Array<Scalar, 1, 0>
const &)
const) &
112 cls.def(
"evaluateDerivatives",
113 py::overload_cast<ndarray::Array<Scalar const, 1, 1>
const &,
114 ndarray::Array<Scalar,1,1>
const &,
116 "x"_a,
"gradient"_a,
"hessian"_a);
118 cls.def(
"updateEM", (
void (Mixture::*)(ndarray::Array<Scalar const, 2, 1>
const &,
119 ndarray::Array<Scalar const, 1, 0>
const &,
Scalar,
Scalar)) &
121 "x"_a,
"w"_a,
"tau1"_a = 0.0,
"tau2"_a = 0.5);
122 cls.def(
"updateEM", (
void (Mixture::*)(ndarray::Array<Scalar const, 2, 1>
const &,
123 ndarray::Array<Scalar const, 1, 0>
const &,
124 MixtureUpdateRestriction
const &restriction,
Scalar,
Scalar)) &
126 "x"_a,
"w"_a,
"restriction"_a,
"tau1"_a = 0.0,
"tau2"_a = 0.5);
127 cls.def(
"updateEM", (
void (Mixture::*)(ndarray::Array<Scalar const, 2, 1>
const &,
128 MixtureUpdateRestriction
const &restriction,
Scalar,
Scalar)) &
130 "x"_a,
"restriction"_a,
"tau1"_a = 0.0,
"tau2"_a = 0.5);
132 cls.def(py::init<int, Mixture::ComponentList &, Scalar>(),
"dim"_a,
"components"_a,
134 utils::python::addOutputOp(cls,
"__str__");
135 utils::python::addOutputOp(cls,
"__repr__");
140 py::module::import(
"lsst.afw.math");
142 auto clsMixtureComponent = declareMixtureComponent(mod);
143 auto clsMixtureUpdateRestriction = declareMixtureUpdateRestriction(mod);
144 auto clsMixture = declareMixture(mod);
145 clsMixture.attr(
"Component") = clsMixtureComponent;
146 clsMixture.attr(
"UpdateRestriction") = clsMixtureUpdateRestriction;
MixtureComponent project(int dim) const
Project the distribution onto the given dimension (marginalize over all others)
Vector getMu() const
Get/set the location parameter (mean/median/mode) of this component.
Scalar weight
Weight of this distribution in the mixture.
void setSigma(Matrix const &sigma)
void setMu(Vector const &mu)
Matrix getSigma() const
Get/set the shape/size parameter.
int getDimension() const
Return the number of dimensions.
void updateEM(ndarray::Array< Scalar const, 2, 1 > const &x, ndarray::Array< Scalar const, 1, 0 > const &w, Scalar tau1=0.0, Scalar tau2=0.5)
Perform an Expectation-Maximization step, updating the component parameters to match the given weight...
Scalar getDegreesOfFreedom() const
Get the number of degrees of freedom in the component Student's T distributions (inf=Gaussian)
std::size_t size() const
Return the number of components.
std::shared_ptr< Mixture > project(int dim) const
Project the distribution onto the given dimensions (marginalize over all others)
Scalar evaluate(Component const &component, Eigen::MatrixBase< Derived > const &x) const
Evaluate the probability density at the given point for the given component distribution.
void normalize()
Iterate over all components, rescaling their weights so they sum to one.
void evaluateComponents(ndarray::Array< Scalar const, 2, 1 > const &x, ndarray::Array< Scalar, 2, 1 > const &p) const
Evaluate the contributions of each component to the full probability at the given points.
void evaluateDerivatives(ndarray::Array< Scalar const, 1, 1 > const &x, ndarray::Array< Scalar, 1, 1 > const &gradient, ndarray::Array< Scalar, 2, 1 > const &hessian) const
Evaluate the derivative of the distribution at the given point.
void shift(int dim, Scalar offset)
Shift the mixture in the given dimension, adding the given offset to all mu vectors.
virtual std::shared_ptr< Mixture > clone() const
Polymorphic deep copy.
virtual int getComponentCount() const
Return the number of components.
void draw(afw::math::Random &rng, ndarray::Array< Scalar, 2, 1 > const &x) const
Draw random variates from the distribution.
int getDimension() const
Return the number of dimensions.
void setDegreesOfFreedom(Scalar df=std::numeric_limits< Scalar >::infinity())
Set the number of degrees of freedom in the component Student's T distributions (inf=Gaussian)
std::size_t clip(Scalar threshold=0.0)
Iterate over all components, removing those with weight less than or equal to threshold.
PYBIND11_MODULE(_cameraGeom, mod)
double Scalar
Typedefs to be used for probability and parameter values.