Feature Selection Toolbox FST4
UTIA · Czech Academy of Sciences
Loading...
Searching...
No Matches
seq_step_ensemble.hpp
Go to the documentation of this file.
1#ifndef FSTSEARCHSEQSTEPENSEMBLE_H
2#define FSTSEARCHSEQSTEPENSEMBLE_H
3 /*
27=========================================================================
28Copyright and license:
29 * FST4 software (with the exception of any bundled or externally linked
30 third-party components) is Copyright (C) 2000-present Institute of
31 Information Theory and Automation of the Czech Academy of Sciences (UTIA).
32 * FST4 is free software: you can redistribute it and/or modify it under
33 the terms of the GNU Affero General Public License as published by the
34 Free Software Foundation, version 3. The full text of the license is in
35 the file LICENSE in the distribution root and at
36 https://www.gnu.org/licenses/agpl-3.0.html.
37 * FST4 is distributed in the hope that it will be useful, but WITHOUT ANY
38 WARRANTY; without even the implied warranty of MERCHANTABILITY or
39 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
40 License for more details.
41 * Closed-source use without the AGPL's copyleft obligations requires a
42 commercial license from UTIA; in case of interest write to
43 utia@utia.cas.cz. LICENSING.md in the distribution root explains both
44 options, the contributor license agreement that every contribution
45 requires, and the contacts (technical questions and pull requests:
46 somol@utia.cas.cz, with "FST" in the subject line).
47========================================================================== */
48
49#include <memory>
50#include <cassert>
51#include <iostream>
52#include <sstream>
53#include <list>
54#include <vector>
55#include <map>
56#include "error.hpp"
57#include "global.hpp"
58#include "seq_step.hpp"
59#include "criterion.hpp"
62
63/*============== Template parameter type naming conventions ==============
64--------- Numeric types: -------------------------------------------------
65DATATYPE - data sample values - usually real numbers (but may be integers
66 in text processing etc.)
67REALTYPE - must be real numbers - for representing intermediate results of
68 calculations like mean, covariance etc.
69IDXTYPE - index values for enumeration of data samples - (nonnegative) integers,
70 extent depends on numbers of samples in data
71DIMTYPE - index values for enumeration of features (dimensions), or classes (not
72 class sizes) - (nonnegative) integers, usually lower extent than IDXTYPE,
73 but be aware of expressions like _classes*_features*_features !
74 in linearized representations of feature matrices for all classes
75BINTYPE - feature selection marker type - represents ca. <10 different feature
76 states (selected, deselected, sel./desel. temporarily 1st nested loop, 2nd...)
77RETURNTYPE - criterion value: real value, but may be extended in future to support
78 multiple values
79--------- Class types: ---------------------------------------------------
80SUBSET - class of class type Subset
81CLASSIFIER - class implementing interface defined in abstract class Classifier
82EVALUATOR - class implementing interface defined in abstract class Sequential_Step
83DISTANCE - class implementing interface defined in abstract class Distance
84DATAACCESSOR - class implementing interface defined in abstract class Data_Accessor
85INTERVALCONTAINER - class of class type Data_Intervaller
86CONTAINER - STL container of class type Data_Interval
87========================================================================== */
88
89namespace FST {
90
91//----------------------------------------------------------------------------
92
139template<class RETURNTYPE, typename DIMTYPE, class SUBSET, class CRITERION>
140class Sequential_Step_Ensemble : public Sequential_Step<RETURNTYPE,DIMTYPE,SUBSET,CRITERION>{
141public:
142 typedef Sequential_Step<RETURNTYPE,DIMTYPE,SUBSET,CRITERION> parent;
143 typedef std::shared_ptr<CRITERION> PCriterion;
144 typedef std::shared_ptr<Criterion<RETURNTYPE,SUBSET> > PAbstractCriterion;
145 typedef std::vector<PAbstractCriterion> PAbstractCriteria;
146 typedef std::shared_ptr<PAbstractCriteria> PEnsembleCriteria;
147 typedef std::shared_ptr<SUBSET> PSubset;
149 typedef std::shared_ptr<EVALUATORENGINE> PEvaluatorEngine;
155 Sequential_Step_Ensemble(const PEnsembleCriteria ensemble, PEvaluatorEngine engine=PEvaluatorEngine()):Sequential_Step<RETURNTYPE,DIMTYPE,SUBSET,CRITERION>(),_engine(engine),track(false) {assert(ensemble); _ensemble=ensemble; if(!_engine) _engine.reset(new Candidate_Evaluator_Sequential<RETURNTYPE,DIMTYPE,SUBSET,Criterion<RETURNTYPE,SUBSET> >()); notify("Sequential_Step_Ensemble constructor.");}
156 virtual ~Sequential_Step_Ensemble() {notify("Sequential_Step_Ensemble destructor.");}
157
158 // NOTE: crit (as well as all criteria in ensemble) is expected to be already initialize()d before use here
159 inline bool evaluate_candidates(RETURNTYPE &result, const PSubset sub, const PCriterion crit, const DIMTYPE _generalization_level=1, std::ostream& os=std::cout) override;
160
162 virtual std::ostream& print(std::ostream& os) const override {
163 if(_engine->is_threaded()) os << "Sequential_Step_Ensemble(threads="<<_engine->get_max_threads()<<")";
164 else os << "Sequential_Step_Ensemble()";
165 if(parent::result_tracker_active()) os << " with " << *parent::_tracker;
166 return os;
167 }
168protected:
182 inline bool order_candidates(const PSubset sub);
183
186
189 public:
191 SubsetCandidate(const RETURNTYPE value, const PSubset sub, const DIMTYPE tfeature) : _value(value), _sub(new SUBSET(*sub)), _tempfeature(tfeature) {}
195 RETURNTYPE _value;
196 const PSubset _sub;
197 const DIMTYPE _tempfeature;
198 };
199 typedef std::shared_ptr<SubsetCandidate> PSubsetCandidate;
200 typedef std::list<SubsetCandidate> CANDIDATELIST;
201 typedef std::shared_ptr<CANDIDATELIST> PCANDIDATELIST;
202 typedef std::vector<PCANDIDATELIST> CANDIDATELISTS;
204 typedef std::map<DIMTYPE, PSubsetCandidate> FINALVALUES;
206
207 typename CANDIDATELISTS::iterator oiter;
208 typename CANDIDATELIST::iterator iter;
209 typename FINALVALUES::iterator fiter;
210
211private:
212 std::unique_ptr<SUBSET> tmp_step_sub;
213 bool track;
214};
215
216
217template<class RETURNTYPE, typename DIMTYPE, class SUBSET, class CRITERION>
219{
220 assert(sub);
221 assert(_engine);
222 assert(_ensemble);
223 assert(!_ensemble->empty());
224 assert(_ensemble->size()==_lists.size());
225
226 _final.clear();
227
228 // first pass (master, no criterion evaluation): register each candidate's temporary
229 // feature in _final and count the candidates (the threaded engine sizes its result
230 // storage from the count)
231 DIMTYPE _tfeat;
232 DIMTYPE _candidates=0;
233 bool b=sub->getFirstCandidateSubset(1,false/*reverse*/); if(!b) return false; // no candidate subsets can be traversed for whatever reason
234 while(b) {
235 if(!sub->getFirstTemporaryFeature(_tfeat)) return false; // just one exists due to the getFirstCandidateSubset(1,false/*reverse*/) call above
236 assert(_tfeat<sub->get_n());
237 PSubsetCandidate _cs(new SubsetCandidate(0.0,sub,_tfeat));
238 _final.insert( make_pair(_tfeat,_cs));
239 ++_candidates;
240 b=sub->getNextCandidateSubset();
241 }
242 if(_candidates==0) return false;
243
244 // per-member engine batches: candidates are re-enumerated for each ensemble member and
245 // evaluated through the injected engine; the per-result callback (fired on the master in
246 // candidate order) does the sorted insertion into the member's ordered list, so the
247 // resulting lists are the same for any thread count. The candidate's temporary feature
248 // rides along as the engine's feature tag.
249 for(typename PAbstractCriteria::size_type j=0;j<_ensemble->size();j++)
250 {
251 PCANDIDATELIST lst=_lists[j];
252 typename EVALUATORENGINE::ResultCallback on_result=[lst](const RETURNTYPE val, const PSubset &csub, const DIMTYPE tfeat) {
253 typename CANDIDATELIST::iterator it;
254 for(it=lst->begin(); it!=lst->end() && val<it->_value; it++);
255 lst->insert(it,SubsetCandidate(val,csub,tfeat));
256 };
257 _engine->initialize((*_ensemble)[j],_candidates,on_result);
258 b=sub->getFirstCandidateSubset(1,false/*reverse*/); if(!b) return false;
259 while(b) {
260 if(!sub->getFirstTemporaryFeature(_tfeat)) return false;
261 if(!_engine->add_candidate(sub,_tfeat)) return false;
262 b=sub->getNextCandidateSubset();
263 }
264 if(!_engine->collect()) return false;
265 }
266 return true;
267}
268
269template<class RETURNTYPE, typename DIMTYPE, class SUBSET, class CRITERION>
270bool Sequential_Step_Ensemble<RETURNTYPE,DIMTYPE,SUBSET,CRITERION>::evaluate_candidates(RETURNTYPE &result, const PSubset sub, const PCriterion crit, const DIMTYPE _generalization_level, std::ostream& os)
271{
272 assert(sub);
273 assert(sub->get_n()>0);
274 assert(crit);
275 assert(_ensemble);
276 assert(!_ensemble->empty());
277 if(_generalization_level!=1) throw FST::fst_error("Sequential_Step_Ensemble currently does not support generalization level other than 1.");
279
280 _lists.reserve(_ensemble->size());
281 while(_lists.size()<_ensemble->size()) _lists.push_back(PCANDIDATELIST(new CANDIDATELIST));
282 assert(_lists.size()==_ensemble->size());
283 for(oiter=_lists.begin(); oiter!=_lists.end(); oiter++) (*oiter)->clear();
284
285 if(!order_candidates(sub)) {if(parent::output_normal()) {std::ostringstream sos; sos << "FAILURE order_candidates() sub=" << *sub << std::endl << std::endl << std::flush; syncout::print(os,sos);} return false;}
286
287 assert(_final.size()>0);
288 for(fiter=_final.begin();fiter!=_final.end();fiter++) (*fiter).second->_value=0.0;
289
290 // Collect ordering votes: walk each member's best-first list and add the candidate's
291 // RANK (1 = the member's most preferred) to that feature's tally in _final. Ranking is
292 // DENSE and ties-aware - the rank advances only when the criterion value actually drops,
293 // so candidates a member scored equally receive the same rank and the next distinct
294 // value gets rank+1 (not rank+number-of-tied). A feature's tally therefore lies between
295 // (number of members) for a unanimous first choice and (number of members)*(number of
296 // distinct values) at worst, and LOWER is better.
297 RETURNTYPE _lastval;
298 DIMTYPE _curposition;
299 for(oiter=_lists.begin(); oiter!=_lists.end(); oiter++)
300 {
301 iter=(*oiter)->begin();
302 _curposition=1;
303 _lastval=iter->_value;
304 _final[iter->_tempfeature]->_value+=_curposition;
305 iter++;
306 while(iter!=(*oiter)->end())
307 {
308 if(iter->_value<_lastval) {_curposition++; _lastval=iter->_value;}
309 _final[iter->_tempfeature]->_value+=_curposition;
310 iter++;
311 }
312 }
313
314 if(!tmp_step_sub || tmp_step_sub->get_n()<sub->get_n()) tmp_step_sub.reset(new SUBSET(sub->get_n()));
315
316 // Pick the candidate with the LOWEST vote tally. _lastval doubles as the
317 // "nothing picked yet" sentinel: a real tally is at least 1 per ensemble member, so the
318 // initial 0.0 (tested as <1.0) makes the first entry of _final the provisional winner,
319 // after which only a strictly smaller positive tally displaces it. _final is a map keyed
320 // by feature index, so when several features tie on the tally the LOWEST feature index
321 // wins - the step is deterministic.
322 _lastval=0.0;
323 _curposition=0;
324 for(fiter=_final.begin();fiter!=_final.end();fiter++)
325 {
326 if(_lastval<1.0 || ( (*fiter).second->_value < _lastval && (*fiter).second->_value > 0.0 ))
327 {
328 _lastval=(*fiter).second->_value;
329 _curposition=(*fiter).second->_tempfeature;
330 tmp_step_sub->stateless_copy(*((*fiter).second->_sub)); // keep the best candidate's subset
331 }
332 }
333 sub->stateless_copy(*tmp_step_sub);
334 assert(sub->get_d()!=0);
335
336 if(!crit->evaluate(result,sub)) {if(parent::output_normal()) {std::ostringstream sos; sos << "FAILURE crit->eval() sub=" << *(sub) << std::endl << std::endl << std::flush; syncout::print(os,sos);} return false;}
337 if(track) parent::_tracker->add(result,sub);
338
340 std::ostringstream sos;
341 sos << "---------------- "<< std::endl;
342 sos << "candidate lists: "<< std::endl;
343 int lst=0;
344 for(oiter=_lists.begin(); oiter!=_lists.end(); oiter++)
345 {
346 sos << lst++ << ": ";
347 for(iter=(*oiter)->begin();iter!=(*oiter)->end();iter++) sos << iter->_tempfeature << "," <<iter->_value << " | ";
348 sos << std::endl;
349 }
350 sos << "final list: "<<std::endl;
351 sos << " ";
352 assert(_final.size()>0);
353
354 for(fiter=_final.begin();fiter!=_final.end();fiter++) sos << (*fiter).first << ") " << (*fiter).second->_value << " | ";
355 sos << std::endl;
356 sos << "verified crit value=" << result << std::endl;
357 sos << std::endl << std::flush;
358 syncout::print(os,sos);
359 }
360
361 return true;
362}
363
364
365} // namespace
366#endif // FSTSEARCHSEQSTEPENSEMBLE_H ///:~
Abstract candidate-evaluation strategy: the seam through which one search algorithm body evaluates ca...
Implements sequential in-line evaluation of a criterion on a set of subset candidates.
Implements sequential in-line evaluation of a criterion on a set of subset candidates.
Definition candidate_evaluator_sequential.hpp:62
Abstract candidate-evaluation strategy (sequential-inline vs. thread-pooled).
Definition candidate_evaluator.hpp:86
std::function< void(const RETURNTYPE, const PSubset &, const DIMTYPE)> ResultCallback
Definition candidate_evaluator.hpp:94
Abstract class, defines interface for feature selection criterion classes.
Definition criterion.hpp:84
Nested class to hold feature/subset candidate info in the course of the ensemble voting process.
Definition seq_step_ensemble.hpp:188
const PSubset _sub
owned snapshot of the candidate subset (see the two constructors above)
Definition seq_step_ensemble.hpp:196
SubsetCandidate(const RETURNTYPE value, const PSubset sub, const DIMTYPE tfeature)
Constructs a candidate entry, taking a deep (owned) copy of sub – the caller's subset object is mutat...
Definition seq_step_ensemble.hpp:191
const DIMTYPE _tempfeature
copy of sub->getFirstTemporaryFeature() at the time this candidate was constructed – the feature this...
Definition seq_step_ensemble.hpp:197
RETURNTYPE _value
Dual-purpose: in a member's per-candidate list (_lists) this is the raw value that member criterion r...
Definition seq_step_ensemble.hpp:195
SubsetCandidate(const SubsetCandidate &fc)
Copy constructor – unlike the constructor above this SHARES (does not deep-copy) the source's _sub,...
Definition seq_step_ensemble.hpp:193
Implements voting ensemble selection step in sequential search type of methods to possibly improve ro...
Definition seq_step_ensemble.hpp:140
CANDIDATELISTS _lists
per-member ordered candidate lists, rebuilt by order_candidates() on every evaluate_candidates() call
Definition seq_step_ensemble.hpp:203
Sequential_Step_Ensemble(const PEnsembleCriteria ensemble, PEvaluatorEngine engine=PEvaluatorEngine())
Constructs the ensemble step over the given member criteria.
Definition seq_step_ensemble.hpp:155
virtual std::ostream & print(std::ostream &os) const override
Writes a human-readable identification of the step, incl. the engine's thread count (if threaded) and...
Definition seq_step_ensemble.hpp:162
std::shared_ptr< SubsetCandidate > PSubsetCandidate
shared pointer to a SubsetCandidate
Definition seq_step_ensemble.hpp:199
bool evaluate_candidates(RETURNTYPE &result, const PSubset sub, const PCriterion crit, const DIMTYPE _generalization_level=1, std::ostream &os=std::cout) override
chooses among subsets offered by sub->get*CandidateSubset()
Definition seq_step_ensemble.hpp:270
std::shared_ptr< SUBSET > PSubset
shared pointer to a feature subset
Definition seq_step_ensemble.hpp:147
PEvaluatorEngine _engine
candidate-evaluation engine driving the per-member candidate batches
Definition seq_step_ensemble.hpp:184
std::vector< PAbstractCriterion > PAbstractCriteria
the ordered collection of ensemble member criteria
Definition seq_step_ensemble.hpp:145
std::shared_ptr< Criterion< RETURNTYPE, SUBSET > > PAbstractCriterion
shared pointer to one ensemble member, held via the abstract Criterion base so unrelated (filter/wrap...
Definition seq_step_ensemble.hpp:144
Candidate_Evaluator< RETURNTYPE, DIMTYPE, SUBSET, Criterion< RETURNTYPE, SUBSET > > EVALUATORENGINE
typed on the abstract Criterion (the ensemble members' type)
Definition seq_step_ensemble.hpp:148
std::vector< PCANDIDATELIST > CANDIDATELISTS
one CANDIDATELIST per ensemble member, indexed the same as _ensemble
Definition seq_step_ensemble.hpp:202
Sequential_Step< RETURNTYPE, DIMTYPE, SUBSET, CRITERION > parent
base class alias
Definition seq_step_ensemble.hpp:142
std::shared_ptr< EVALUATORENGINE > PEvaluatorEngine
shared pointer to the candidate-evaluation engine (see candidate_evaluator.hpp)
Definition seq_step_ensemble.hpp:149
PEnsembleCriteria _ensemble
the ensemble member criteria, as supplied to the constructor
Definition seq_step_ensemble.hpp:185
bool track
cached parent::result_tracker_active() for the duration of the current evaluate_candidates() call
Definition seq_step_ensemble.hpp:213
FINALVALUES::iterator fiter
iterates _final, i.e. over candidate features and their tallied votes
Definition seq_step_ensemble.hpp:209
std::shared_ptr< CANDIDATELIST > PCANDIDATELIST
shared pointer to a CANDIDATELIST
Definition seq_step_ensemble.hpp:201
bool order_candidates(const PSubset sub)
Builds, for each ensemble member, the ordered (best-first) list of candidate subsets in _lists,...
Definition seq_step_ensemble.hpp:218
std::shared_ptr< PAbstractCriteria > PEnsembleCriteria
shared pointer to the ensemble member collection, as supplied to the constructor
Definition seq_step_ensemble.hpp:146
std::unique_ptr< SUBSET > tmp_step_sub
holds the winning candidate subset while evaluate_candidates() assembles it, before it is copied into...
Definition seq_step_ensemble.hpp:212
CANDIDATELIST::iterator iter
iterates one member's ordered candidate list (an element of _lists)
Definition seq_step_ensemble.hpp:208
FINALVALUES _final
the per-feature vote tally built by evaluate_candidates() from _lists; the entry with the lowest (bes...
Definition seq_step_ensemble.hpp:205
std::list< SubsetCandidate > CANDIDATELIST
one ensemble member's candidates, kept sorted best (highest _value) first by order_candidates()
Definition seq_step_ensemble.hpp:200
std::shared_ptr< CRITERION > PCriterion
shared pointer to the single criterion passed into evaluate_candidates() and used to (re-)score the w...
Definition seq_step_ensemble.hpp:143
std::map< DIMTYPE, PSubsetCandidate > FINALVALUES
maps each candidate feature to its tallied ensemble vote (see SubsetCandidate::_value); iteration ord...
Definition seq_step_ensemble.hpp:204
CANDIDATELISTS::iterator oiter
iterates _lists, i.e. over ensemble members
Definition seq_step_ensemble.hpp:207
bool output_normal() const
true unless output detail is SILENT
Definition seq_step.hpp:137
PResultTracker _tracker
the assigned result tracker, or null (see enable_result_tracking()/result_tracker_active())
Definition seq_step.hpp:140
bool output_detailed() const
true only at the DETAILED output level
Definition seq_step.hpp:138
bool result_tracker_active() const
true if a result tracker was assigned via enable_result_tracking() and not since disabled
Definition seq_step.hpp:133
FST4 specific error passing class.
Definition error.hpp:61
static void print(std::ostream &os, std::ostringstream &sos)
Writes sos's buffered content to os, serializing concurrent writers under FST_THREADED via a shared m...
Definition global.hpp:86
Defines interface for feature selection criterion classes.
FST4 specific error passing class.
Global definitions.
The Feature Selection Toolbox 4 library: every library component – data access, criteria and classifi...
Definition data_accessor.hpp:80
void notify(const std::string msg)
Prints msg followed by a newline via syncout::print(); a no-op unless the preprocessor macro DEBUG is...
Definition global.hpp:112
Defines interface for implementations of one selection step in sequential search type of methods.
Copyright © 2000–present ÚTIA, Institute of Information Theory and Automation of the Czech Academy of Sciences · Contacts · This site sets no cookies and uses no analytics.