From f74bfe355b931a426ad7fe16f72b83e41f232166 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 23 Feb 2026 15:25:09 +0100 Subject: [PATCH 01/14] feat: Add GSF functions for solely parameter merging --- .../detail/GsfComponentMerging.hpp | 211 +++++++++++++----- 1 file changed, 152 insertions(+), 59 deletions(-) diff --git a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp index 59a7a11e3ad..151f4273d46 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp @@ -20,7 +20,9 @@ namespace Acts::detail::Gsf { -/// Reduce Gaussian mixture +/// Reduce Gaussian mixture into a single parameter vector and covariance, using +/// the specified method to reduce the mixture. +/// /// @param mixture The mixture iterable /// @param surface The surface, on which the bound state is /// @param method How to reduce the mixture @@ -29,7 +31,8 @@ std::tuple mergeGaussianMixture( std::span mixture, const Surface &surface, ComponentMergeMethod method); -/// Merge two GSF components into one +/// Merge two Gaussian mixture components into one +/// /// @param a First component /// @param b Second component /// @param surface The surface, on which the bound state is @@ -93,15 +96,86 @@ auto angleDescriptionSwitch(const Surface &surface, Callable &&callable) { } } +/// Combine multiple components into one representative parameter object. The +/// function takes iterators to allow for arbitrary ranges to be combined. +/// +/// @note The correct mean and variances for cyclic coordinates or spherical +/// coordinates (theta, phi) must generally be computed using a special circular +/// mean or in cartesian coordinates. This implements a approximation, which +/// only works well for close components. +/// +/// @param cmps The component range to merge +/// @param projector A projector to extract the weight and parameters from the components +/// @param angleDesc The angle description object +/// @return parameters +template +BoundVector mergeGaussianMixtureMean(const component_range_t &cmps, + const projector_t &projector, + const angle_desc_t &angleDesc) { + // Early return in case of range with length 1 + if (cmps.size() == 1) { + auto &&[beginWeight, beginPars] = projector(cmps.front()); + return beginPars; + } + + // Do the (circular) mean with complex arithmetic. + // For normal values, just keep the real values. For angles, use the complex + // phase. Weighting then transparently happens by multiplying a real-valued + // weight. + using CVec = Eigen::Matrix, eBoundSize, 1>; + CVec cMean = CVec::Zero(); + double sumOfWeights = 0; + + for (auto &&cmp : cmps) { + auto &&[weight_l, pars_l] = projector(cmp); + + CVec pars_l_c = pars_l; + + const auto setPolar = [&](const auto &desc) { + pars_l_c[desc.idx] = std::polar(1.0, pars_l[desc.idx] / desc.constant); + }; + std::apply([&](auto... dsc) { (setPolar(dsc), ...); }, angleDesc); + + sumOfWeights += weight_l; + cMean += weight_l * pars_l_c; + } + + cMean /= sumOfWeights; + + BoundVector mean = cMean.real(); + + const auto getArg = [&](const auto &desc) { + mean[desc.idx] = desc.constant * std::arg(cMean[desc.idx]); + }; + std::apply([&](auto... dsc) { (getArg(dsc), ...); }, angleDesc); + + return mean; +} + +/// Combine multiple components into one representative parameter object. The +/// function takes iterators to allow for arbitrary ranges to be combined. +/// +/// @param cmps The component range to merge +/// @param projector A projector to extract the weight and parameters from the components +/// @return parameters +template +BoundVector mergeGaussianMixtureMode(const component_range_t &cmps, + const projector_t &projector) { + const auto maxWeightIt = std::ranges::max_element(cmps, {}, [&](auto &&cmp) { + auto &&[weight_l, pars_l] = projector(cmp); + return weight_l; + }); + auto &&[weight_l, pars_l] = projector(*maxWeightIt); + return pars_l; +} + /// Compute the covariance of a Gaussian mixture given the mean. The function -/// takes iterators to allow for arbitrary ranges to be combined. The dimension -/// of the vectors is inferred from the inputs. +/// takes iterators to allow for arbitrary ranges to be combined. /// /// @param cmps The component range to merge -/// @param projector A projector to extract the weight, parameters and covariance -/// from the components +/// @param projector A projector to extract the weight and parameters from the components /// @param mean The precomputed mean of the mixture -/// @param sumOfWeights The precomputed sum of weights of the mixture /// @param angleDesc The angle description object /// @return covariance template mergeGaussianMixtureMeanCov( const component_range_t &cmps, const projector_t &projector, const angle_desc_t &angleDesc) { - // Early return in case of range with length 1 if (cmps.size() == 1) { - const auto &[beginWeight, beginPars, beginCov] = projector(cmps.front()); - return {beginPars / beginWeight, beginCov / beginWeight}; - } - - // Do the (circular) mean with complex arithmetic. - // For normal values, just keep the real values. For angles, use the complex - // phase. Weighting then transparently happens by multiplying a real-valued - // weight. - using CVec = Eigen::Matrix, eBoundSize, 1>; - CVec cMean = CVec::Zero(); - double sumOfWeights{0.0}; - - for (const auto &cmp : cmps) { - const auto &[weight_l, pars_l, cov_l] = projector(cmp); - - CVec pars_l_c = pars_l; - - const auto setPolar = [&](const auto &desc) { - pars_l_c[desc.idx] = std::polar(1.0, pars_l[desc.idx] / desc.constant); - }; - std::apply([&](auto... dsc) { (setPolar(dsc), ...); }, angleDesc); - - sumOfWeights += weight_l; - cMean += weight_l * pars_l_c; + auto &&[beginWeight, beginPars, beginCov] = projector(cmps.front()); + return {beginPars, beginCov}; } - cMean /= sumOfWeights; - - BoundVector mean = cMean.real(); - - const auto getArg = [&](const auto &desc) { - mean[desc.idx] = desc.constant * std::arg(cMean[desc.idx]); - }; - std::apply([&](auto... dsc) { (getArg(dsc), ...); }, angleDesc); + const BoundVector mean = mergeGaussianMixtureMean( + cmps, + [&](auto &&c) { + auto &&[weight_l, pars_l, cov_l] = projector(c); + return std::forward_as_tuple(weight_l, pars_l); + }, + angleDesc); // MARK: fpeMaskBegin(FLTUND, 1, #2347) const BoundMatrix cov = - mergeGaussianMixtureCov(cmps, projector, mean, sumOfWeights, angleDesc); + mergeGaussianMixtureCov(cmps, projector, mean, angleDesc); // MARK: fpeMaskEnd(FLTUND) return {mean, cov}; } -/// Reduce Gaussian mixture +/// Reduce Gaussian mixture into a single parameter vector, using the specified +/// method to reduce the mixture. +/// +/// @param cmps The component range to merge +/// @param projector A projector to extract the weight and parameters from the components +/// @param angleDesc The angle description object +/// @param method How to reduce the mixture +/// @return parameters +template +BoundVector mergeGaussianMixtureParams(const component_range_t &cmps, + const projector_t &projector, + const angle_desc_t &angleDesc, + ComponentMergeMethod method) { + if (method == ComponentMergeMethod::eMean) { + return mergeGaussianMixtureMean(cmps, projector, angleDesc); + } else if (method == ComponentMergeMethod::eMaxWeight) { + return mergeGaussianMixtureMode(cmps, projector); + } else { + throw std::logic_error("Invalid component merge method"); + } +} + +/// Reduce Gaussian mixture into a single parameter vector and covariance, using +/// the specified method to reduce the mixture. /// /// @param cmps The component range to merge /// @param projector A projector to extract the weight, parameters and covariance @@ -223,20 +300,36 @@ std::tuple mergeGaussianMixture( if (method == ComponentMergeMethod::eMean) { return {mean, cov}; } else if (method == ComponentMergeMethod::eMaxWeight) { - const auto maxWeightIt = - std::ranges::max_element(cmps, {}, [&](const auto &cmp) { - const auto &[weight_l, pars_l, cov_l] = projector(cmp); - return weight_l; - }); - const auto &[weight_l, pars_l, cov_l] = projector(*maxWeightIt); - - return {pars_l, cov}; + const BoundVector mode = mergeGaussianMixtureMode(cmps, [&](auto &&c) { + auto &&[weight_l, pars_l, cov_l] = projector(c); + return std::forward_as_tuple(weight_l, pars_l); + }); + return {mode, cov}; } else { throw std::logic_error("Invalid component merge method"); } } -/// Reduce Gaussian mixture +/// Reduce Gaussian mixture into a single parameter vector, using the specified +/// method to reduce the mixture. +/// +/// @param cmps The component range to merge +/// @param projector A projector to extract the weight and parameters from the components +/// @param surface The surface, which the bound state is on +/// @param method How to reduce the mixture +/// @return parameters +template +BoundVector mergeGaussianMixtureParams(const component_range_t &cmps, + const projector_t &projector, + const Surface &surface, + ComponentMergeMethod method) { + return angleDescriptionSwitch(surface, [&](const auto &desc) { + return mergeGaussianMixtureParams(cmps, projector, desc, method); + }); +} + +/// Reduce Gaussian mixture into a single parameter vector and covariance, using +/// the specified method to reduce the mixture. /// /// @param cmps The component range to merge /// @param projector A projector to extract the weight, parameters and covariance From d27a02caba62b1e33ed4ce3777d4069fc1d1bc85 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 23 Feb 2026 15:54:08 +0100 Subject: [PATCH 02/14] try again --- .../include/Acts/TrackFitting/GaussianSumFitter.hpp | 2 +- .../TrackFitting/detail/GsfComponentMerging.hpp | 13 +++++++------ Core/include/Acts/TrackFitting/detail/GsfUtils.hpp | 12 ++++++------ 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Core/include/Acts/TrackFitting/GaussianSumFitter.hpp b/Core/include/Acts/TrackFitting/GaussianSumFitter.hpp index 201ab564bdb..1f3dc8fdd4e 100644 --- a/Core/include/Acts/TrackFitting/GaussianSumFitter.hpp +++ b/Core/include/Acts/TrackFitting/GaussianSumFitter.hpp @@ -508,7 +508,7 @@ struct GaussianSumFitter { const auto [finalPars, finalCov] = detail::Gsf::mergeGaussianMixture( params.components(), [](const auto& cmp) { - const auto& [weight_l, pars_l, opt_cov_l] = cmp; + auto&& [weight_l, pars_l, opt_cov_l] = cmp; return std::tie(weight_l, pars_l, *opt_cov_l); }, params.referenceSurface(), options.componentMergeMethod); diff --git a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp index 151f4273d46..288ab82927f 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp @@ -127,7 +127,7 @@ BoundVector mergeGaussianMixtureMean(const component_range_t &cmps, CVec cMean = CVec::Zero(); double sumOfWeights = 0; - for (auto &&cmp : cmps) { + for (const auto &cmp : cmps) { auto &&[weight_l, pars_l] = projector(cmp); CVec pars_l_c = pars_l; @@ -162,10 +162,11 @@ BoundVector mergeGaussianMixtureMean(const component_range_t &cmps, template BoundVector mergeGaussianMixtureMode(const component_range_t &cmps, const projector_t &projector) { - const auto maxWeightIt = std::ranges::max_element(cmps, {}, [&](auto &&cmp) { - auto &&[weight_l, pars_l] = projector(cmp); - return weight_l; - }); + const auto maxWeightIt = + std::ranges::max_element(cmps, {}, [&](const auto &cmp) { + auto &&[weight_l, pars_l] = projector(cmp); + return weight_l; + }); auto &&[weight_l, pars_l] = projector(*maxWeightIt); return pars_l; } @@ -192,7 +193,7 @@ BoundMatrix mergeGaussianMixtureCov(const component_range_t &cmps, BoundMatrix cov = BoundMatrix::Zero(); double sumOfWeights = 0; - for (auto &&cmp : cmps) { + for (const auto &cmp : cmps) { auto &&[weight_l, pars_l, cov_l] = projector(cmp); cov += weight_l * cov_l; // MARK: fpeMask(FLTUND, 1, #2347) diff --git a/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp b/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp index e842e32920a..c2baf96c637 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp @@ -225,14 +225,14 @@ struct MultiTrajectoryProjector { const auto proxy = mt.getTrackState(idx); switch (type) { case StatesType::ePredicted: - return std::make_tuple(weights.at(idx), proxy.predicted(), - proxy.predictedCovariance()); + return std::tuple(weights.at(idx), proxy.predicted(), + proxy.predictedCovariance()); case StatesType::eFiltered: - return std::make_tuple(weights.at(idx), proxy.filtered(), - proxy.filteredCovariance()); + return std::tuple(weights.at(idx), proxy.filtered(), + proxy.filteredCovariance()); case StatesType::eSmoothed: - return std::make_tuple(weights.at(idx), proxy.smoothed(), - proxy.smoothedCovariance()); + return std::tuple(weights.at(idx), proxy.smoothed(), + proxy.smoothedCovariance()); default: throw std::invalid_argument( "Incorrect StatesType, should be ePredicted" From 25b97aae757fc8581f261ead02d55e867507b053 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 23 Feb 2026 16:49:57 +0100 Subject: [PATCH 03/14] try again --- .../detail/GsfComponentMerging.hpp | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp index 288ab82927f..fc063748bed 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp @@ -115,8 +115,8 @@ BoundVector mergeGaussianMixtureMean(const component_range_t &cmps, const angle_desc_t &angleDesc) { // Early return in case of range with length 1 if (cmps.size() == 1) { - auto &&[beginWeight, beginPars] = projector(cmps.front()); - return beginPars; + auto [weight_, pars_l] = projector(cmps.front()); + return pars_l; } // Do the (circular) mean with complex arithmetic. @@ -128,7 +128,7 @@ BoundVector mergeGaussianMixtureMean(const component_range_t &cmps, double sumOfWeights = 0; for (const auto &cmp : cmps) { - auto &&[weight_l, pars_l] = projector(cmp); + auto [weight_l, pars_l] = projector(cmp); CVec pars_l_c = pars_l; @@ -164,10 +164,10 @@ BoundVector mergeGaussianMixtureMode(const component_range_t &cmps, const projector_t &projector) { const auto maxWeightIt = std::ranges::max_element(cmps, {}, [&](const auto &cmp) { - auto &&[weight_l, pars_l] = projector(cmp); + auto [weight_l, pars_l] = projector(cmp); return weight_l; }); - auto &&[weight_l, pars_l] = projector(*maxWeightIt); + auto [weight_max, pars_l] = projector(*maxWeightIt); return pars_l; } @@ -186,15 +186,15 @@ BoundMatrix mergeGaussianMixtureCov(const component_range_t &cmps, const BoundVector &mean, const angle_desc_t &angleDesc) { if (cmps.size() == 1) { - auto &&[beginWeight, beginPars, beginCov] = projector(cmps.front()); - return beginCov; + auto [weight_l, pars_l, cov_l] = projector(cmps.front()); + return cov_l; } BoundMatrix cov = BoundMatrix::Zero(); double sumOfWeights = 0; for (const auto &cmp : cmps) { - auto &&[weight_l, pars_l, cov_l] = projector(cmp); + auto [weight_l, pars_l, cov_l] = projector(cmp); cov += weight_l * cov_l; // MARK: fpeMask(FLTUND, 1, #2347) @@ -238,15 +238,15 @@ std::tuple mergeGaussianMixtureMeanCov( const component_range_t &cmps, const projector_t &projector, const angle_desc_t &angleDesc) { if (cmps.size() == 1) { - auto &&[beginWeight, beginPars, beginCov] = projector(cmps.front()); - return {beginPars, beginCov}; + auto [weight_l, pars_l, cov_l] = projector(cmps.front()); + return {pars_l, cov_l}; } const BoundVector mean = mergeGaussianMixtureMean( cmps, [&](auto &&c) { - auto &&[weight_l, pars_l, cov_l] = projector(c); - return std::forward_as_tuple(weight_l, pars_l); + auto [weight_l, pars_l, cov_l] = projector(c); + return std::tuple(weight_l, pars_l); }, angleDesc); @@ -302,8 +302,8 @@ std::tuple mergeGaussianMixture( return {mean, cov}; } else if (method == ComponentMergeMethod::eMaxWeight) { const BoundVector mode = mergeGaussianMixtureMode(cmps, [&](auto &&c) { - auto &&[weight_l, pars_l, cov_l] = projector(c); - return std::forward_as_tuple(weight_l, pars_l); + auto [weight_l, pars_l, cov_l] = projector(c); + return std::tuple(weight_l, pars_l); }); return {mode, cov}; } else { From 343b71cebed36ad1cac69398d224bbfcca89e35d Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 23 Feb 2026 17:20:22 +0100 Subject: [PATCH 04/14] try again --- .../detail/GsfComponentMerging.hpp | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp index fc063748bed..a926ce19888 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp @@ -115,7 +115,7 @@ BoundVector mergeGaussianMixtureMean(const component_range_t &cmps, const angle_desc_t &angleDesc) { // Early return in case of range with length 1 if (cmps.size() == 1) { - auto [weight_, pars_l] = projector(cmps.front()); + const auto &[weight_l, pars_l] = projector(cmps.front()); return pars_l; } @@ -128,7 +128,7 @@ BoundVector mergeGaussianMixtureMean(const component_range_t &cmps, double sumOfWeights = 0; for (const auto &cmp : cmps) { - auto [weight_l, pars_l] = projector(cmp); + const auto &[weight_l, pars_l] = projector(cmp); CVec pars_l_c = pars_l; @@ -164,10 +164,10 @@ BoundVector mergeGaussianMixtureMode(const component_range_t &cmps, const projector_t &projector) { const auto maxWeightIt = std::ranges::max_element(cmps, {}, [&](const auto &cmp) { - auto [weight_l, pars_l] = projector(cmp); + const auto &[weight_l, pars_l] = projector(cmp); return weight_l; }); - auto [weight_max, pars_l] = projector(*maxWeightIt); + const auto &[weight_max, pars_l] = projector(*maxWeightIt); return pars_l; } @@ -186,7 +186,7 @@ BoundMatrix mergeGaussianMixtureCov(const component_range_t &cmps, const BoundVector &mean, const angle_desc_t &angleDesc) { if (cmps.size() == 1) { - auto [weight_l, pars_l, cov_l] = projector(cmps.front()); + const auto &[weight_l, pars_l, cov_l] = projector(cmps.front()); return cov_l; } @@ -194,7 +194,7 @@ BoundMatrix mergeGaussianMixtureCov(const component_range_t &cmps, double sumOfWeights = 0; for (const auto &cmp : cmps) { - auto [weight_l, pars_l, cov_l] = projector(cmp); + const auto &[weight_l, pars_l, cov_l] = projector(cmp); cov += weight_l * cov_l; // MARK: fpeMask(FLTUND, 1, #2347) @@ -238,15 +238,15 @@ std::tuple mergeGaussianMixtureMeanCov( const component_range_t &cmps, const projector_t &projector, const angle_desc_t &angleDesc) { if (cmps.size() == 1) { - auto [weight_l, pars_l, cov_l] = projector(cmps.front()); + const auto &[weight_l, pars_l, cov_l] = projector(cmps.front()); return {pars_l, cov_l}; } const BoundVector mean = mergeGaussianMixtureMean( cmps, - [&](auto &&c) { + [&](const auto &c) { auto [weight_l, pars_l, cov_l] = projector(c); - return std::tuple(weight_l, pars_l); + return std::tuple(std::move(weight_l), std::move(pars_l)); }, angleDesc); @@ -301,9 +301,9 @@ std::tuple mergeGaussianMixture( if (method == ComponentMergeMethod::eMean) { return {mean, cov}; } else if (method == ComponentMergeMethod::eMaxWeight) { - const BoundVector mode = mergeGaussianMixtureMode(cmps, [&](auto &&c) { + const BoundVector mode = mergeGaussianMixtureMode(cmps, [&](const auto &c) { auto [weight_l, pars_l, cov_l] = projector(c); - return std::tuple(weight_l, pars_l); + return std::tuple(std::move(weight_l), std::move(pars_l)); }); return {mode, cov}; } else { From bc4c3ec2ff8e0570e9bf1bdf60a440d9589fe9f8 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 23 Feb 2026 17:51:09 +0100 Subject: [PATCH 05/14] try again --- .../detail/GsfComponentMerging.hpp | 53 ++++++++++--------- .../detail/GsfComponentMerging.cpp | 7 ++- .../TrackFitting/GsfComponentMergingTests.cpp | 6 ++- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp index a926ce19888..c74f96804f4 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp @@ -20,6 +20,12 @@ namespace Acts::detail::Gsf { +template +auto forward_first_two(Tuple &&t) { + return std::forward_as_tuple(std::get<0>(std::forward(t)), + std::get<1>(std::forward(t))); +} + /// Reduce Gaussian mixture into a single parameter vector and covariance, using /// the specified method to reduce the mixture. /// @@ -115,8 +121,8 @@ BoundVector mergeGaussianMixtureMean(const component_range_t &cmps, const angle_desc_t &angleDesc) { // Early return in case of range with length 1 if (cmps.size() == 1) { - const auto &[weight_l, pars_l] = projector(cmps.front()); - return pars_l; + decltype(auto) weight_pars_l = projector(cmps.front()); + return std::get<1>(weight_pars_l); } // Do the (circular) mean with complex arithmetic. @@ -128,17 +134,19 @@ BoundVector mergeGaussianMixtureMean(const component_range_t &cmps, double sumOfWeights = 0; for (const auto &cmp : cmps) { - const auto &[weight_l, pars_l] = projector(cmp); + decltype(auto) weight_pars_l = projector(cmp); + const double weight_l = std::get<0>(weight_pars_l); + const auto &pars_l = std::get<1>(weight_pars_l); - CVec pars_l_c = pars_l; + CVec cPars_l = pars_l; const auto setPolar = [&](const auto &desc) { - pars_l_c[desc.idx] = std::polar(1.0, pars_l[desc.idx] / desc.constant); + cPars_l[desc.idx] = std::polar(1.0, pars_l[desc.idx] / desc.constant); }; std::apply([&](auto... dsc) { (setPolar(dsc), ...); }, angleDesc); sumOfWeights += weight_l; - cMean += weight_l * pars_l_c; + cMean += weight_l * cPars_l; } cMean /= sumOfWeights; @@ -164,11 +172,11 @@ BoundVector mergeGaussianMixtureMode(const component_range_t &cmps, const projector_t &projector) { const auto maxWeightIt = std::ranges::max_element(cmps, {}, [&](const auto &cmp) { - const auto &[weight_l, pars_l] = projector(cmp); - return weight_l; + decltype(auto) weight_pars = projector(cmp); + return std::get<0>(weight_pars); }); - const auto &[weight_max, pars_l] = projector(*maxWeightIt); - return pars_l; + decltype(auto) weight_pars = projector(*maxWeightIt); + return std::get<1>(weight_pars); } /// Compute the covariance of a Gaussian mixture given the mean. The function @@ -186,15 +194,18 @@ BoundMatrix mergeGaussianMixtureCov(const component_range_t &cmps, const BoundVector &mean, const angle_desc_t &angleDesc) { if (cmps.size() == 1) { - const auto &[weight_l, pars_l, cov_l] = projector(cmps.front()); - return cov_l; + decltype(auto) weight_pars_cov_l = projector(cmps.front()); + return std::get<2>(weight_pars_cov_l); } BoundMatrix cov = BoundMatrix::Zero(); double sumOfWeights = 0; for (const auto &cmp : cmps) { - const auto &[weight_l, pars_l, cov_l] = projector(cmp); + decltype(auto) weight_pars_cov_l = projector(cmp); + const double weight_l = std::get<0>(weight_pars_cov_l); + const auto &pars_l = std::get<1>(weight_pars_cov_l); + const auto &cov_l = std::get<2>(weight_pars_cov_l); cov += weight_l * cov_l; // MARK: fpeMask(FLTUND, 1, #2347) @@ -238,16 +249,12 @@ std::tuple mergeGaussianMixtureMeanCov( const component_range_t &cmps, const projector_t &projector, const angle_desc_t &angleDesc) { if (cmps.size() == 1) { - const auto &[weight_l, pars_l, cov_l] = projector(cmps.front()); - return {pars_l, cov_l}; + decltype(auto) weight_pars_cov_l = projector(cmps.front()); + return {std::get<1>(weight_pars_cov_l), std::get<2>(weight_pars_cov_l)}; } const BoundVector mean = mergeGaussianMixtureMean( - cmps, - [&](const auto &c) { - auto [weight_l, pars_l, cov_l] = projector(c); - return std::tuple(std::move(weight_l), std::move(pars_l)); - }, + cmps, [&](const auto &c) { return forward_first_two(projector(c)); }, angleDesc); // MARK: fpeMaskBegin(FLTUND, 1, #2347) @@ -301,10 +308,8 @@ std::tuple mergeGaussianMixture( if (method == ComponentMergeMethod::eMean) { return {mean, cov}; } else if (method == ComponentMergeMethod::eMaxWeight) { - const BoundVector mode = mergeGaussianMixtureMode(cmps, [&](const auto &c) { - auto [weight_l, pars_l, cov_l] = projector(c); - return std::tuple(std::move(weight_l), std::move(pars_l)); - }); + const BoundVector mode = mergeGaussianMixtureMode( + cmps, [&](const auto &c) { return forward_first_two(projector(c)); }); return {mode, cov}; } else { throw std::logic_error("Invalid component merge method"); diff --git a/Core/src/TrackFitting/detail/GsfComponentMerging.cpp b/Core/src/TrackFitting/detail/GsfComponentMerging.cpp index 831caf3bbca..2b864be2414 100644 --- a/Core/src/TrackFitting/detail/GsfComponentMerging.cpp +++ b/Core/src/TrackFitting/detail/GsfComponentMerging.cpp @@ -15,7 +15,12 @@ namespace Acts { std::tuple detail::Gsf::mergeGaussianMixture( std::span mixture, const Surface &surface, ComponentMergeMethod method) { - return mergeGaussianMixture(mixture, std::identity{}, surface, method); + return mergeGaussianMixture( + mixture, + [](const GsfComponent &c) { + return std::tie(c.weight, c.boundPars, c.boundCov); + }, + surface, method); } GsfComponent detail::Gsf::mergeTwoComponents(const GsfComponent &a, diff --git a/Tests/UnitTests/Core/TrackFitting/GsfComponentMergingTests.cpp b/Tests/UnitTests/Core/TrackFitting/GsfComponentMergingTests.cpp index 41fb0b1ffa7..7e3d258bc2f 100644 --- a/Tests/UnitTests/Core/TrackFitting/GsfComponentMergingTests.cpp +++ b/Tests/UnitTests/Core/TrackFitting/GsfComponentMergingTests.cpp @@ -301,7 +301,11 @@ BOOST_AUTO_TEST_CASE(test_with_data_circular) { using detail::Gsf::CyclicAngle; const auto d = std::tuple, CyclicAngle>{}; const auto [mean_test, boundCov_test] = detail::Gsf::mergeGaussianMixture( - cmps, std::identity{}, d, ComponentMergeMethod::eMean); + cmps, + [](const GsfComponent &c) { + return std::tie(c.weight, c.boundPars, c.boundCov); + }, + d, ComponentMergeMethod::eMean); BOOST_CHECK(std::abs(detail::difference_periodic( mean_data[0], mean_test[0], 2 * std::numbers::pi)) < 1.e-1); From 4d7bf691e032db9d194b679af0c4365e23ab3852 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 23 Feb 2026 17:56:21 +0100 Subject: [PATCH 06/14] simplify --- .../detail/GsfComponentMerging.hpp | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp index c74f96804f4..18cb4e6ed20 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp @@ -121,8 +121,8 @@ BoundVector mergeGaussianMixtureMean(const component_range_t &cmps, const angle_desc_t &angleDesc) { // Early return in case of range with length 1 if (cmps.size() == 1) { - decltype(auto) weight_pars_l = projector(cmps.front()); - return std::get<1>(weight_pars_l); + const auto &[weight_l, pars_l] = projector(cmps.front()); + return pars_l; } // Do the (circular) mean with complex arithmetic. @@ -134,10 +134,7 @@ BoundVector mergeGaussianMixtureMean(const component_range_t &cmps, double sumOfWeights = 0; for (const auto &cmp : cmps) { - decltype(auto) weight_pars_l = projector(cmp); - const double weight_l = std::get<0>(weight_pars_l); - const auto &pars_l = std::get<1>(weight_pars_l); - + const auto &[weight_l, pars_l] = projector(cmp); CVec cPars_l = pars_l; const auto setPolar = [&](const auto &desc) { @@ -172,11 +169,11 @@ BoundVector mergeGaussianMixtureMode(const component_range_t &cmps, const projector_t &projector) { const auto maxWeightIt = std::ranges::max_element(cmps, {}, [&](const auto &cmp) { - decltype(auto) weight_pars = projector(cmp); - return std::get<0>(weight_pars); + const auto &[weight_l, pars_l] = projector(cmp); + return weight_l; }); - decltype(auto) weight_pars = projector(*maxWeightIt); - return std::get<1>(weight_pars); + const auto &[weight_max, pars_max] = projector(*maxWeightIt); + return pars_max; } /// Compute the covariance of a Gaussian mixture given the mean. The function @@ -194,18 +191,15 @@ BoundMatrix mergeGaussianMixtureCov(const component_range_t &cmps, const BoundVector &mean, const angle_desc_t &angleDesc) { if (cmps.size() == 1) { - decltype(auto) weight_pars_cov_l = projector(cmps.front()); - return std::get<2>(weight_pars_cov_l); + const auto &[weight_l, pars_l, cov_l] = projector(cmps.front()); + return cov_l; } BoundMatrix cov = BoundMatrix::Zero(); double sumOfWeights = 0; for (const auto &cmp : cmps) { - decltype(auto) weight_pars_cov_l = projector(cmp); - const double weight_l = std::get<0>(weight_pars_cov_l); - const auto &pars_l = std::get<1>(weight_pars_cov_l); - const auto &cov_l = std::get<2>(weight_pars_cov_l); + const auto &[weight_l, pars_l, cov_l] = projector(cmp); cov += weight_l * cov_l; // MARK: fpeMask(FLTUND, 1, #2347) @@ -249,8 +243,8 @@ std::tuple mergeGaussianMixtureMeanCov( const component_range_t &cmps, const projector_t &projector, const angle_desc_t &angleDesc) { if (cmps.size() == 1) { - decltype(auto) weight_pars_cov_l = projector(cmps.front()); - return {std::get<1>(weight_pars_cov_l), std::get<2>(weight_pars_cov_l)}; + const auto &[weight_l, pars_l, cov_l] = projector(cmps.front()); + return {pars_l, cov_l}; } const BoundVector mean = mergeGaussianMixtureMean( @@ -302,7 +296,7 @@ template mergeGaussianMixture( const component_range_t &cmps, const projector_t &projector, const angle_desc_t &angleDesc, ComponentMergeMethod method) { - const auto [mean, cov] = + const auto &[mean, cov] = mergeGaussianMixtureMeanCov(cmps, projector, angleDesc); if (method == ComponentMergeMethod::eMean) { From 659d8e3688d7c322226725988c8a66f640cd6c5c Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 23 Feb 2026 23:26:40 +0100 Subject: [PATCH 07/14] try again --- Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp index 18cb4e6ed20..9718de46389 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp @@ -21,7 +21,7 @@ namespace Acts::detail::Gsf { template -auto forward_first_two(Tuple &&t) { +decltype(auto) forward_first_two(Tuple &&t) { return std::forward_as_tuple(std::get<0>(std::forward(t)), std::get<1>(std::forward(t))); } From 35a846170f3937cb55ebc17218b109cb7b150632 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 23 Feb 2026 23:52:54 +0100 Subject: [PATCH 08/14] try again --- .../TrackFitting/detail/GsfComponentMerging.hpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp index 9718de46389..be1a94d2717 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp @@ -20,12 +20,6 @@ namespace Acts::detail::Gsf { -template -decltype(auto) forward_first_two(Tuple &&t) { - return std::forward_as_tuple(std::get<0>(std::forward(t)), - std::get<1>(std::forward(t))); -} - /// Reduce Gaussian mixture into a single parameter vector and covariance, using /// the specified method to reduce the mixture. /// @@ -248,7 +242,10 @@ std::tuple mergeGaussianMixtureMeanCov( } const BoundVector mean = mergeGaussianMixtureMean( - cmps, [&](const auto &c) { return forward_first_two(projector(c)); }, + cmps, + [&](const auto &c) -> decltype(auto) { + return forward_first_two(projector(c)); + }, angleDesc); // MARK: fpeMaskBegin(FLTUND, 1, #2347) @@ -302,8 +299,10 @@ std::tuple mergeGaussianMixture( if (method == ComponentMergeMethod::eMean) { return {mean, cov}; } else if (method == ComponentMergeMethod::eMaxWeight) { - const BoundVector mode = mergeGaussianMixtureMode( - cmps, [&](const auto &c) { return forward_first_two(projector(c)); }); + const BoundVector mode = + mergeGaussianMixtureMode(cmps, [&](const auto &c) -> decltype(auto) { + return forward_first_two(projector(c)); + }); return {mode, cov}; } else { throw std::logic_error("Invalid component merge method"); From 00e57682d4b19eab202a81bb700a1e8b6fe24e1e Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Tue, 24 Feb 2026 00:36:48 +0100 Subject: [PATCH 09/14] try again --- .../detail/GsfComponentMerging.hpp | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp index be1a94d2717..f5642adc2a3 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp @@ -20,6 +20,12 @@ namespace Acts::detail::Gsf { +template +auto forward_first_two(Tuple &&t) { + return std::forward_as_tuple(std::get<0>(std::forward(t)), + std::get<1>(std::forward(t))); +} + /// Reduce Gaussian mixture into a single parameter vector and covariance, using /// the specified method to reduce the mixture. /// @@ -115,7 +121,7 @@ BoundVector mergeGaussianMixtureMean(const component_range_t &cmps, const angle_desc_t &angleDesc) { // Early return in case of range with length 1 if (cmps.size() == 1) { - const auto &[weight_l, pars_l] = projector(cmps.front()); + const auto [weight_l, pars_l] = projector(cmps.front()); return pars_l; } @@ -128,7 +134,7 @@ BoundVector mergeGaussianMixtureMean(const component_range_t &cmps, double sumOfWeights = 0; for (const auto &cmp : cmps) { - const auto &[weight_l, pars_l] = projector(cmp); + const auto [weight_l, pars_l] = projector(cmp); CVec cPars_l = pars_l; const auto setPolar = [&](const auto &desc) { @@ -163,10 +169,10 @@ BoundVector mergeGaussianMixtureMode(const component_range_t &cmps, const projector_t &projector) { const auto maxWeightIt = std::ranges::max_element(cmps, {}, [&](const auto &cmp) { - const auto &[weight_l, pars_l] = projector(cmp); + const auto [weight_l, pars_l] = projector(cmp); return weight_l; }); - const auto &[weight_max, pars_max] = projector(*maxWeightIt); + const auto [weight_max, pars_max] = projector(*maxWeightIt); return pars_max; } @@ -185,7 +191,7 @@ BoundMatrix mergeGaussianMixtureCov(const component_range_t &cmps, const BoundVector &mean, const angle_desc_t &angleDesc) { if (cmps.size() == 1) { - const auto &[weight_l, pars_l, cov_l] = projector(cmps.front()); + const auto [weight_l, pars_l, cov_l] = projector(cmps.front()); return cov_l; } @@ -193,7 +199,7 @@ BoundMatrix mergeGaussianMixtureCov(const component_range_t &cmps, double sumOfWeights = 0; for (const auto &cmp : cmps) { - const auto &[weight_l, pars_l, cov_l] = projector(cmp); + const auto [weight_l, pars_l, cov_l] = projector(cmp); cov += weight_l * cov_l; // MARK: fpeMask(FLTUND, 1, #2347) @@ -237,15 +243,12 @@ std::tuple mergeGaussianMixtureMeanCov( const component_range_t &cmps, const projector_t &projector, const angle_desc_t &angleDesc) { if (cmps.size() == 1) { - const auto &[weight_l, pars_l, cov_l] = projector(cmps.front()); + const auto [weight_l, pars_l, cov_l] = projector(cmps.front()); return {pars_l, cov_l}; } const BoundVector mean = mergeGaussianMixtureMean( - cmps, - [&](const auto &c) -> decltype(auto) { - return forward_first_two(projector(c)); - }, + cmps, [&](const auto &c) { return forward_first_two(projector(c)); }, angleDesc); // MARK: fpeMaskBegin(FLTUND, 1, #2347) @@ -299,10 +302,8 @@ std::tuple mergeGaussianMixture( if (method == ComponentMergeMethod::eMean) { return {mean, cov}; } else if (method == ComponentMergeMethod::eMaxWeight) { - const BoundVector mode = - mergeGaussianMixtureMode(cmps, [&](const auto &c) -> decltype(auto) { - return forward_first_two(projector(c)); - }); + const BoundVector mode = mergeGaussianMixtureMode( + cmps, [&](const auto &c) { return forward_first_two(projector(c)); }); return {mode, cov}; } else { throw std::logic_error("Invalid component merge method"); From c29121876e821d3f1d90af00e7c348f8f621293d Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Tue, 24 Feb 2026 00:51:38 +0100 Subject: [PATCH 10/14] try again --- Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp index f5642adc2a3..23d10dd8799 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp @@ -296,7 +296,7 @@ template mergeGaussianMixture( const component_range_t &cmps, const projector_t &projector, const angle_desc_t &angleDesc, ComponentMergeMethod method) { - const auto &[mean, cov] = + const auto [mean, cov] = mergeGaussianMixtureMeanCov(cmps, projector, angleDesc); if (method == ComponentMergeMethod::eMean) { From 791e6f1f2fbc587172eabad7249b61fc0174fdcc Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Tue, 24 Feb 2026 01:10:24 +0100 Subject: [PATCH 11/14] try agagin --- .../detail/GsfComponentMerging.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp index 23d10dd8799..16b40125ea7 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp @@ -20,12 +20,6 @@ namespace Acts::detail::Gsf { -template -auto forward_first_two(Tuple &&t) { - return std::forward_as_tuple(std::get<0>(std::forward(t)), - std::get<1>(std::forward(t))); -} - /// Reduce Gaussian mixture into a single parameter vector and covariance, using /// the specified method to reduce the mixture. /// @@ -248,7 +242,11 @@ std::tuple mergeGaussianMixtureMeanCov( } const BoundVector mean = mergeGaussianMixtureMean( - cmps, [&](const auto &c) { return forward_first_two(projector(c)); }, + cmps, + [&](const auto &c) { + const auto [weight_l, pars_l, cov_l] = projector(c); + return std::tuple(weight_l, pars_l); + }, angleDesc); // MARK: fpeMaskBegin(FLTUND, 1, #2347) @@ -302,8 +300,10 @@ std::tuple mergeGaussianMixture( if (method == ComponentMergeMethod::eMean) { return {mean, cov}; } else if (method == ComponentMergeMethod::eMaxWeight) { - const BoundVector mode = mergeGaussianMixtureMode( - cmps, [&](const auto &c) { return forward_first_two(projector(c)); }); + const BoundVector mode = mergeGaussianMixtureMode(cmps, [&](const auto &c) { + const auto [weight_l, pars_l, cov_l] = projector(c); + return std::tuple(weight_l, pars_l); + }); return {mode, cov}; } else { throw std::logic_error("Invalid component merge method"); From 97503cec5b33595f09f04618df57da22e3a858ff Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Tue, 24 Feb 2026 15:53:31 +0100 Subject: [PATCH 12/14] try again --- .../detail/GsfComponentMerging.hpp | 18 +++++++++--------- .../Acts/TrackFitting/detail/GsfUtils.hpp | 19 ++++++++++++------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp index 16b40125ea7..23d10dd8799 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp @@ -20,6 +20,12 @@ namespace Acts::detail::Gsf { +template +auto forward_first_two(Tuple &&t) { + return std::forward_as_tuple(std::get<0>(std::forward(t)), + std::get<1>(std::forward(t))); +} + /// Reduce Gaussian mixture into a single parameter vector and covariance, using /// the specified method to reduce the mixture. /// @@ -242,11 +248,7 @@ std::tuple mergeGaussianMixtureMeanCov( } const BoundVector mean = mergeGaussianMixtureMean( - cmps, - [&](const auto &c) { - const auto [weight_l, pars_l, cov_l] = projector(c); - return std::tuple(weight_l, pars_l); - }, + cmps, [&](const auto &c) { return forward_first_two(projector(c)); }, angleDesc); // MARK: fpeMaskBegin(FLTUND, 1, #2347) @@ -300,10 +302,8 @@ std::tuple mergeGaussianMixture( if (method == ComponentMergeMethod::eMean) { return {mean, cov}; } else if (method == ComponentMergeMethod::eMaxWeight) { - const BoundVector mode = mergeGaussianMixtureMode(cmps, [&](const auto &c) { - const auto [weight_l, pars_l, cov_l] = projector(c); - return std::tuple(weight_l, pars_l); - }); + const BoundVector mode = mergeGaussianMixtureMode( + cmps, [&](const auto &c) { return forward_first_two(projector(c)); }); return {mode, cov}; } else { throw std::logic_error("Invalid component merge method"); diff --git a/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp b/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp index c2baf96c637..aa283426501 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp @@ -217,21 +217,26 @@ inline std::ostream &operator<<(std::ostream &os, StatesType type) { /// [weight, parameters, covariance]. Therefore, it contains a MultiTrajectory /// and for now a std::map for the weights template -struct MultiTrajectoryProjector { - const traj_t &mt; - const std::map &weights; +class MultiTrajectoryProjector { + const traj_t *mt{}; + const std::map *weights{}; + + public: + MultiTrajectoryProjector(const traj_t &mt, + const std::map &weights) + : mt(&mt), weights(&weights) {} auto operator()(TrackIndexType idx) const { - const auto proxy = mt.getTrackState(idx); + const auto proxy = mt->getTrackState(idx); switch (type) { case StatesType::ePredicted: - return std::tuple(weights.at(idx), proxy.predicted(), + return std::tuple(weights->at(idx), proxy.predicted(), proxy.predictedCovariance()); case StatesType::eFiltered: - return std::tuple(weights.at(idx), proxy.filtered(), + return std::tuple(weights->at(idx), proxy.filtered(), proxy.filteredCovariance()); case StatesType::eSmoothed: - return std::tuple(weights.at(idx), proxy.smoothed(), + return std::tuple(weights->at(idx), proxy.smoothed(), proxy.smoothedCovariance()); default: throw std::invalid_argument( From 2d233b6733f8dd1d59a68d0baebaa29d6fdf1396 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Tue, 24 Feb 2026 16:26:05 +0100 Subject: [PATCH 13/14] Revert "try again" This reverts commit 97503cec5b33595f09f04618df57da22e3a858ff. --- .../detail/GsfComponentMerging.hpp | 18 +++++++++--------- .../Acts/TrackFitting/detail/GsfUtils.hpp | 19 +++++++------------ 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp index 23d10dd8799..16b40125ea7 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp @@ -20,12 +20,6 @@ namespace Acts::detail::Gsf { -template -auto forward_first_two(Tuple &&t) { - return std::forward_as_tuple(std::get<0>(std::forward(t)), - std::get<1>(std::forward(t))); -} - /// Reduce Gaussian mixture into a single parameter vector and covariance, using /// the specified method to reduce the mixture. /// @@ -248,7 +242,11 @@ std::tuple mergeGaussianMixtureMeanCov( } const BoundVector mean = mergeGaussianMixtureMean( - cmps, [&](const auto &c) { return forward_first_two(projector(c)); }, + cmps, + [&](const auto &c) { + const auto [weight_l, pars_l, cov_l] = projector(c); + return std::tuple(weight_l, pars_l); + }, angleDesc); // MARK: fpeMaskBegin(FLTUND, 1, #2347) @@ -302,8 +300,10 @@ std::tuple mergeGaussianMixture( if (method == ComponentMergeMethod::eMean) { return {mean, cov}; } else if (method == ComponentMergeMethod::eMaxWeight) { - const BoundVector mode = mergeGaussianMixtureMode( - cmps, [&](const auto &c) { return forward_first_two(projector(c)); }); + const BoundVector mode = mergeGaussianMixtureMode(cmps, [&](const auto &c) { + const auto [weight_l, pars_l, cov_l] = projector(c); + return std::tuple(weight_l, pars_l); + }); return {mode, cov}; } else { throw std::logic_error("Invalid component merge method"); diff --git a/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp b/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp index aa283426501..c2baf96c637 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfUtils.hpp @@ -217,26 +217,21 @@ inline std::ostream &operator<<(std::ostream &os, StatesType type) { /// [weight, parameters, covariance]. Therefore, it contains a MultiTrajectory /// and for now a std::map for the weights template -class MultiTrajectoryProjector { - const traj_t *mt{}; - const std::map *weights{}; - - public: - MultiTrajectoryProjector(const traj_t &mt, - const std::map &weights) - : mt(&mt), weights(&weights) {} +struct MultiTrajectoryProjector { + const traj_t &mt; + const std::map &weights; auto operator()(TrackIndexType idx) const { - const auto proxy = mt->getTrackState(idx); + const auto proxy = mt.getTrackState(idx); switch (type) { case StatesType::ePredicted: - return std::tuple(weights->at(idx), proxy.predicted(), + return std::tuple(weights.at(idx), proxy.predicted(), proxy.predictedCovariance()); case StatesType::eFiltered: - return std::tuple(weights->at(idx), proxy.filtered(), + return std::tuple(weights.at(idx), proxy.filtered(), proxy.filteredCovariance()); case StatesType::eSmoothed: - return std::tuple(weights->at(idx), proxy.smoothed(), + return std::tuple(weights.at(idx), proxy.smoothed(), proxy.smoothedCovariance()); default: throw std::invalid_argument( From 4032b3dce911fa433ac66ddbe51bf209623df881 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Wed, 25 Feb 2026 09:48:28 +0100 Subject: [PATCH 14/14] pr feedback --- .../detail/GsfComponentMerging.hpp | 38 ++++++++----------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp index 16b40125ea7..d542fcd4a33 100644 --- a/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp +++ b/Core/include/Acts/TrackFitting/detail/GsfComponentMerging.hpp @@ -97,12 +97,8 @@ auto angleDescriptionSwitch(const Surface &surface, Callable &&callable) { } /// Combine multiple components into one representative parameter object. The -/// function takes iterators to allow for arbitrary ranges to be combined. -/// -/// @note The correct mean and variances for cyclic coordinates or spherical -/// coordinates (theta, phi) must generally be computed using a special circular -/// mean or in cartesian coordinates. This implements a approximation, which -/// only works well for close components. +/// function takes a range and a projector to allow for arbitrary input to be +/// combined. /// /// @param cmps The component range to merge /// @param projector A projector to extract the weight and parameters from the components @@ -153,14 +149,15 @@ BoundVector mergeGaussianMixtureMean(const component_range_t &cmps, } /// Combine multiple components into one representative parameter object. The -/// function takes iterators to allow for arbitrary ranges to be combined. +/// function takes a range and a projector to allow for arbitrary input to be +/// combined. /// /// @param cmps The component range to merge /// @param projector A projector to extract the weight and parameters from the components /// @return parameters template -BoundVector mergeGaussianMixtureMode(const component_range_t &cmps, - const projector_t &projector) { +BoundVector mergeGaussianMixtureMaxWeight(const component_range_t &cmps, + const projector_t &projector) { const auto maxWeightIt = std::ranges::max_element(cmps, {}, [&](const auto &cmp) { const auto [weight_l, pars_l] = projector(cmp); @@ -171,7 +168,7 @@ BoundVector mergeGaussianMixtureMode(const component_range_t &cmps, } /// Compute the covariance of a Gaussian mixture given the mean. The function -/// takes iterators to allow for arbitrary ranges to be combined. +/// takes a range and a projector to allow for arbitrary input to be combined. /// /// @param cmps The component range to merge /// @param projector A projector to extract the weight and parameters from the components @@ -218,13 +215,9 @@ BoundMatrix mergeGaussianMixtureCov(const component_range_t &cmps, return cov; } -/// Combine multiple components into one representative track state object. The -/// function takes iterators to allow for arbitrary ranges to be combined. -/// -/// @note The correct mean and variances for cyclic coordinates or spherical -/// coordinates (theta, phi) must generally be computed using a special circular -/// mean or in cartesian coordinates. This implements a approximation, which -/// only works well for close components. +/// Combine multiple components into one representative parameter object. The +/// function takes a range and a projector to allow for arbitrary input to be +/// combined. /// /// @param cmps The component range to merge /// @param projector A projector to extract the weight, parameters and covariance @@ -274,7 +267,7 @@ BoundVector mergeGaussianMixtureParams(const component_range_t &cmps, if (method == ComponentMergeMethod::eMean) { return mergeGaussianMixtureMean(cmps, projector, angleDesc); } else if (method == ComponentMergeMethod::eMaxWeight) { - return mergeGaussianMixtureMode(cmps, projector); + return mergeGaussianMixtureMaxWeight(cmps, projector); } else { throw std::logic_error("Invalid component merge method"); } @@ -300,10 +293,11 @@ std::tuple mergeGaussianMixture( if (method == ComponentMergeMethod::eMean) { return {mean, cov}; } else if (method == ComponentMergeMethod::eMaxWeight) { - const BoundVector mode = mergeGaussianMixtureMode(cmps, [&](const auto &c) { - const auto [weight_l, pars_l, cov_l] = projector(c); - return std::tuple(weight_l, pars_l); - }); + const BoundVector mode = + mergeGaussianMixtureMaxWeight(cmps, [&](const auto &c) { + const auto [weight_l, pars_l, cov_l] = projector(c); + return std::tuple(weight_l, pars_l); + }); return {mode, cov}; } else { throw std::logic_error("Invalid component merge method");