< If this grows greater than one then we have to start culling features from legs
< How many features the leg at keepLegIndex can afford to lose before it starts to fail its multiplicity requirement.
152 {
154
155
158
159
161
162
163
165 const HLT::Identifier chainId = HLT::Identifier(chainName);
167
169 allDecisionIds.insert(requiredDecisionID);
170
171 bool overallDecision = true;
172
173 std::vector< SG::SGKeySet > legFeatureHashes;
174 legFeatureHashes.resize( multiplicityPerLeg.size() );
176
178
179
180
181
182
183
184
185
186
188
189
190 for ( size_t legIndex = 0; legIndex < multiplicityPerLeg.size(); ++legIndex ) {
191 const size_t requiredMultiplicity = multiplicityPerLeg.at( legIndex );
192
193 HLT::Identifier legId = chainId;
194
195 if (multiplicityPerLeg.size() > 1) {
196 ATH_MSG_DEBUG(chainId <<
" has multiplicityPerLeg.size() > 1, so we use legXXX_HLT_YYY, instead of HLT_YYY");
198 }
199
201 ATH_MSG_DEBUG(
"Container " << legIndex <<
", looking at leg : " << legId );
202
203 Combo::LegDecisionsMap::const_iterator
it = dmap.find(requiredDecisionIDLeg);
204 if ( it == dmap.end() ) {
205 continue;
206 }
207
208
209 const size_t nLegDecisionObjects =
it->second.size();
210
211 ATH_MSG_DEBUG(
"Will attempt to meet the required multiplicity of " << requiredMultiplicity <<
" for leg " << legId
212 << " with " << nLegDecisionObjects << " Decision Objects in leg " << legIndex << " of " << legId);
213
214
215
216
217
218
219
220
221
222
223
224
225
226 for (
const ElementLink<DecisionContainer>& dEL :
it->second){
230 bool roiIsFullscan = false;
231 bool objectRequestsNoMultiplicityCheck = false;
232 ATH_CHECK(
extractFeatureAndRoI(
it->first, dEL, featureKey, featureIndex, roiKey, roiIndex, roiIsFullscan, objectRequestsNoMultiplicityCheck, priorFeaturesMap) );
233 const bool theFeatureIsTheROI = (
SG::sgkeyEqual (featureKey, roiKey) and featureIndex == roiIndex);
234 const bool thereIsNoFeatureYet = (featureKey == 0 and roiKey != 0);
235 if (objectRequestsNoMultiplicityCheck or (roiIsFullscan and (theFeatureIsTheROI or thereIsNoFeatureYet))) {
236
237 for (
size_t i = 0;
i < requiredMultiplicity; ++
i) {
238 legFeatureHashes.at( legIndex ).insert( ++passthroughCounter );
239 ATH_MSG_DEBUG(
" -- Add feature hash '" << passthroughCounter <<
"' to leg " << legIndex
240 << ". (Note: unique passing hash generated from " << (objectRequestsNoMultiplicityCheck ? "an object requesting NO multiplicity checks" : "an FullScan ROI") << ")");
241 }
242 } else {
243 const SG::sgkey_t uniquenessHash = (featureKey != 0 ? (featureKey + featureIndex) : (roiKey + roiIndex));
244 legFeatureHashes.at( legIndex ).insert( uniquenessHash );
245 ATH_MSG_DEBUG(
" -- Add feature hash '" << uniquenessHash <<
"' to leg " << legIndex <<
".");
246 }
247 }
248
249
250 thisChainCombMap.insert (*it);
251 allDecisionIds.insert(requiredDecisionIDLeg);
252
253 }
254
255
256
258
259 size_t emergencyBreak = 0;
260 while (true) {
261 bool somethingChanged = false;
263 for (auto const& [key, payloadSet] : priorFeaturesMap) {
264 if (payloadSet.count(legHash) == 1) {
265 ATH_MSG_DEBUG(
"Feature hash=" << legHash <<
" identified as a prior feature of hash=" << key
266 << ", we will up-cast this hash to the later version for ComboHypo uniqueness comparison purposes.");
267 legHashes.erase(legHash);
268 legHashes.insert(key);
269
270
271 somethingChanged = true;
272 break;
273 }
274 }
275 if (somethingChanged) {
276 break;
277 }
278 }
279 if (!somethingChanged or ++emergencyBreak == 500) {
280 if (emergencyBreak == 500) {
282 }
283 break;
284 }
285 }
286 }
287
288
289
290
291
292
293
294 std::set<SG::sgkey_t> allFeatureHashes;
295 for (
const SG::SGKeySet& legHashes : legFeatureHashes) {
296 allFeatureHashes.insert(legHashes.begin(), legHashes.end());
297 }
298 for (
const SG::sgkey_t featureHash : allFeatureHashes) {
299 size_t legsWithHash = 0;
300 size_t keepLegIndex = 0;
301 int32_t keepLegMargin = std::numeric_limits<int32_t>::max();
302 for (size_t legIndex = 0; legIndex < multiplicityPerLeg.size(); ++legIndex) {
303 if (legFeatureHashes.at(legIndex).count(featureHash) == 0) {
304 continue;
305 }
306 ++legsWithHash;
307 const int32_t requiredMultiplicity = multiplicityPerLeg.at(legIndex);
308 const int32_t currentMultiplicity = legFeatureHashes.at(legIndex).size();
309 const int32_t safetyMargin = currentMultiplicity - requiredMultiplicity;
310 if (safetyMargin < keepLegMargin) {
311 keepLegMargin = safetyMargin;
312 keepLegIndex = legIndex;
313 }
314 }
315 if (legsWithHash == 1) {
316 continue;
317 }
318
319 for (size_t legIndex = 0; legIndex < multiplicityPerLeg.size(); ++legIndex) {
320 if (legIndex == keepLegIndex) {
321 ATH_MSG_DEBUG(
"Keeping feature hash '" << featureHash <<
"', on leg " << legIndex <<
". This leg can least afford to lose it. "
322 << "Leg has " << legFeatureHashes.at(legIndex).size()
323 << " features, and a multiplicity requirement of " << multiplicityPerLeg.at(legIndex));
324 continue;
325 }
326 if (legFeatureHashes.at(legIndex).erase(featureHash)) {
327 ATH_MSG_DEBUG(
"Removed duplicate feature hash '" << featureHash <<
"', from leg " << legIndex <<
". Leg now has " << legFeatureHashes.at(legIndex).size()
328 << " remaining features, and a multiplicity requirement of " << multiplicityPerLeg.at(legIndex));
329 }
330 }
331 }
332
333
334 for (size_t legIndex = 0; legIndex < multiplicityPerLeg.size(); ++legIndex) {
335 const size_t requiredMultiplicity = multiplicityPerLeg.at(legIndex);
336 const size_t currentMultiplicity = legFeatureHashes.at(legIndex).size();
337 if (currentMultiplicity < requiredMultiplicity) {
338 ATH_MSG_DEBUG(
"Leg " << legIndex <<
" fails multiplicity check. Required unique features:" << requiredMultiplicity <<
", found unique features: " << currentMultiplicity);
339 overallDecision = false;
340 break;
341 }
342 }
343
344
345 ATH_MSG_DEBUG(
"Chain " << chainId << ( overallDecision ?
" is accepted" :
" is rejected") <<
" after multiplicity requirements" );
346 if ( overallDecision == true ) {
347 for (auto decID: allDecisionIds) {
348
349 passingLegs.insert (thisChainCombMap.begin(), thisChainCombMap.end());
350 ATH_MSG_DEBUG(
" Passing " << HLT::Identifier(decID)<<
" after multiplicity test");
351 }
352 }
353 }
354
355 if (passingLegs.size()!=0){
356
361 }
362 }
363
364
366 for (auto const& [id, decisions] : passingLegs) {
368 }
369 }
370
371
373
374 return StatusCode::SUCCESS;
375}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x)
StatusCode extractFeatureAndRoI(const HLT::Identifier &chainLegId, const ElementLink< TrigCompositeUtils::DecisionContainer > &EL, SG::sgkey_t &featureKey, TrigCompositeUtils::Decision::index_type &featureIndex, SG::sgkey_t &roiKey, TrigCompositeUtils::Decision::index_type &roiIndex, bool &roiFullscan, bool &objectRequestsNoMultiplicityCheck, SG::SGKeyMap< std::set< uint32_t > > &priorFeaturesMap) const
For a given Decision node from a HypoAlg, extracts type-less identification data on the node's Featur...
StatusCode copyDecisions(const Combo::LegDecisionsMap &passingLegs, const EventContext &context) const
iterates over the inputs and for every object (no filtering) crates output object linked to input mov...
Gaudi::Property< Combo::MultiplicityReqMap > m_multiplicitiesReqMap
StatusCode fillDecisionsMap(Combo::LegDecisionsMap &dmap, const EventContext &context) const
iterates over all inputs, associating inputs to legs
ToolHandleArray< ComboHypoToolBase > m_hypoTools
std::map< TrigCompositeUtils::DecisionID, std::vector< ElementLink< TrigCompositeUtils::DecisionContainer > > > LegDecisionsMap
LegDecisionsMap For a given chain leg key, this map holds all Decision Objects which are active on th...
uint32_t sgkey_t
Type used for hashed StoreGate key+CLID pairs.
std::unordered_set< sgkey_t > SGKeySet
A set of sgkey_t values.
constexpr bool sgkeyEqual(const sgkey_t a, const sgkey_t b)
Compare two sgkeys for equality.
std::unordered_map< sgkey_t, T > SGKeyMap
A map using sgkey_t as a key.
HLT::Identifier createLegName(const HLT::Identifier &chainIdentifier, size_t counter)
Generate the HLT::Identifier which corresponds to a specific leg of a given chain.