19 #include<boost/container/static_vector.hpp>
23 constexpr
double invsqrt2PI =
24 M_2_SQRTPI / (2. * M_SQRT2);
36 Component(
double aWeight,
double aMean,
double aSigma)
46 using VecOfComponents =
47 boost::container::static_vector<
Component,
61 const double invertsigma = 1. /
sigma;
62 const double z = (
x -
mean) * invertsigma;
63 return (invsqrt2PI * invertsigma) *
exp(-0.5 *
z *
z);
68 pdf(
double x,
int i,
const std::array<VecOfComponents, 5>& mixture)
71 auto component = mixture[
i].begin();
72 for (; component != mixture[
i].end(); ++component) {
73 pdf += component->weight * gaus(
x, component->mean, component->sigma);
81 fullPdf(
double x,
int i,
const std::array<VecOfComponents, 5>& mixture)
84 auto component = mixture[
i].begin();
85 for (; component != mixture[
i].end(); ++component) {
86 double componentgaus = gaus(
x, component->mean, component->sigma);
87 pdf.value += component->weight * componentgaus;
88 const double invertSigma = 1. / component->sigma;
89 const double z = (
x - component->mean) * invertSigma;
90 pdf.deriv1 += -1. * component->weight *
z * componentgaus * invertSigma;
91 pdf.deriv2 += component->weight * invertSigma * invertSigma * (
z *
z - 1.) *
100 width(
int i,
const std::array<VecOfComponents, 5>& mixture)
103 auto component = mixture[
i].begin();
104 for (; component != mixture[
i].end(); ++component) {
105 pdf += component->weight * component->sigma;
112 std::array<VecOfComponents, 5>& mixture)
122 for (
size_t i = 0;
i < 5; ++
i) {
124 const AmgSymMatrix(5)* measuredCov = componentParameters->covariance();
130 double weight = component.weight;
131 double mean = componentParameters->parameters()[parameter[
i]];
134 double sigma = sqrt(std::abs((*measuredCov)(parameter[
i], parameter[
i])));
139 multiComponentState.begin()->params->parameters()[2] -
mean;
152 findMode(
double xStart,
154 const std::array<VecOfComponents, 5>& mixture)
157 bool converged =
false;
160 double currentMode(xStart);
161 double nextMode(currentMode);
163 pdfAndDeriv currentPdf = fullPdf(currentMode,
i, mixture);
166 for (
int iteration = 0; iteration < 20; ++iteration) {
168 if (currentPdf.deriv2 != 0.0) {
169 nextMode = currentMode - currentPdf.deriv1 / currentPdf.deriv2;
175 pdfAndDeriv nextPdf = fullPdf(nextMode,
i, mixture);
177 if ((nextPdf.value + currentPdf.value) != 0.0) {
178 tolerance = std::abs(nextPdf.value - currentPdf.value) /
179 (nextPdf.value + currentPdf.value);
189 currentPdf = nextPdf;
190 currentMode = nextMode;
206 const std::array<VecOfComponents, 5>& mixture)
218 bool ac_equal(
false);
223 int MaxIterations = 20;
226 for (
int iter = 0; iter <= MaxIterations; iter++) {
228 if ((fb < 0 && fc < 0) || (fb > 0 && fc > 0)) {
237 if (std::abs(fc) < std::abs(fb)) {
248 double m = 0.5 * (
c -
b);
250 if (fb == 0 || std::abs(
m) <= tol) {
255 if (std::abs(
e) < tol || std::abs(fa) <= std::abs(fb)) {
272 p =
s * (2 *
m *
q * (
q -
r) - (
b -
a) * (
r - 1));
273 q = (
q - 1) * (
r - 1) * (
s - 1);
282 double min1 = 3 *
m *
q - std::abs(tol *
q);
283 double min2 = std::abs(
e *
q);
284 if (2 *
p < (min1 < min2 ? min1 : min2)) {
298 if (std::abs(
d) > tol) {
301 b += (
m > 0 ? +tol : -tol);
314 std::array<double, 10>
315 evaluateMode(
const std::array<VecOfComponents, 5>& mixture)
317 std::array<double, 10> modes{};
320 for (
int i = 0;
i < 5;
i++) {
322 double largerPdfComponent = 0.0;
323 double largerMeanComponent = 0.0;
330 for (
const Component& component : mixture[
i]) {
331 double pdfValue =
pdf(component.mean,
i, mixture);
332 if (pdfValue > largerPdfComponent) {
333 largerPdfComponent = pdfValue;
334 largerMeanComponent = component.mean;
337 modes[
i] = findMode(largerMeanComponent,
i, mixture);
340 if (largerMeanComponent != modes[
i]) {
342 double currentWidth =
width(
i, mixture);
345 double pdfVal =
pdf(modes[
i],
i, mixture);
349 double upperbound = modes[
i] + 1.5 * currentWidth;
351 if (
pdf(upperbound,
i, mixture) > pdfVal * 0.5) {
352 upperbound += currentWidth;
359 findRoot(highX, modes[
i], upperbound, pdfVal * 0.5,
i, mixture);
361 double lowerbound = modes[
i] - 1.5 * currentWidth;
363 if (
pdf(lowerbound,
i, mixture) > pdfVal * 0.5) {
364 lowerbound -= currentWidth;
370 findRoot(lowX, lowerbound, modes[
i], pdfVal * 0.5,
i, mixture);
371 if (highXFound && lowXFound) {
372 double FWHM = highX - lowX;
373 modes[
i + 5] = FWHM / 2.35482;
385 std::array<double, 10>
393 std::array<VecOfComponents, 5> mixture;
395 fillMixture(multiComponentState, mixture);
396 return evaluateMode(mixture);