External-tool criterion: a user-supplied command computes the criterion value itself - unlike wrapper-extern, which exchanges labels and computes accuracy on the FST4 side. More...
#include <criterion_extern_value.hpp>
Public Types | |
| typedef Criterion< RETURNTYPE, SUBSET > | parent |
| base class: the abstract criterion interface | |
| typedef Clonable_Impl< Criterion_Extern_Value, parent > | parent_impl |
| implements clone(); sharing/stateless_clone throw in Criterion | |
| typedef std::shared_ptr< DATAACCESSOR > | PDataAccessor |
| shared pointer to the data accessor supplying the DATA block's TRAIN part | |
| typedef std::shared_ptr< SUBSET > | PSubset |
| shared pointer to the feature subset being evaluated | |
| typedef DATAACCESSOR::PPattern | PPattern |
| raw feature-vector pointer type, as sent full-width by send_row() | |
| Public Types inherited from FST::Criterion< RETURNTYPE, SUBSET > | |
| typedef std::shared_ptr< SUBSET > | PSubset |
| shared pointer to the feature subset being evaluated | |
Public Member Functions | |
| void | set_command (const std::string &cmd) |
| sets the external command line (--extern-cmd); required before the first evaluate() | |
| const std::string & | get_command () const |
| returns the currently configured external command line | |
| void | set_monotonic (const bool m) |
| the user's assertion (--extern-monotonic); see the class note | |
| virtual bool | is_monotonic () const override |
| void | set_no_data (const bool nd) |
| --extern-no-data: suppress the DATA block - pure set-function optimization, the tool answers index-only VALUE requests from its own logic | |
| 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 TRAIN part. Must be called before the first evaluate(), and again whenever the effective split changes – that is what makes the next evaluate() re-send the DATA block. Throws fst_error when no command has been set, or (unless no-data mode is in effect) when da has fewer than 2 classes. | |
| virtual bool | evaluate (RETURNTYPE &result, const PSubset sub) override |
Evaluates sub by one VALUE request to the external tool. | |
| virtual std::ostream & | print (std::ostream &os) const override |
| writes a human-readable identification of the object; base default writes nothing | |
| Public Member Functions inherited from FST::Clonable_Impl< Criterion_Extern_Value< RETURNTYPE, DATATYPE, REALTYPE, IDXTYPE, DIMTYPE, SUBSET, DATAACCESSOR >, Criterion< RETURNTYPE, SUBSET > > | |
| Criterion< RETURNTYPE, SUBSET > * | clone () const override |
| dispatches to the DEEP_KIND mechanism (default CLONE_DEEP: Derived's copy-constructor) | |
| Criterion< RETURNTYPE, SUBSET > * | sharing_clone () const override |
| dispatches to the SHARING_KIND mechanism (default CLONE_INHERIT: defers to Base, which throws by family convention) | |
| Criterion< RETURNTYPE, SUBSET > * | stateless_clone () const override |
| dispatches to the STATELESS_KIND mechanism (default CLONE_INHERIT: defers to Base, which throws by family convention) | |
| Public Member Functions inherited from FST::Criterion< RETURNTYPE, SUBSET > | |
| Criterion * | sharing_clone () const override |
| Criterion * | stateless_clone () const override |
| Public Member Functions inherited from FST::Clonable | |
| bool | is_clone () const |
| bool | is_sharing () const |
| true if this instance is a sharing_clone() result (referencing, not owning, the source's structures) | |
| bool | is_sharing_clone () const |
| true if this instance is BOTH a clone and sharing – i.e. specifically a sharing_clone() result, not a clone()/stateless_clone() one | |
Protected Member Functions | |
| bool | send_data_block () |
| sends one full-width DATA block over the current split's TRAIN part (returns false on an empty train part) | |
| void | send_row (const DIMTYPE label, const PPattern &pattern) |
| sends one %.17g-formatted labelled FULL-WIDTH data row | |
| double | parse_value (const std::string &line) |
| strict full-line numeric parse incl. finiteness (throws on violation, symmetric with the classifier bridge's loudness) | |
| Protected Member Functions inherited from FST::Clonable | |
| void | set_cloned (const bool cloned=true) |
| marks/unmarks this instance as a clone; call from clone()/stateless_clone() overrides (Clonable_Impl does this automatically) | |
| void | set_sharing (const bool sharing=true) |
| marks/unmarks this instance as sharing (see is_sharing()) | |
| void | set_sharing_cloned (const bool cloned=true, const bool sharing=true) |
| sets both flags at once; call from sharing_clone() overrides (Clonable_Impl does this automatically) | |
Protected Attributes | |
| Extern_Bridge | _bridge |
| persistent child process + line I/O (per instance; never shared by clones) | |
| bool | _monotonic |
| the user's cardinality-monotonicity assertion | |
| bool | _no_data |
| --extern-no-data: never send DATA (the tool is a pure set function over index sets) | |
| bool | _data_stale |
| the tool's stored DATA no longer matches the current split (set by initialize() and child respawn) | |
| PDataAccessor | _da |
| the data accessor whose TRAIN part feeds the DATA block | |
| DIMTYPE | _classes |
| class count recorded by initialize(), from _da->getNoOfClasses() | |
| DIMTYPE | _features |
| raw feature count recorded by initialize(), from _da->getNoOfFeatures() | |
| DIMTYPE | _subfeatures |
| d = current subset size (number of valid entries in _index) | |
| std::vector< DIMTYPE > | _index |
| subset position -> raw feature index (first _subfeatures entries valid) | |
Private Member Functions | |
| Criterion_Extern_Value (const Criterion_Extern_Value &cev) | |
| Copy-constructor; spawns its own fresh bridge (clones never share pipes) and copies the recorded data shape. | |
Private Attributes | |
| friend | parent_impl |
External-tool criterion: a user-supplied command computes the criterion value itself - unlike wrapper-extern, which exchanges labels and computes accuracy on the FST4 side.
One PERSISTENT child process per criterion instance (spawned lazily on first use; clones spawn their own, so threaded evaluation is isolation-safe), speaking a line protocol on stdin/stdout:
-> DATA <N> <D> <K>\n followed by N lines <label> <v1> ... <vD> <- OK\n (anything else fails the evaluation, loudly) -> VALUE <d> <f1> ... <fd>\n (0-based RAW feature indices, ascending) <- one line: the criterion value (parsed as a strict full-line double)
The DATA block carries the FULL-width TRAIN part of the current split (the filter convention: the criterion sees training data only) and is sent once per split - re-sent whenever initialize() is called (the pipeline's refresh contract, same as filter model re-estimation) or the child was (re)spawned. Each evaluation then costs one VALUE request of d integers: the tool holds the data (or better, per-feature SUFFICIENT STATISTICS computed at DATA time) and answers from the indices - O(d) per request instead of re-streaming N*d values (the cost model that matters under B&B's thousands of evaluations). Raw indices also give the tool feature IDENTITIES (per-feature caching, acquisition-cost-aware measures). Values are exchanged as %.17g decimal (bit round-trip for doubles). A reference implementation ships in tests/extern_value_meandiff.awk (the sufficient-statistics pattern).
NO-DATA MODE (set_no_data(), the CLI's --extern-no-data): the DATA block is suppressed entirely and the tool answers index-only VALUE requests from logic of its own - cost tables, simulations, external experiments: FST4 as a black-box SET-FUNCTION optimizer over an abstract feature universe. A dataset is then only a source of the universe size, and the fst4 CLI does not need one at all in this mode: --features N replaces --data and supplies a feature-only accessor of N features and no classes. The three-layer design: wrapper-extern = external CLASSIFIER, extern-value with DATA = external DATA-DEPENDENT CRITERION (the DATA block is the split-synchronization mechanism - only FST4 knows the current split, and a self-loading tool would leak held-out data), extern-value with no data = external SET FUNCTION.
VALUE SEMANTICS: FST4 maximizes - larger values must mean better subsets (negate error-style measures inside the tool). There is NO range or scale requirement beyond that: criterion values are only ever compared within the same search, never across criteria (built-in filters return unbounded distances, wrappers [0,1] accuracies — both coexist for the same reason). Values must be FINITE doubles (non-finite responses fail loudly, see parse_value) and deterministic for identical requests. Flags expressed in value units (--tracker-margin, --regularize-margins) are in the external measure's own units, as with every criterion.
NORMALIZATION follows the standard FST4 convention: the streamed values are the accessor's in-memory data AFTER the global --scaler (applied per-feature over the whole dataset at load) — exactly what built-in criteria see; the bridge adds NO internal per-training standardization. If the tool normalizes further, beware the monotonicity assertion: per-feature-independent normalization is safe for per-feature-sum measures, but normalization coupling the streamed columns (subset-level variance/totals) can silently break the asserted monotonicity and void the B&B optimality guarantee.
MONOTONICITY AND BRANCH & BOUND: is_monotonic() returns what the user asserted via set_monotonic() (the CLI's --extern-monotonic; default false). Asserting it admits the criterion to the optimal B&B searches — THE OPTIMALITY GUARANTEE THEN RESTS ENTIRELY ON THE ASSERTION being true of the external measure (removing a feature must never increase the value). A false assertion yields silently suboptimal "optimal" results. Without the assertion, Search_Branch_And_Bound prints its warning (and the fst4 CLI refuses bb-* searches outright).
All LOUD CAVEATS of the extern mechanism apply as for wrapper-extern (classifier_extern.hpp): USER-SUPPLIED CODE EXECUTION through the system shell; REPRODUCIBILITY GUARANTEES END AT THE BRIDGE (a stochastic external measure breaks run- and thread-reproducibility AND, under B&B, the optimality logic itself); no timeout machinery (extern_bridge.hpp).
|
overridevirtual |
Evaluates sub by one VALUE request to the external tool.
Sends "VALUE d f1 ... fd" with the 0-based RAW feature indices in ascending subset order and reads back one line holding the value. Before that, in the DATA modes, the DATA block is (re)sent whenever it is stale – after an initialize(), and after the child process was spawned or respawned, since a fresh child holds nothing.
Implements FST::Criterion< RETURNTYPE, SUBSET >.
| void FST::Criterion_Extern_Value< RETURNTYPE, DATATYPE, REALTYPE, IDXTYPE, DIMTYPE, SUBSET, DATAACCESSOR >::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 TRAIN part. Must be called before the first evaluate(), and again whenever the effective split changes – that is what makes the next evaluate() re-send the DATA block. Throws fst_error when no command has been set, or (unless no-data mode is in effect) when da has fewer than 2 classes.
| da | the accessor the criterion reads; its currently designated TRAIN part becomes the DATA block, and its feature count the size of the feature universe. |
| da_for_evaluate | accepted for signature compatibility with the criteria that evaluate on a second accessor; this criterion has no such split and ignores it. |
|
inlineoverridevirtual |
Declares monotonicity with respect to subset cardinality: true means removing a feature can NEVER increase the criterion value. Branch & Bound prunes on this property, so ALL of its optimality guarantees rest on this declaration - and the library cannot verify it, it is an assertion made by the criterion's author. A false declaration silently turns Branch & Bound into a heuristic that may skip the optimum. Search_Branch_And_Bound therefore prints a warning at search start when the supplied criterion does not declare the property, and the fst4 command-line tool refuses the --search bb-* algorithms outright for such a criterion. Defaults to false: user-supplied criteria should override to true only if monotonicity provably holds. The built-in normal-model and multinomial filters declare true (see Criterion_Normal and Criterion_Multinomial); wrapper criteria and the adapter criteria (negative/subset-size/sum-of-weights) deliberately keep the false default.
Reimplemented from FST::Criterion< RETURNTYPE, SUBSET >.
|
inlineoverridevirtual |
writes a human-readable identification of the object; base default writes nothing
Reimplemented from FST::Clonable.
|
private |
grants Clonable_Impl access to the copy-constructor