Feature Selection Toolbox FST4
UTIA · Czech Academy of Sciences
Loading...
Searching...
No Matches
criterion_extern_value.hpp
Go to the documentation of this file.
1#ifndef FSTCRITERIONEXTERNVALUE_H
2#define FSTCRITERIONEXTERNVALUE_H
3 /*
25=========================================================================
26Copyright and license:
27 * FST4 software (with the exception of any bundled or externally linked
28 third-party components) is Copyright (C) 2000-present Institute of
29 Information Theory and Automation of the Czech Academy of Sciences (UTIA).
30 * FST4 is free software: you can redistribute it and/or modify it under
31 the terms of the GNU Affero General Public License as published by the
32 Free Software Foundation, version 3. The full text of the license is in
33 the file LICENSE in the distribution root and at
34 https://www.gnu.org/licenses/agpl-3.0.html.
35 * FST4 is distributed in the hope that it will be useful, but WITHOUT ANY
36 WARRANTY; without even the implied warranty of MERCHANTABILITY or
37 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
38 License for more details.
39 * Closed-source use without the AGPL's copyleft obligations requires a
40 commercial license from UTIA; in case of interest write to
41 utia@utia.cas.cz. LICENSING.md in the distribution root explains both
42 options, the contributor license agreement that every contribution
43 requires, and the contacts (technical questions and pull requests:
44 somol@utia.cas.cz, with "FST" in the subject line).
45========================================================================== */
46
47#include <memory>
48#include <vector>
49#include <string>
50#include <cstdio>
51#include <cstdlib>
52#include <cassert>
53#include <cmath>
54#include <iostream>
55#include "error.hpp"
56#include "global.hpp"
57#include "clonable.hpp"
58#include "criterion.hpp"
59#include "extern_bridge.hpp"
60
61/*============== Template parameter type naming conventions ==============
62--------- Numeric types: -------------------------------------------------
63DATATYPE - data sample values - usually real numbers (but may be integers
64 in text processing etc.)
65REALTYPE - must be real numbers - for representing intermediate results of
66 calculations like mean, covariance etc.
67IDXTYPE - index values for enumeration of data samples - (nonnegative) integers,
68 extent depends on numbers of samples in data
69DIMTYPE - index values for enumeration of features (dimensions), or classes (not
70 class sizes) - (nonnegative) integers, usually lower extent than IDXTYPE,
71 but be aware of expressions like _classes*_features*_features !
72 in linearized representations of feature matrices for all classes
73BINTYPE - feature selection marker type - represents ca. <10 different feature
74 states (selected, deselected, sel./desel. temporarily 1st nested loop, 2nd...)
75RETURNTYPE - criterion value: real value, but may be extended in future to support
76 multiple values
77--------- Class types: ---------------------------------------------------
78SUBSET - class of class type Subset
79CLASSIFIER - class implementing interface defined in abstract class Classifier
80EVALUATOR - class implementing interface defined in abstract class Sequential_Step
81DISTANCE - class implementing interface defined in abstract class Distance
82DATAACCESSOR - class implementing interface defined in abstract class Data_Accessor
83INTERVALCONTAINER - class of class type Data_Intervaller
84CONTAINER - STL container of class type Data_Interval
85========================================================================== */
86
87namespace FST {
88
162template<class RETURNTYPE, typename DATATYPE, typename REALTYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET, class DATAACCESSOR>
163class Criterion_Extern_Value : public Clonable_Impl<Criterion_Extern_Value<RETURNTYPE,DATATYPE,REALTYPE,IDXTYPE,DIMTYPE,SUBSET,DATAACCESSOR>,Criterion<RETURNTYPE,SUBSET> > {
164public:
167 typedef std::shared_ptr<DATAACCESSOR> PDataAccessor;
168 typedef std::shared_ptr<SUBSET> PSubset;
169 typedef typename DATAACCESSOR::PPattern PPattern;
170 Criterion_Extern_Value() : _bridge("Criterion_Extern_Value"), _monotonic(false), _no_data(false), _data_stale(true), _classes(0), _features(0), _subfeatures(0) {notify("Criterion_Extern_Value constructor.");}
171 virtual ~Criterion_Extern_Value() {notify("Criterion_Extern_Value destructor.");} // the bridge destructor shuts the child down
172
173 void set_command(const std::string &cmd) {_bridge.set_command(cmd);}
174 const std::string& get_command() const {return _bridge.get_command();}
175 void set_monotonic(const bool m) {_monotonic=m;}
176 virtual bool is_monotonic() const override {return _monotonic;}
177 void set_no_data(const bool nd) {_no_data=nd;}
178
188 void initialize(const PDataAccessor da, const PDataAccessor da_for_evaluate=PDataAccessor());
200 virtual bool evaluate(RETURNTYPE &result, const PSubset sub) override;
201
202 virtual std::ostream& print(std::ostream& os) const override {os << "Criterion_Extern_Value(cmd=\"" << _bridge.get_command() << "\", monotonic=" << (_monotonic?"asserted":"no") << (_no_data?", no-data":"") << ")"; return os;}
203private:
204 friend parent_impl;
206 Criterion_Extern_Value(const Criterion_Extern_Value& cev) :
207 _bridge("Criterion_Extern_Value"), // clones NEVER share pipes - each fresh bridge spawns its own child lazily
209 _no_data(cev._no_data),
210 _data_stale(true), // the clone's own child holds no DATA yet
211 _da(cev._da),
212 _classes(cev._classes),
213 _features(cev._features),
215 _index(cev._index)
216 {
217 _bridge.set_command(cev._bridge.get_command());
218 notify("Criterion_Extern_Value copy-constructor.");
219 }
220protected:
223 bool _no_data;
226 DIMTYPE _classes;
227 DIMTYPE _features;
228 DIMTYPE _subfeatures;
229 std::vector<DIMTYPE> _index;
230
231 bool send_data_block();
232 void send_row(const DIMTYPE label, const PPattern &pattern);
233 double parse_value(const std::string &line);
234};
235
236template<class RETURNTYPE, typename DATATYPE, typename REALTYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET, class DATAACCESSOR>
238{
239 notify("Criterion_Extern_Value::initialize().");
240 assert(da);
241 assert(da->getNoOfFeatures()>0);
242 // the class-count requirement guards the DATA protocol (its header carries K, its rows carry
243 // labels); in no-data mode the tool never sees either, and the data-free `--features` entry
244 // legitimately supplies a classless universe accessor — so the check applies only when DATA flows
245 if(!_no_data && da->getNoOfClasses()<2) throw fst_error("Criterion_Extern_Value requires at least 2 classes");
246 if(_bridge.get_command().empty()) throw fst_error("Criterion_Extern_Value: no command set (see --extern-cmd)");
247 _da=da;
248 _classes=da->getNoOfClasses();
249 _features=da->getNoOfFeatures();
250 _index.resize(_features);
251 _subfeatures=0;
252 _data_stale=true; // the pipeline calls initialize() whenever the effective split changes
253 // (the filter re-estimation contract) - the tool's DATA must follow
254}
255
256template<class RETURNTYPE, typename DATATYPE, typename REALTYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET, class DATAACCESSOR>
258{
259 std::FILE *out=_bridge.to_child();
260 char buf[64];
261 std::snprintf(buf,sizeof(buf),"%ld",(long)label); std::fputs(buf,out);
262 for(DIMTYPE f=0;f<_features;f++) // FULL width: the DATA block carries every feature
263 {
264 std::snprintf(buf,sizeof(buf),"%.17g",(double)pattern[f]); // bit round-trip for doubles
265 std::fputc(' ',out);
266 std::fputs(buf,out);
267 }
268 if(std::fputc('\n',out)==EOF)
269 _bridge.die_on_write();
270}
271
272template<class RETURNTYPE, typename DATATYPE, typename REALTYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET, class DATAACCESSOR>
274{
275 // header first: count the training patterns (cheap block-size sweep)
276 unsigned long long n=0;
277 {IDXTYPE s; for(DIMTYPE c=0;c<_classes;c++) {_da->setClass(c); for(const auto &blk : _da->blocks(TRAIN)) {s=blk.size; n+=(unsigned long long)s;}}}
278 if(n==0) return false;
279 _bridge.send_line("DATA "+std::to_string(n)+" "+std::to_string((long)_features)+" "+std::to_string((long)_classes));
280
281 typename DATAACCESSOR::PPattern p;
282 IDXTYPE s,i;
283 const DIMTYPE stride=_da->getNoOfFeatures();
284 for(DIMTYPE c=0;c<_classes;c++)
285 {
286 _da->setClass(c);
287 for(const auto &blk : _da->blocks(TRAIN)) for(i=0,p=blk.data,s=blk.size;i<s;i++)
288 send_row(c,&p[(std::size_t)i*stride]);
289 }
290 _bridge.flush_to_child();
291 const std::string resp=_bridge.read_line();
292 if(resp!="OK") throw fst_error("Criterion_Extern_Value: '"+_bridge.get_command()+"' rejected DATA: "+resp);
293 _data_stale=false;
294 return true;
295}
296
297template<class RETURNTYPE, typename DATATYPE, typename REALTYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET, class DATAACCESSOR>
299{
300 // strict full-line numeric parse: bare strtod would accept any garbage line (stray
301 // child diagnostics, "ERROR ..." messages) as a valid 0.0 value - silently wrong
302 // search results; fail loudly instead, like the classifier bridge's prediction parse
303 const char *s=line.c_str();
304 char *end=0;
305 const double v=std::strtod(s,&end);
306 if(end==s || *end!='\0')
307 {_bridge.shutdown_process(); throw fst_error("Criterion_Extern_Value: '"+_bridge.get_command()+"' returned a non-numeric value line: '"+line+"'");}
308 // strtod accepts "nan"/"inf" as numbers, but a non-finite criterion value would poison
309 // every comparison SILENTLY (NaN orders false against everything - subsets never win,
310 // B&B cut logic misbehaves invisibly); reject it as loudly as garbage text
311 if(!std::isfinite(v))
312 {_bridge.shutdown_process(); throw fst_error("Criterion_Extern_Value: '"+_bridge.get_command()+"' returned a non-finite value: '"+line+"' (criterion values must be finite; negate error-style measures inside the tool rather than returning infinities)");}
313 return v;
314}
315
316template<class RETURNTYPE, typename DATATYPE, typename REALTYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET, class DATAACCESSOR>
318{
319 notify("Criterion_Extern_Value::evaluate().");
320 assert(_da);
321 assert(sub);
322 assert(_classes==_da->getNoOfClasses());
323 assert(_features==_da->getNoOfFeatures());
324 assert(sub->get_n_raw()==_da->getNoOfFeatures());
325
326 // buffer the feature subset index
327 _subfeatures=0;
328 for(DIMTYPE fsel : sub->selected_features()) {assert(_subfeatures<_features); _index[_subfeatures++]=fsel;}
329 assert(_subfeatures==sub->get_d_raw());
330 if(_subfeatures==0) return false;
331
332 const bool was_running=_bridge.running();
333 _bridge.ensure_process();
334 if(!was_running) _data_stale=true; // a freshly (re)spawned child holds no DATA
335
336 if(!_no_data && _data_stale && !send_data_block()) return false; // empty train part
337 // (in no-data mode the tool never receives DATA - it computes from the indices alone)
338
339 // one VALUE request: d + the 0-based raw feature indices (ascending subset order)
340 std::string req="VALUE "+std::to_string((long)_subfeatures);
341 for(DIMTYPE f=0;f<_subfeatures;f++) {req+=' '; req+=std::to_string((long)_index[f]);}
342 _bridge.send_line(req);
343 _bridge.flush_to_child();
344 result=(RETURNTYPE)parse_value(_bridge.read_line());
345 return true;
346}
347
348} // namespace
349#endif // FSTCRITERIONEXTERNVALUE_H ///:~
CRTP mixin implementing the Clonable protocol for a concrete class.
Definition clonable.hpp:184
External-tool criterion: a user-supplied command computes the criterion value itself - unlike wrapper...
Definition criterion_extern_value.hpp:163
virtual bool is_monotonic() const override
Definition criterion_extern_value.hpp:176
bool send_data_block()
sends one full-width DATA block over the current split's TRAIN part (returns false on an empty train ...
Definition criterion_extern_value.hpp:273
std::shared_ptr< SUBSET > PSubset
shared pointer to the feature subset being evaluated
Definition criterion_extern_value.hpp:168
virtual std::ostream & print(std::ostream &os) const override
writes a human-readable identification of the object; base default writes nothing
Definition criterion_extern_value.hpp:202
void send_row(const DIMTYPE label, const PPattern &pattern)
sends one %.17g-formatted labelled FULL-WIDTH data row
Definition criterion_extern_value.hpp:257
Criterion_Extern_Value(const Criterion_Extern_Value &cev)
Copy-constructor; spawns its own fresh bridge (clones never share pipes) and copies the recorded data...
Definition criterion_extern_value.hpp:206
DATAACCESSOR::PPattern PPattern
raw feature-vector pointer type, as sent full-width by send_row()
Definition criterion_extern_value.hpp:169
void set_no_data(const bool nd)
--extern-no-data: suppress the DATA block - pure set-function optimization, the tool answers index-on...
Definition criterion_extern_value.hpp:177
DIMTYPE _features
raw feature count recorded by initialize(), from _da->getNoOfFeatures()
Definition criterion_extern_value.hpp:227
Clonable_Impl< Criterion_Extern_Value, parent > parent_impl
implements clone(); sharing/stateless_clone throw in Criterion
Definition criterion_extern_value.hpp:166
DIMTYPE _subfeatures
d = current subset size (number of valid entries in _index)
Definition criterion_extern_value.hpp:228
std::shared_ptr< DATAACCESSOR > PDataAccessor
shared pointer to the data accessor supplying the DATA block's TRAIN part
Definition criterion_extern_value.hpp:167
bool _no_data
--extern-no-data: never send DATA (the tool is a pure set function over index sets)
Definition criterion_extern_value.hpp:223
void set_monotonic(const bool m)
the user's assertion (--extern-monotonic); see the class note
Definition criterion_extern_value.hpp:175
double parse_value(const std::string &line)
strict full-line numeric parse incl. finiteness (throws on violation, symmetric with the classifier b...
Definition criterion_extern_value.hpp:298
virtual bool evaluate(RETURNTYPE &result, const PSubset sub) override
Evaluates sub by one VALUE request to the external tool.
Definition criterion_extern_value.hpp:317
Extern_Bridge _bridge
persistent child process + line I/O (per instance; never shared by clones)
Definition criterion_extern_value.hpp:221
const std::string & get_command() const
returns the currently configured external command line
Definition criterion_extern_value.hpp:174
DIMTYPE _classes
class count recorded by initialize(), from _da->getNoOfClasses()
Definition criterion_extern_value.hpp:226
bool _monotonic
the user's cardinality-monotonicity assertion
Definition criterion_extern_value.hpp:222
PDataAccessor _da
the data accessor whose TRAIN part feeds the DATA block
Definition criterion_extern_value.hpp:225
Criterion< RETURNTYPE, SUBSET > parent
base class: the abstract criterion interface
Definition criterion_extern_value.hpp:165
void initialize(const PDataAccessor da, const PDataAccessor da_for_evaluate=PDataAccessor())
Records the data shape and marks the tool's stored DATA stale; the criterion then evaluates on da's T...
Definition criterion_extern_value.hpp:237
std::vector< DIMTYPE > _index
subset position -> raw feature index (first _subfeatures entries valid)
Definition criterion_extern_value.hpp:229
bool _data_stale
the tool's stored DATA no longer matches the current split (set by initialize() and child respawn)
Definition criterion_extern_value.hpp:224
void set_command(const std::string &cmd)
sets the external command line (--extern-cmd); required before the first evaluate()
Definition criterion_extern_value.hpp:173
Abstract class, defines interface for feature selection criterion classes.
Definition criterion.hpp:84
Persistent-child-process line-protocol plumbing shared by the external-tool bridges: Classifier_Exter...
Definition extern_bridge.hpp:105
const std::string & get_command() const
returns the configured command line
Definition extern_bridge.hpp:113
FST4 specific error passing class.
Definition error.hpp:61
Defines interface for classes that may need to get cloned.
Defines interface for feature selection criterion classes.
FST4 specific error passing class.
Persistent-child-process line-protocol plumbing shared by the external-tool bridges (Classifier_Exter...
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
@ TRAIN
the split's training part
Definition data_accessor.hpp:85
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.