Feature Selection Toolbox FST4
UTIA · Czech Academy of Sciences
Loading...
Searching...
No Matches
search_branch_and_bound.hpp
Go to the documentation of this file.
1#ifndef FSTSEARCHBRANCHANDBOUND_H
2#define FSTSEARCHBRANCHANDBOUND_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 <vector>
54#include <list>
55#include "error.hpp"
56#include "global.hpp"
57#include "stopwatch.hpp"
58#include "search.hpp"
59#include "result_tracker.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
107
108template<class RETURNTYPE, typename DIMTYPE, class SUBSET, class CRITERION>
109class Search_Branch_And_Bound : public Search<RETURNTYPE,DIMTYPE,SUBSET,CRITERION>{
110public:
111 typedef Search<RETURNTYPE,DIMTYPE,SUBSET,CRITERION> parent;
112 typedef std::shared_ptr<CRITERION> PCriterion;
113 typedef std::shared_ptr<SUBSET> PSubset;
115 typedef std::shared_ptr<EVALUATORENGINE> PEvaluatorEngine;
121 explicit Search_Branch_And_Bound(PEvaluatorEngine engine=PEvaluatorEngine()):Search<RETURNTYPE,DIMTYPE,SUBSET,CRITERION>(),_engine(engine) {
123 notify("Search_Branch_And_Bound constructor.");
124 }
125 virtual ~Search_Branch_And_Bound() {notify("Search_Branch_And_Bound destructor.");}
126
127 // NOTE: crit is expected to be already initialize()d before use here
128 virtual bool search(const DIMTYPE target_d, RETURNTYPE &result, const PSubset sub, const PCriterion crit, std::ostream& os=std::cout) override;
129
130 virtual std::ostream& print(std::ostream& os) const override {os << "Search_Branch_And_Bound() abstract class"; return os;};
131
132protected:
134 typedef enum {UNKNOWN, RANDOM, PREDICTED, COMPUTED} NodeType;
136 typedef struct {
137 DIMTYPE feature;
138 RETURNTYPE value;
140 bool valid;
141 } Node;
142 typedef Node* PNode;
143 typedef std::list<Node> ListNode;
144 typedef std::vector<ListNode> VectorListNode;
145 typedef typename ListNode::iterator ListNodeIter;
146 typedef typename std::vector<ListNode>::iterator TreeLevelIter;
147 typedef std::vector<Node> VectorNode;
148
149private:
150 // the following structures need to be valid throughout the course of one search
152
154
156
158 DIMTYPE _availiter;
159
161 DIMTYPE get_available_size() {DIMTYPE c=0; for(DIMTYPE i=0;i<_available.size();i++) if(_available[i].valid) c++; return c;}
162 void available_add(const DIMTYPE feature) {assert(_available.size()>feature && !_available[feature].valid); _available[feature].valid=true; _available[feature].type=UNKNOWN;}
163 void available_remove(const DIMTYPE feature) {assert(_available.size()>feature && _available[feature].valid); _available[feature].valid=false;}
164
166 void currentset_add(const DIMTYPE feature) {assert(!_currentset->selected_raw(feature)); _currentset->select_raw(feature);}
167 void currentset_remove(const DIMTYPE feature) {assert(_currentset->selected_raw(feature)); _currentset->deselect_raw(feature);}
168
170
172 RETURNTYPE _boundvalue;
174
175 DIMTYPE k;
176 DIMTYPE n;
177 DIMTYPE d;
178
179protected:
180 PCriterion const &get_criterion() const {assert(_criterion); return _criterion;}
181 PEvaluatorEngine const &get_engine() const {assert(_engine); return _engine;}
182
183 RETURNTYPE get_bound_value() const {return _boundvalue;}
184 bool is_bound_valid() const {return _boundvalid;}
185
186 int get_k() const {return k;}
187 DIMTYPE get_n() const {return n;}
188 DIMTYPE get_d() const {return d;}
189
190 bool getFirstNode(PNode &nod) {assert(k<n-d+1 && _tree.size()==n-d); if(_tree[k].empty()) return false; else {_nodeiter=_tree[k].begin(); nod=&(*_nodeiter); return true;}}
191 bool getNextNode(PNode &nod) {assert(k<n-d+1 && _tree.size()==n-d); if(++_nodeiter==_tree[k].end()) return false; else {nod=&(*_nodeiter); return true;}}
192
193 bool getFirstAvailable(PNode &avail) {assert(_available.size()>0); for(_availiter=0; _availiter<_available.size() && !_available[_availiter].valid; _availiter++) {} if(_availiter<_available.size()) {avail=&(_available[_availiter]); return true;} else return false;}
194 bool getNextAvailable(PNode &avail) {assert(_available.size()>0 && _availiter<_available.size()); _availiter++; while(_availiter<_available.size() && !_available[_availiter].valid) {_availiter++;} if(_availiter<_available.size()) {avail=&(_available[_availiter]); return true;} else return false;}
195 bool getAvailable(DIMTYPE idx, PNode &avail) {assert(idx<_available.size()); if(idx<_available.size()) {avail=&(_available[idx]); return true;} else return false;}
196
197protected:
199 Node& get_parent_node(){assert(k>0 && _tree.size()>=k && !_tree[k-1].empty()); return _tree[k-1].back();}
200 Node& get_current_node(){assert(_tree.size()>k && !_tree[k].empty()); return _tree[k].back();}
201
202 std::ostream* shared_os;
203
209 void setup_default_structures(const DIMTYPE d, const DIMTYPE n);
215 void update_bound(const RETURNTYPE val, const PSubset &sub);
222 void make_tree_level();
228
229 std::shared_ptr<StopWatch> swatch;
230protected:
231 // the following may/must be overriden in descendant Branch and Bound specialization classes (to implement specific functionality or threading)
232 virtual void process_leafs();
233 virtual void leaf_result(const DIMTYPE feature, const RETURNTYPE value) {}
238 virtual void initialize(const DIMTYPE d, const DIMTYPE n, const PCriterion crit)=0;
243 virtual void pre_evaluate_availables()=0;
247 virtual void post_process_tree_level()=0;
253 virtual bool cut_possible()=0;
254};
255
256template<class RETURNTYPE, typename DIMTYPE, class SUBSET, class CRITERION>
258{
259 assert(d>0);
260 assert(d<n);
261 _tree.resize(n-d); // logically n-d+1 levels, but the last (leaf) level is not stored - its nodes are evaluated directly by process_leafs()
262 for(TreeLevelIter i=_tree.begin();i!=_tree.end();i++) i->clear();
263 _available.resize(n); for(DIMTYPE f=0;f<n;f++) {_available[f].feature=f; _available[f].valid=true;}
264 _currentset.reset(new SUBSET(n)); _currentset->select_all_raw();
265 _tempset.reset(new SUBSET(n));
266 _boundset.reset(new SUBSET(n)); _boundvalid=false;
267}
268
269template<class RETURNTYPE, typename DIMTYPE, class SUBSET, class CRITERION>
271{
272 assert(sub);
273 assert(_boundset);
274 assert(sub->get_n()==_boundset->get_n());
275 assert(swatch);
276 if(!_boundvalid || val>_boundvalue) {
277 _boundvalue=val;
278 _boundset->stateless_copy(*sub);
279 _boundvalid=true;
280 if(parent::output_normal()) this->report_solution(*shared_os, val, *sub, msgbuf() << "NEW BOUND (val="<<val<<"): " << *sub << std::endl << *swatch << std::endl << std::endl << std::flush);
281 }
283}
284
285template<class RETURNTYPE, typename DIMTYPE, class SUBSET, class CRITERION>
287{
288 // based on k and no. of _available features
289 assert(k>0);
290 assert(k<n-d+1);
291 assert(_tree.size()==n-d);
292 assert(_tree[k].empty());
293 assert(_available.size()==n);
294
295 pre_evaluate_availables(); // assign values to candidates to enable sorting into the tree level to be constructed here
296
297 const DIMTYPE levelsize=get_available_size()-(n-d-k+1);
298 assert(levelsize>0);
299 assert(levelsize<=get_available_size());
300
301 // sort-in levelsize features according to value (in case of type UNKNOWN feature put at the end of list)
302 PNode avail;
303 for(bool got=getFirstAvailable(avail);got;got=getNextAvailable(avail))
304 {
305 DIMTYPE pos=0;
306 ListNodeIter it=_tree[k].begin();
307 while(it!=_tree[k].end() && it->value<avail->value) {++it; ++pos;}
308 if(pos<levelsize) {
309 _tree[k].insert(it,*avail);
310 if(_tree[k].size()>levelsize) _tree[k].pop_back();
311 }
312 }
313 assert(_tree[k].size()==levelsize);
314 for(ListNodeIter it=_tree[k].begin();it!=_tree[k].end();it++) {
315 available_remove(it->feature);
316 }
317
318 post_process_tree_level(); // enable to re-evaluate chosen candidate values (e.g., supply missing true _criterion values, etc.)
319}
320
321template<class RETURNTYPE, typename DIMTYPE, class SUBSET, class CRITERION>
323{
324 assert(_tempset);
325 assert(_currentset);
326 assert(_available.size()==n);
327 assert(get_available_size()>0);
328 assert(_criterion);
329 _tempset->stateless_copy(*_currentset);
330
331 RETURNTYPE val;
332 PNode avail;
333
334 for(bool got=getFirstAvailable(avail);got;got=getNextAvailable(avail)) _tempset->deselect_raw(avail->feature);
335 if(!_criterion->evaluate(val,_tempset)) throw FST::fst_error("Criterion evaluation failure.");
336 update_bound(val,_tempset); //adds to tracker
337 if(parent::output_detailed()) this->report(*shared_os, msgbuf() << "rightmost leaf (val="<<val<<"): " << *_tempset << std::endl << std::endl << std::flush);
338}
339
340template<class RETURNTYPE, typename DIMTYPE, class SUBSET, class CRITERION>
342{
343 assert(_currentset);
344 assert(get_criterion());
345 assert(_engine);
346 PNode avail;
347 // bound updates and progress output fire once per leaf in enumeration order: the
348 // sequential engine fires them interleaved with the evaluations, the threaded engine
349 // once the batch has completed - either way the order, and hence the result, is the same
350 typename EVALUATORENGINE::ResultCallback on_result=[this](const RETURNTYPE value, const PSubset &csub, const DIMTYPE feat) {
351 update_bound(value,csub); //adds to tracker
352 if(parent::output_detailed()) this->report(*shared_os, msgbuf() << "leaf (val="<<value<<"): " << *csub << std::endl << std::endl << std::flush);
353 leaf_result(feat,value); // descendant hook (FBB/BBPP prediction learning) - fires in candidate order under both engine implementations
354 };
355 _engine->initialize(get_criterion(), get_n(), on_result);
356 for(bool got=getFirstAvailable(avail);got;got=getNextAvailable(avail))
357 {
359 if(!_engine->add_candidate(_currentset,avail->feature)) throw FST::fst_error("Criterion evaluation failure.");
360 currentset_add(avail->feature);
361 }
362 _engine->collect(); // (return value carries no error here: sequential evaluation failures throw at add_candidate above, threaded ones throw in the worker)
363}
364
365template<class RETURNTYPE, typename DIMTYPE, class SUBSET, class CRITERION>
366bool Search_Branch_And_Bound<RETURNTYPE,DIMTYPE,SUBSET,CRITERION>::search(const DIMTYPE target_d, RETURNTYPE &result, const PSubset sub, const PCriterion crit, std::ostream& os) // returns found subset + _criterion value
367{
368 swatch.reset(new StopWatch);
369 notify("Search_Branch_And_Bound::search().");
370 assert(sub);
371 assert(crit);
372 n=sub->get_n();
373 assert(target_d>0 && target_d<n);
374 d=target_d;
375 assert(d>0 && d<=n);
376 shared_os=&os;
377
379
381 msgbuf sos;
382 sos << "---------------------------------------" << std::endl;
383 sos << "Starting " << *this << std::endl;
384 sos << "with Criterion: " << *crit << std::endl;
385 sos << "Target subset size set to: " << target_d << std::endl;
386 sos << std::endl << std::flush;
387 this->report(os,sos);
388 }
389 // user-supplied criteria default to is_monotonic()==false and get this warning
390 // automatically; the criteria shipped with FST4 that are monotonic declare the
391 // property, so they stay silent
392 if(parent::output_normal() && !crit->is_monotonic()) {
393 this->report(os, msgbuf() << "WARNING: the supplied criterion does not declare monotonicity w.r.t. subset cardinality" << std::endl
394 << "(Criterion::is_monotonic()==false). Branch & Bound optimality guarantees do NOT apply -" << std::endl
395 << "the result may be suboptimal. Override is_monotonic() to true only if removing a feature" << std::endl
396 << "provably never increases the criterion value; otherwise prefer a non-optimal search." << std::endl << std::endl << std::flush);
397 }
398
399 if(n==d) {
400 sub->select_all_raw();
401 if(!crit->evaluate(result,sub)) throw FST::fst_error("Criterion evaluation failure.");
402 return true;
403 }
404
406
407 // initialize root
408 Node root; // Node::feature and Node::valid are not used in root
409 _tempset->select_all_raw();
410 if(!crit->evaluate(root.value,_tempset)) throw FST::fst_error("Criterion evaluation failure.");
411 root.type=COMPUTED;
412 _tree[0].push_back(root);
413
414 initialize(d,n,crit); // to enable overloaded functionality
415 _criterion=crit;
416
417 // Deepest level at which a CUT message was last printed. Cuts near the leaves are both
418 // frequent and uninteresting, so a CUT is reported only when it happens at that level or
419 // higher up the tree; this throttles the message stream without affecting the search.
420 DIMTYPE lastcut_k=n-d;
421
422 DIMTYPE feature;
423 // TRAVERSAL INVARIANT, maintained by every block below. At any point between iterations:
424 // - the features removed on the path from the root to level k are exactly the features
425 // deselected in _currentset, one per level 1..k-1, namely _tree[j].back().feature;
426 // - a feature is in exactly one of three places: selected in _currentset, sorted into some
427 // level of _tree, or valid in _available. Descending one level moves _tree[k].back().feature
428 // out of _currentset; backtracking one level moves it back into _currentset AND back into
429 // _available, and pops it off the level, so the level's next node becomes the current one.
430 // - a level that becomes empty means its subtree is fully explored, hence the "pop and go up"
431 // loops keep climbing while _tree[k] is empty. Reaching k==0 ends the search.
432 k=1; // start with the first level below root
433 do{
434 // traverse tree branch down
435 while(k>0 && k<n-d) {
436
437 make_tree_level(); // make k-th level, choose |_available|-(n-d-k+1) nodes from _available and use them to make next level
439
440 // recursively cut all sub-branches that can be cut
441 while(k>0 && cut_possible())
442 {
443 assert(!_tree[k].empty());
444 if(k<=lastcut_k) { // report only cuts at or above the last reported level (see lastcut_k)
445 if(parent::output_normal()) this->report(os, msgbuf() << "CUT (k="<<k<<", val="<<_tree[k].back().value<<", bound="<<get_bound_value()<<", feature=" << _tree[k].back().feature<<") " << std::endl << std::endl);
446 lastcut_k=k;
447 }
448 feature=_tree[k].back().feature; assert(feature<n);
449 available_add(feature);
450 _tree[k].pop_back();
451 // the cut emptied this level: climb until a level with an untried node is found,
452 // restoring each passed level's feature into _currentset and _available on the way
453 while(k>0 && _tree[k].empty()) {
454 --k;
455 if(k>0) {
456 assert(!_tree[k].empty());
457 feature=_tree[k].back().feature; assert(feature<n);
458 currentset_add(feature);
459 available_add(feature);
460 _tree[k].pop_back();
461 }
462 }
463 }
464 // no more cutting possible, proceed down to next level (or finish if k==0)
465 if(k>0) {
466 feature=_tree[k].back().feature; assert(feature<n);
467 currentset_remove(feature);
468 ++k;
469 }
470 }
471 // evaluate all leafs that are descendants of the just visited node
472 if(k==n-d) {
473 process_leafs(); //depends on _currentset, _available, not on k
474 // the leaf level has no stored nodes, so there is nothing left to try here:
475 // backtrack up to the closest ancestor that still has an untried node, undoing
476 // each level's feature removal as we climb
477 do {
478 --k;
479 if(k>0) {
480 assert(!_tree[k].empty());
481 feature=_tree[k].back().feature; assert(feature<n);
482 currentset_add(feature);
483 available_add(feature);
484 _tree[k].pop_back();
485 }
486 } while(k>0 && _tree[k].empty());
487 }
488 // proceed down through the next rightmost subbranch to the left from the last one
489 if(k>0) {
490 assert(!_tree[k].empty());
491 feature=_tree[k].back().feature; assert(feature<n);
492 currentset_remove(feature);
493 ++k;
494 }
495
496 } while(k>0);
497
498 assert(_boundset);
499 assert(sub->get_n()==_boundset->get_n());
500 sub->stateless_copy(*_boundset);
501 result=_boundvalue;
503 msgbuf sos;
504 sos << "......................................." << std::endl;
505 sos << "Branch and Bound search finished. " << *swatch << std::endl;
506 sos << "Search result: "<< std::endl << *sub << std::endl << "Criterion value: " << result << std::endl << std::endl << std::flush;
507 this->report(os,sos);
508 }
509 swatch.reset();
510 return true;
511}
512
513} // namespace
514#endif // FSTSEARCHBRANCHANDBOUND_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
fired once per evaluated batch candidate: (criterion value, candidate, feature tag as passed to add_c...
Definition candidate_evaluator.hpp:94
Implements Branch and Bound template method as basis for more advanced B&B implementations.
Definition search_branch_and_bound.hpp:109
PSubset & get_currentset()
mutable accessor for _currentset, for use by descendant B&B variants' hooks
Definition search_branch_and_bound.hpp:198
PSubset _currentset
the subset defined by the branch currently being followed: all n features minus the ones removed on t...
Definition search_branch_and_bound.hpp:165
Node & get_parent_node()
the node one level up (_tree[k-1].back()) whose feature removal defines the branch currently being fo...
Definition search_branch_and_bound.hpp:199
virtual void pre_evaluate_availables()=0
Called by make_tree_level() before the k-th level is built. It must assign Node::value (and Node::typ...
virtual std::ostream & print(std::ostream &os) const override
writes a human-readable identification of the search and its configuration; base default writes nothi...
Definition search_branch_and_bound.hpp:130
virtual void process_leafs()
engine-routed leaf evaluation; descendants hook per-leaf work via leaf_result() instead of overriding...
Definition search_branch_and_bound.hpp:341
virtual void initialize(const DIMTYPE d, const DIMTYPE n, const PCriterion crit)=0
Called once per search() run, after setup_default_structures() and the root evaluation but before the...
DIMTYPE get_d() const
target subset cardinality, see d
Definition search_branch_and_bound.hpp:188
Node * PNode
pointer to a Node, as used by the getFirst.../getNext... accessors below
Definition search_branch_and_bound.hpp:142
virtual bool cut_possible()=0
Tests the current node (get_current_node(), i.e. _tree[k].back()) for the possibility to cut the whol...
bool getFirstNode(PNode &nod)
begins forward iteration (ascending by value, from _tree[k].begin()) over the current level's not-yet...
Definition search_branch_and_bound.hpp:190
PCriterion const & get_criterion() const
accessor for _criterion, for use by descendant B&B variants' hooks
Definition search_branch_and_bound.hpp:180
Search_Branch_And_Bound(PEvaluatorEngine engine=PEvaluatorEngine())
Constructs the search, optionally injecting a candidate-evaluation engine.
Definition search_branch_and_bound.hpp:121
DIMTYPE n
no. of all features
Definition search_branch_and_bound.hpp:176
VectorNode _available
the pool of still-undecided features, one entry per original feature and indexed by feature id: Node:...
Definition search_branch_and_bound.hpp:160
virtual void leaf_result(const DIMTYPE feature, const RETURNTYPE value)
Definition search_branch_and_bound.hpp:233
void available_add(const DIMTYPE feature)
re-admits feature to the undecided candidate pool (valid=true, type reset to UNKNOWN); used on backtr...
Definition search_branch_and_bound.hpp:162
DIMTYPE k
current tree level
Definition search_branch_and_bound.hpp:175
Node & get_current_node()
the node at the current level k presently being visited (_tree[k].back()), i.e. about to be tested fo...
Definition search_branch_and_bound.hpp:200
Search< RETURNTYPE, DIMTYPE, SUBSET, CRITERION > parent
base class: the abstract Search interface (search(), progress reporting, result tracker)
Definition search_branch_and_bound.hpp:111
PEvaluatorEngine const & get_engine() const
accessor for the injected evaluation strategy (sequential-inline or thread-pooled),...
Definition search_branch_and_bound.hpp:181
Candidate_Evaluator< RETURNTYPE, DIMTYPE, SUBSET, CRITERION > EVALUATORENGINE
the injected candidate-evaluation strategy type (sequential-inline or thread-pooled); process_leafs()...
Definition search_branch_and_bound.hpp:114
int get_k() const
the tree depth/level currently being processed (root is 0; the deepest stored level is n-d-1,...
Definition search_branch_and_bound.hpp:186
bool getAvailable(DIMTYPE idx, PNode &avail)
direct lookup of _available[idx] by feature index, regardless of its valid flag; returns false if idx...
Definition search_branch_and_bound.hpp:195
ListNode::iterator ListNodeIter
iterator into a single tree level's ListNode, as used by _nodeiter/getFirstNode()/getNextNode()
Definition search_branch_and_bound.hpp:145
PSubset _boundset
the best subset of target cardinality d found so far; meaningful only once _boundvalid is true
Definition search_branch_and_bound.hpp:171
bool getFirstAvailable(PNode &avail)
begins iteration over _available in feature-index order, skipping withdrawn (invalid) entries,...
Definition search_branch_and_bound.hpp:193
std::list< Node > ListNode
one tree level's not-yet-decided candidate nodes, kept sorted ascending by value; the main search loo...
Definition search_branch_and_bound.hpp:143
void currentset_remove(const DIMTYPE feature)
deselects feature from _currentset, committing its removal as the branch descends past it
Definition search_branch_and_bound.hpp:167
virtual void post_process_tree_level()=0
Called by make_tree_level() once the k-th level has been filled and its features withdrawn from _avai...
ListNodeIter _nodeiter
used in get*Node()
Definition search_branch_and_bound.hpp:157
bool getNextNode(PNode &nod)
advances the getFirstNode() iteration; returns false once the level's end is reached
Definition search_branch_and_bound.hpp:191
DIMTYPE d
no. of features to be selected
Definition search_branch_and_bound.hpp:177
PEvaluatorEngine _engine
injected evaluation strategy (sequential-inline or thread-pooled)
Definition search_branch_and_bound.hpp:153
std::shared_ptr< EVALUATORENGINE > PEvaluatorEngine
shared pointer to an EVALUATORENGINE, as accepted by the constructor and returned by get_engine()
Definition search_branch_and_bound.hpp:115
DIMTYPE get_available_size()
number of features still undecided (valid==true) in _available
Definition search_branch_and_bound.hpp:161
void currentset_add(const DIMTYPE feature)
re-selects feature in _currentset, undoing a prior currentset_remove() (used when backtracking up the...
Definition search_branch_and_bound.hpp:166
PCriterion _criterion
the criterion supplied to search(), assigned once initialize() has run (see search())
Definition search_branch_and_bound.hpp:151
void available_remove(const DIMTYPE feature)
withdraws feature from the undecided candidate pool (valid=false), e.g. once it has been sorted into ...
Definition search_branch_and_bound.hpp:163
bool is_bound_valid() const
true once a valid bound has been established, see _boundvalid
Definition search_branch_and_bound.hpp:184
virtual bool search(const DIMTYPE target_d, RETURNTYPE &result, const PSubset sub, const PCriterion crit, std::ostream &os=std::cout) override
returns the found subset of exactly target_d features + its criterion value; target_d must be nonzero...
Definition search_branch_and_bound.hpp:366
std::shared_ptr< SUBSET > PSubset
shared pointer to a feature subset
Definition search_branch_and_bound.hpp:113
void make_tree_level()
Builds the k-th tree level (_tree[k]), keeping exactly n-d-k+1 candidates in reserve for the levels s...
Definition search_branch_and_bound.hpp:286
bool getNextAvailable(PNode &avail)
advances the getFirstAvailable() iteration, again skipping invalid entries; returns false once exhaus...
Definition search_branch_and_bound.hpp:194
std::shared_ptr< CRITERION > PCriterion
shared pointer to the criterion under optimization
Definition search_branch_and_bound.hpp:112
NodeType
Marks how a Node's value was obtained: UNKNOWN = not yet assigned; RANDOM = reserved but currently un...
Definition search_branch_and_bound.hpp:134
VectorListNode _tree
the search tree; _tree[k] holds the not-yet-decided candidate nodes at depth k (see make_tree_level()...
Definition search_branch_and_bound.hpp:155
void setup_default_structures(const DIMTYPE d, const DIMTYPE n)
Allocates and resets everything one search() run needs: the n-d stored tree levels (all emptied),...
Definition search_branch_and_bound.hpp:257
void process_rightmost_path()
Evaluates and registers the "rightmost" leaf reachable from the current branch by removing every feat...
Definition search_branch_and_bound.hpp:322
std::shared_ptr< StopWatch > swatch
stopwatch for the running search, (re)created at the start of search() and reported alongside progres...
Definition search_branch_and_bound.hpp:229
std::vector< ListNode >::iterator TreeLevelIter
iterator over tree levels (used only to clear _tree in setup_default_structures())
Definition search_branch_and_bound.hpp:146
std::ostream * shared_os
to enable sharing the same stream across the methods below
Definition search_branch_and_bound.hpp:202
DIMTYPE get_n() const
total number of features, see n
Definition search_branch_and_bound.hpp:187
RETURNTYPE get_bound_value() const
the current best (bound) criterion value; meaningful only once is_bound_valid()
Definition search_branch_and_bound.hpp:183
RETURNTYPE _boundvalue
the criterion value of _boundset; meaningful only once _boundvalid is true
Definition search_branch_and_bound.hpp:172
void update_bound(const RETURNTYPE val, const PSubset &sub)
Registers one fully-evaluated candidate subset of target cardinality d against the running bound....
Definition search_branch_and_bound.hpp:270
PSubset _tempset
temporary copy of _currentset subset to be modified and evaluated
Definition search_branch_and_bound.hpp:169
DIMTYPE _availiter
iteration cursor used by getFirstAvailable()/getNextAvailable() over _available
Definition search_branch_and_bound.hpp:158
std::vector< Node > VectorNode
type of _available: one Node per original feature, indexed by feature id
Definition search_branch_and_bound.hpp:147
std::vector< ListNode > VectorListNode
the search tree: one ListNode per level, indexed by tree depth k (see _tree)
Definition search_branch_and_bound.hpp:144
bool _boundvalid
true once at least one candidate of target cardinality d has been evaluated, so _boundset/_boundvalue...
Definition search_branch_and_bound.hpp:173
bool output_normal() const
true unless output detail is SILENT
Definition search.hpp:159
void report(std::ostream &os, const msgbuf &m) const
delivers one pre-formatted progress message: to the observer if attached, otherwise as syncout text t...
Definition search.hpp:170
bool result_tracker_active() const
true if a result tracker was assigned via enable_result_tracking() and not since disabled
Definition search.hpp:155
OutputDetail get_output_detail() const
the currently configured output detail level
Definition search.hpp:158
PResultTracker _tracker
the assigned result tracker, or null (see enable_result_tracking()/result_tracker_active())
Definition search.hpp:179
void report_solution(std::ostream &os, const RETURNTYPE value, const SUBSET &sub, const msgbuf &m) const
like report(), for sites announcing a new (sub-)solution; fires on_solution instead
Definition search.hpp:175
bool output_detailed() const
true only at the DETAILED output level
Definition search.hpp:160
Simple stopwatch to measure run time of search algorithms.
Definition stopwatch.hpp:92
FST4 specific error passing class.
Definition error.hpp:61
Message accumulator for Search::report() - collects one progress message exactly as an std::ostringst...
Definition search.hpp:87
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 classes that enable collecting multiple results.
Defines interface for search method implementations.
Simple tool to measure run time.
Structure representing search tree node.
Definition search_branch_and_bound.hpp:136
RETURNTYPE value
the node's criterion value: exact once type==COMPUTED, an ordering estimate while type==PREDICTED,...
Definition search_branch_and_bound.hpp:138
DIMTYPE feature
the feature index this node represents removing from its ancestor set (meaningless in the single root...
Definition search_branch_and_bound.hpp:137
NodeType type
how value was obtained, see NodeType
Definition search_branch_and_bound.hpp:139
bool valid
for use in _available only: true while the feature is still an undecided candidate (see available_add...
Definition search_branch_and_bound.hpp:140
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.