Feature Selection Toolbox FST4
UTIA · Czech Academy of Sciences
Loading...
Searching...
No Matches
search_seq_sfs.hpp
Go to the documentation of this file.
1#ifndef FSTSEARCHSEQSFS_H
2#define FSTSEARCHSEQSFS_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 "error.hpp"
54#include "global.hpp"
55#include "stopwatch.hpp"
56#include "search_seq.hpp"
57
58/*============== Template parameter type naming conventions ==============
59--------- Numeric types: -------------------------------------------------
60DATATYPE - data sample values - usually real numbers (but may be integers
61 in text processing etc.)
62REALTYPE - must be real numbers - for representing intermediate results of
63 calculations like mean, covariance etc.
64IDXTYPE - index values for enumeration of data samples - (nonnegative) integers,
65 extent depends on numbers of samples in data
66DIMTYPE - index values for enumeration of features (dimensions), or classes (not
67 class sizes) - (nonnegative) integers, usually lower extent than IDXTYPE,
68 but be aware of expressions like _classes*_features*_features !
69 in linearized representations of feature matrices for all classes
70BINTYPE - feature selection marker type - represents ca. <10 different feature
71 states (selected, deselected, sel./desel. temporarily 1st nested loop, 2nd...)
72RETURNTYPE - criterion value: real value, but may be extended in future to support
73 multiple values
74--------- Class types: ---------------------------------------------------
75SUBSET - class of class type Subset
76CLASSIFIER - class implementing interface defined in abstract class Classifier
77EVALUATOR - class implementing interface defined in abstract class Sequential_Step
78DISTANCE - class implementing interface defined in abstract class Distance
79DATAACCESSOR - class implementing interface defined in abstract class Data_Accessor
80INTERVALCONTAINER - class of class type Data_Intervaller
81CONTAINER - STL container of class type Data_Interval
82========================================================================== */
83
84namespace FST {
85
91template<class RETURNTYPE, typename DIMTYPE, class SUBSET, class CRITERION, class EVALUATOR>
92class Search_SFS : public Search_Sequential<RETURNTYPE,DIMTYPE,SUBSET,CRITERION,EVALUATOR>{
93public:
95 typedef typename parent::parent grandparent;
96 typedef std::shared_ptr<EVALUATOR> PEvaluator;
97 typedef std::shared_ptr<CRITERION> PCriterion;
98 typedef std::shared_ptr<SUBSET> PSubset;
99 Search_SFS(const PEvaluator evaluator) : Search_Sequential<RETURNTYPE,DIMTYPE,SUBSET,CRITERION,EVALUATOR>(evaluator) {_direction=FORWARD; notify("Search_SFS constructor.");}
100 virtual ~Search_SFS() {notify("Search_SFS destructor.");}
101
102 // NOTE: crit is expected to be already initialize()d before use here
116 virtual bool search(const DIMTYPE target_d, RETURNTYPE &result, const PSubset sub, const PCriterion crit, std::ostream& os=std::cout) override;
117
118 void set_search_direction(const SearchDirection direction) {assert(direction==FORWARD || direction==BACKWARD); _direction=direction;}
120
122 bool get_result(const DIMTYPE d, RETURNTYPE &result, PSubset &sub);
123
124 virtual std::ostream& print(std::ostream& os) const override;
125protected:
128 struct OneSubset {
129 RETURNTYPE critvalue;
130 std::unique_ptr<SUBSET> sub;
131 };
132 std::unique_ptr<OneSubset[]> bsubs;
133 DIMTYPE _n;
134};
135
136template<class RETURNTYPE, typename DIMTYPE, class SUBSET, class CRITERION, class EVALUATOR>
138{
139 if(parent::get_generalization_level()>1) os << "(G)";
140 if(_direction==FORWARD) os << "SFS"; else os << "SBS";
142 os << " [Search_SFS()";
143 if(parent::_evaluator) os << " with " << *parent::_evaluator;
145 os << "]";
146 return os;
147}
148
149template<class RETURNTYPE, typename DIMTYPE, class SUBSET, class CRITERION, class EVALUATOR>
150bool Search_SFS<RETURNTYPE,DIMTYPE,SUBSET,CRITERION,EVALUATOR>::search(const DIMTYPE target_d, RETURNTYPE &result, const PSubset sub, const PCriterion crit, std::ostream& os) // returns found subset + criterion value
151{
152 // NOTE: certain parameter combinations (initial sub->get_d() versus target_d versus parent::_generalization_level)
153 // make it impossible to yield a valid solution. In such case search() just returns false
154 StopWatch swatch;
155 if(parent::_evaluator) parent::_evaluator->set_output_detail(grandparent::get_output_detail()); else throw FST::fst_error("Search_Sequential: Missing evaluator.");
157 assert(sub);
158 assert(crit);
159 assert(sub->get_n()>0);
160 assert(target_d<=sub->get_n());
162
163 const bool _forward=(_direction==FORWARD);
164 sub->set_forward_mode(true); // select_all()/deselect_all() write mode-dependent ids - a Subset left in backward mode by a previous search() would otherwise re-initialize empty
166 if(_forward) sub->deselect_all(); else sub->select_all();
167 }
168 DIMTYPE _d=sub->get_d();
169 _n=sub->get_n();
170 bsubs.reset(new OneSubset[_n]);
171
172 // no solution is reachable under this setting when, with g = generalization level:
173 // forward, but there is no room for another g-tuple (d+g>n),
174 // backward, but removing a g-tuple would not leave a non-empty subset (d<=g),
175 // a target size is requested that the starting subset has already reached or passed
176 // (forward: d>=target_d, backward: d<=target_d),
177 // or the distance between d and target_d is not a whole number of g-sized steps
178 if( (_forward && _d+parent::get_generalization_level()>_n) ||
179 (!_forward && _d<=parent::get_generalization_level()) ||
180 (target_d>0 && _forward && _d>=target_d) ||
181 (target_d>0 && !_forward && _d<=target_d) ||
182 (target_d>0 && ((target_d>_d)?(target_d-_d):(_d-target_d))%parent::get_generalization_level()>0) ) return false; // no solution reachable under this setting
183
185 msgbuf sos;
186 sos << "---------------------------------------" << std::endl;
187 sos << "Starting " << *this << std::endl;
188 sos << "with Criterion: " << *crit << std::endl;
189 sos << "with initial subset: " << *sub << std::endl;
190 if(target_d==0) sos << "Subset size to be optimized." << std::endl; else sos << "Target subset size set to: " << target_d << std::endl;
191 sos << std::endl << std::flush;
192 this->report(os,sos);
193 }
194
195 sub->set_forward_mode(_forward); // FORWARD is the prevailing mode
196
197 if(_d>0) { // evaluate initial subset if any
198 if(!crit->evaluate(result,sub)) return false;
199 if(track) grandparent::_tracker->add(result,sub);
200 bsubs[_d-1].sub.reset(new SUBSET(_n));
201 bsubs[_d-1].sub->stateless_copy(*sub);
202 bsubs[_d-1].critvalue=result;
203 if(grandparent::output_normal()) this->report_solution(os, result, *sub, msgbuf() << "subresult=" << result << " " << *sub << std::endl << std::endl);
204 }
205
206 DIMTYPE steps;
207 if(target_d>0 && target_d<=_n) { // search for subset of size target_d
208 steps=((target_d>_d)?(target_d-_d):(_d-target_d))/parent::get_generalization_level();
209 } else { // find best dimensionality
210 if(_forward) steps=(_n-_d)/parent::get_generalization_level();
211 else steps=(_d-1)/parent::get_generalization_level();
212 }
213
214 // main search loop
215 for(DIMTYPE i=0;i<steps;i++) {
216 if(!parent::Step(_forward, result, sub, crit, os)) return false;
217 if(track) grandparent::_tracker->add(result,sub);
218 if(grandparent::output_normal()) this->report_solution(os, result, *sub, msgbuf() << "subresult=" << result << " " << *sub << std::endl << std::endl << std::flush);
219 _d=sub->get_d();
220 bsubs[_d-1].sub.reset(new SUBSET(_n));
221 bsubs[_d-1].sub->stateless_copy(*sub);
222 bsubs[_d-1].critvalue=result;
223 }
224
225 DIMTYPE finalidx;
226 if(target_d>0 && target_d<=_n) finalidx=target_d-1;
227 else {
228 for(finalidx=0;finalidx<_n && !bsubs[finalidx].sub;finalidx++);
229 for(DIMTYPE i=finalidx+1;i<_n;i++) if(bsubs[i].sub && bsubs[i].critvalue>bsubs[finalidx].critvalue) finalidx=i;
230 }
231
232 if(finalidx>=_n || !bsubs[finalidx].sub) return false;
233
234 result=bsubs[finalidx].critvalue;
235 sub->stateless_copy(*(bsubs[finalidx].sub));
236
238 msgbuf sos;
239 sos << "......................................." << std::endl;
240 sos << "Search_SFS() search finished. " << swatch << std::endl;
241 sos << "Search result: "<< std::endl << *sub << std::endl << "Criterion value: " << result << std::endl << std::endl << std::flush;
242 this->report(os,sos);
243 }
244 return true;
245}
246
247template<class RETURNTYPE, typename DIMTYPE, class SUBSET, class CRITERION, class EVALUATOR>
248bool Search_SFS<RETURNTYPE,DIMTYPE,SUBSET,CRITERION,EVALUATOR>::get_result(const DIMTYPE d, RETURNTYPE &result, PSubset &sub) // retrieves temporary solution of cardinality d that had been updated in the course of the last search
249{
250 assert(sub);
251 assert(d>0 && d<=_n);
252 if(bsubs && d>0 && d<=_n && bsubs[d-1].sub) {
253 result=bsubs[d-1].critvalue;
254 sub->stateless_copy(*(bsubs[d-1].sub));
255 return true;
256 }
257 return false;
258}
259
260
261} // namespace
262#endif // FSTSEARCHSEQSFS_H ///:~
Implements Sequential_Forward_Selection and Sequential_Backward_Selection.
Definition search_seq_sfs.hpp:92
SearchDirection _direction
Definition search_seq_sfs.hpp:126
void set_search_direction(const SearchDirection direction)
FORWARD implies SFS, BACKWARD implies SBS (do not change concurrently to running search()).
Definition search_seq_sfs.hpp:118
Search_SFS(const PEvaluator evaluator)
evaluator must be non-null; direction defaults to FORWARD (SFS); call set_search_direction(BACKWARD) ...
Definition search_seq_sfs.hpp:99
SearchDirection get_search_direction() const
the currently configured direction (see set_search_direction())
Definition search_seq_sfs.hpp:119
std::shared_ptr< SUBSET > PSubset
shared pointer to a feature subset
Definition search_seq_sfs.hpp:98
std::shared_ptr< CRITERION > PCriterion
shared pointer to the criterion the search optimizes
Definition search_seq_sfs.hpp:97
virtual bool search(const DIMTYPE target_d, RETURNTYPE &result, const PSubset sub, const PCriterion crit, std::ostream &os=std::cout) override
Runs SFS (or SBS) and returns the resulting subset + its criterion value.
Definition search_seq_sfs.hpp:150
bool get_result(const DIMTYPE d, RETURNTYPE &result, PSubset &sub)
retrieves the subset of cardinality d (1-based: d ranges over 1..n) recorded during the last search()...
Definition search_seq_sfs.hpp:248
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_seq_sfs.hpp:137
Search_Sequential< RETURNTYPE, DIMTYPE, SUBSET, CRITERION, EVALUATOR > parent
base class alias
Definition search_seq_sfs.hpp:94
parent::parent grandparent
the shared Search base (output detail, result tracker)
Definition search_seq_sfs.hpp:95
DIMTYPE _n
bsubs array size
Definition search_seq_sfs.hpp:133
std::unique_ptr< OneSubset[]> bsubs
per-cardinality result found in the course of the last search() (index d-1); read by get_result()
Definition search_seq_sfs.hpp:132
std::shared_ptr< EVALUATOR > PEvaluator
shared pointer to the sequential-step evaluator
Definition search_seq_sfs.hpp:96
Search< RETURNTYPE, DIMTYPE, SUBSET, CRITERION > parent
base class alias
Definition search_seq.hpp:107
Search_Sequential(const PEvaluator evaluator)
evaluator must be non-null
Definition search_seq.hpp:111
bool Step(const bool forward, RETURNTYPE &result, const PSubset sub, const PCriterion crit, std::ostream &os=std::cout)
Performs one sequential step: adds (forward) or removes (!forward) the best g-tuple of features,...
Definition search_seq.hpp:146
PEvaluator _evaluator
the sequential-step evaluator injected at construction; drives Step()'s candidate generation and best...
Definition search_seq.hpp:139
bool initial_subset_enabled() const
true if enable_initial_subset() was called (and not since disabled by disable_initial_subset())
Definition search_seq.hpp:136
DIMTYPE get_generalization_level() const
the currently configured generalization level (see set_generalization_level())
Definition search_seq.hpp:131
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
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
SearchDirection
Direction a sequential search proceeds in.
Definition search_seq.hpp:91
Defines interface for sequential search method implementations.
Simple tool to measure run time.
Structure to hold [subset,criterion value] temporary solutions in the course of search.
Definition search_seq_sfs.hpp:128
std::unique_ptr< SUBSET > sub
the subset itself, or null if no result was recorded at this cardinality
Definition search_seq_sfs.hpp:130
RETURNTYPE critvalue
the subset's criterion value
Definition search_seq_sfs.hpp:129
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.