1#ifndef FSTSEARCHSEQSTEPSAMPLED_H
2#define FSTSEARCHSEQSTEPSAMPLED_H
155template<
class RETURNTYPE,
typename DIMTYPE,
class SUBSET,
class CRITERION,
class WEIGHTER>
158 typedef Sequential_Step<RETURNTYPE,DIMTYPE,SUBSET,CRITERION>
parent;
170 enum SamplerMode { SAMPLER_SOFTMAX, SAMPLER_UNIFORM, SAMPLER_TOPK };
185 : Sequential_Step<RETURNTYPE,DIMTYPE,SUBSET,CRITERION>(),
_stats(stats),
_engine(engine),
_cap(cap),
191 notify(
"Sequential_Step_Sampled constructor.");
228 virtual std::ostream&
print(std::ostream& os)
const override {
229 os <<
"Sequential_Step_Sampled(cap=";
232 os <<
", explore=" <<
_explore <<
", tau=";
233 if(
_tau>0.0) os <<
_tau;
else os <<
"auto";
234 os <<
", sampler=" << (
_sampler==SAMPLER_SOFTMAX?
"softmax":(
_sampler==SAMPLER_UNIFORM?
"uniform":
"topk"));
235 os <<
", stats=" << (
_stats->get_mode()==WEIGHTER::STATS_ZCONTRAST?
"zcontrast":
"rawmean") <<
", decay=" <<
_stats->get_horizon();
236 if(
_engine->is_threaded()) os <<
", threads=" <<
_engine->get_max_threads();
300 inline void note_step(
const bool forward,
const DIMTYPE order,
const DIMTYPE cnt,
const DIMTYPE pool, std::ostream& os);
316template<
class RETURNTYPE,
typename DIMTYPE,
class SUBSET,
class CRITERION,
class WEIGHTER>
322 assert(_generalization_level>=1 && _generalization_level<=sub->get_n());
323 if(
_stats->get_n()!=sub->get_n())
_stats->reset(sub->get_n());
324 const bool forward=sub->get_forward_mode();
325 const DIMTYPE pool = forward ? (DIMTYPE)(sub->get_n()-sub->get_d()) : sub->get_d();
326 if(pool==0)
return false;
329 if(sub->get_frozen_mode())
330 return full_sweep(result,sub,crit,_generalization_level,pool,os);
336 if(cap==0 || pool<=cap || _generalization_level>1)
337 return full_sweep(result,sub,crit,_generalization_level,pool,os);
342 if(
_cap_backward==0 || pool<=_cap_backward || _generalization_level>1)
343 return full_sweep(result,sub,crit,_generalization_level,pool,os);
347template<
class RETURNTYPE,
typename DIMTYPE,
class SUBSET,
class CRITERION,
class WEIGHTER>
350 const bool forward=sub->get_forward_mode();
356 RETURNTYPE bestval=0;
357 DIMTYPE order=0,cnt=0;
358 bool best_available=
false,stats_ok=
true;
361 if(!
_stats->add(val,csub)) stats_ok=
false;
364 if(!best_available || val>bestval) {bestval=val; order=cnt; best_available=
true;}
368 const DIMTYPE max_candidates =
_engine->is_threaded() ? sub->getNoOfCandidateSubsets(g,
false) : 1;
369 _engine->initialize(crit,max_candidates,on_result);
370 bool b=sub->getFirstCandidateSubset(g,
false);
373 if(!
_engine->add_candidate(sub))
return false;
374 b=sub->getNextCandidateSubset();
377 if(!
_engine->add_candidate(sub))
return false;
378 b=sub->getNextCandidateSubset();
381 DIMTYPE dummyfeature;
382 if(!
_engine->getBestResult(result,psub,dummyfeature))
return false;
383 if(!stats_ok)
return false;
385 assert(psub && psub->get_n()==sub->get_n());
386 sub->stateless_copy(*psub);
391template<
class RETURNTYPE,
typename DIMTYPE,
class SUBSET,
class CRITERION,
class WEIGHTER>
394 const DIMTYPE n=sub->get_n();
396 assert(cap>0 && pool>cap);
398 std::vector<DIMTYPE> freef;
400 for(DIMTYPE f=0;f<n;f++)
if(!sub->selected_raw(f)) freef.push_back(f);
401 assert((DIMTYPE)freef.size()==pool);
402 const DIMTYPE want=cap;
403 std::vector<DIMTYPE> prop;
405 std::vector<char> taken(n,0);
408 std::vector<DIMTYPE> byscore(freef);
409 std::partial_sort(byscore.begin(),byscore.begin()+want,byscore.end(),
410 [
this](
const DIMTYPE a,
const DIMTYPE b){const RETURNTYPE sa=_stats->score(a),sb=_stats->score(b); return sa>sb || (sa==sb && a<b);});
411 for(DIMTYPE i=0;i<want;i++) prop.push_back(byscore[i]);
413 DIMTYPE u = (
_sampler==SAMPLER_UNIFORM) ? want : (DIMTYPE)(
_explore*(
double)want+0.5);
418 std::vector<DIMTYPE> bycnt(freef);
419 const DIMTYPE le = (
_sampler==SAMPLER_UNIFORM) ? pool : std::min<DIMTYPE>(pool,std::max<DIMTYPE>(4*u,u));
421 std::partial_sort(bycnt.begin(),bycnt.begin()+le,bycnt.end(),
422 [
this](
const DIMTYPE a,
const DIMTYPE b){const auto ca=_stats->count_is(a),cb=_stats->count_is(b); return ca<cb || (ca==cb && a<b);});
423 for(DIMTYPE k=0;k<u;k++) {
424 const DIMTYPE j=k+(DIMTYPE)(
frand()*(
double)(le-k));
425 std::swap(bycnt[k],bycnt[j]);
426 prop.push_back(bycnt[k]);
430 const DIMTYPE rest=want-u;
433 std::vector<DIMTYPE> cand;
434 cand.reserve(pool-u);
435 for(
size_t i=0;i<freef.size();i++)
if(!taken[freef[i]]) cand.push_back(freef[i]);
436 std::vector<double> sc(cand.size());
437 for(
size_t i=0;i<cand.size();i++) sc[i]=(
double)
_stats->score(cand[i]);
440 std::vector<double> tmp(sc);
441 const size_t q1=tmp.size()/4, q3=(3*tmp.size())/4;
442 std::nth_element(tmp.begin(),tmp.begin()+q1,tmp.end());
443 const double a=tmp[q1];
444 std::nth_element(tmp.begin(),tmp.begin()+q3,tmp.end());
445 const double b=tmp[q3];
450 if(!(tau>1e-9)) tau=1e-9;
452 const double smax=*std::max_element(sc.begin(),sc.end());
453 std::vector<double> w(sc.size());
455 for(
size_t i=0;i<sc.size();i++) {w[i]=std::exp((sc[i]-smax)/tau); W+=w[i];}
456 for(DIMTYPE k=0;k<rest;k++) {
457 const double r=
frand()*W;
458 size_t pick=w.size();
460 for(
size_t i=0;i<w.size();i++) {
461 if(w[i]<=0.0)
continue;
463 if(r<acc) {pick=i;
break;}
465 if(pick==w.size()) {
for(
size_t i=w.size();i-->0;)
if(w[i]>0.0) {pick=i;
break;}}
476 for(
size_t i=0;i<w.size();i++)
if(w[i]>=0.0 && (pick==w.size() || sc[i]>sc[pick])) pick=i;
478 assert(pick<w.size());
479 prop.push_back(cand[pick]);
485 assert((DIMTYPE)prop.size()==want);
492 else tmp_cand->stateless_copy(*sub);
493 RETURNTYPE bestval=0;
494 DIMTYPE bestf=n,order=0,cnt=0;
498 if(!
_stats->add(val,csub)) stats_ok=
false;
501 if(bestf==n || val>bestval) {
507 _engine->initialize(crit,want,on_result);
508 for(
size_t i=0;i<prop.size();i++) {
509 const DIMTYPE f=prop[i];
515 if(!
_engine->collect())
return false;
516 if(!stats_ok)
return false;
518 if(bestf==n)
return false;
519 sub->select_raw(bestf);
536template<
class RETURNTYPE,
typename DIMTYPE,
class SUBSET,
class CRITERION,
class WEIGHTER>
539 const DIMTYPE n=sub->get_n();
541 assert(cap>0 && pool>cap);
542 assert(!sub->get_forward_mode());
544 std::vector<DIMTYPE> memb;
546 for(DIMTYPE f=0;f<n;f++)
if(sub->selected_raw(f)) memb.push_back(f);
547 assert((DIMTYPE)memb.size()==pool);
548 const DIMTYPE want=cap;
549 std::vector<DIMTYPE> prop;
551 std::vector<char> taken(n,0);
554 std::vector<DIMTYPE> byscore(memb);
555 std::partial_sort(byscore.begin(),byscore.begin()+want,byscore.end(),
556 [
this](
const DIMTYPE a,
const DIMTYPE b){const RETURNTYPE sa=_stats->score(a),sb=_stats->score(b); return sa<sb || (sa==sb && a<b);});
557 for(DIMTYPE i=0;i<want;i++) prop.push_back(byscore[i]);
559 DIMTYPE u = (
_sampler==SAMPLER_UNIFORM) ? want : (DIMTYPE)(
_explore*(
double)want+0.5);
564 std::vector<DIMTYPE> bycnt(memb);
565 const DIMTYPE le = (
_sampler==SAMPLER_UNIFORM) ? pool : std::min<DIMTYPE>(pool,std::max<DIMTYPE>(4*u,u));
567 std::partial_sort(bycnt.begin(),bycnt.begin()+le,bycnt.end(),
568 [
this](
const DIMTYPE a,
const DIMTYPE b){const auto ca=_stats->count_isnot(a),cb=_stats->count_isnot(b); return ca<cb || (ca==cb && a<b);});
569 for(DIMTYPE k=0;k<u;k++) {
570 const DIMTYPE j=k+(DIMTYPE)(
frand()*(
double)(le-k));
571 std::swap(bycnt[k],bycnt[j]);
572 prop.push_back(bycnt[k]);
576 const DIMTYPE rest=want-u;
580 std::vector<DIMTYPE> cand;
581 cand.reserve(pool-u);
582 for(
size_t i=0;i<memb.size();i++)
if(!taken[memb[i]]) cand.push_back(memb[i]);
583 std::vector<double> sc(cand.size());
584 for(
size_t i=0;i<cand.size();i++) sc[i]=(
double)
_stats->score(cand[i]);
587 std::vector<double> tmp(sc);
588 const size_t q1=tmp.size()/4, q3=(3*tmp.size())/4;
589 std::nth_element(tmp.begin(),tmp.begin()+q1,tmp.end());
590 const double a=tmp[q1];
591 std::nth_element(tmp.begin(),tmp.begin()+q3,tmp.end());
592 const double b=tmp[q3];
597 if(!(tau>1e-9)) tau=1e-9;
599 const double smin=*std::min_element(sc.begin(),sc.end());
600 std::vector<double> w(sc.size());
602 for(
size_t i=0;i<sc.size();i++) {w[i]=std::exp((smin-sc[i])/tau); W+=w[i];}
603 for(DIMTYPE k=0;k<rest;k++) {
604 const double r=
frand()*W;
605 size_t pick=w.size();
607 for(
size_t i=0;i<w.size();i++) {
608 if(w[i]<=0.0)
continue;
610 if(r<acc) {pick=i;
break;}
612 if(pick==w.size()) {
for(
size_t i=w.size();i-->0;)
if(w[i]>0.0) {pick=i;
break;}}
619 for(
size_t i=0;i<w.size();i++)
if(w[i]>=0.0 && (pick==w.size() || sc[i]<sc[pick])) pick=i;
621 assert(pick<w.size());
622 prop.push_back(cand[pick]);
628 assert((DIMTYPE)prop.size()==want);
633 RETURNTYPE bestval=0;
634 DIMTYPE bestf=n,order=0,cnt=0;
638 if(!
_stats->add(val,csub)) stats_ok=
false;
641 if(bestf==n || val>bestval) {
647 _engine->initialize(crit,want,on_result);
648 for(
size_t i=0;i<prop.size();i++) {
649 const DIMTYPE f=prop[i];
652 if(!
_engine->add_candidate(sub,f))
return false;
653 sub->deselect_raw(f);
655 if(!
_engine->collect())
return false;
656 if(!stats_ok)
return false;
658 if(bestf==n)
return false;
659 sub->select_raw(bestf);
665template<
class RETURNTYPE,
typename DIMTYPE,
class SUBSET,
class CRITERION,
class WEIGHTER>
669 const RETURNTYPE r=(RETURNTYPE)order/(RETURNTYPE)cnt;
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 the budgeted (sampled) sequential selection step: forward steps evaluate only a sampled ba...
Definition seq_step_sampled.hpp:156
void note_step(const bool forward, const DIMTYPE order, const DIMTYPE cnt, const DIMTYPE pool, std::ostream &os)
Folds one completed step's outcome into the order-instrumentation running averages (order_forward/ord...
Definition seq_step_sampled.hpp:666
DIMTYPE count_forward
Definition seq_step_sampled.hpp:309
PWeighter _stats
Definition seq_step_sampled.hpp:245
virtual bool print_summary(std::ostream &os=std::cout)
Prints the statistics engine's diagnostic top-scored-feature listing (Result_Weighter_Sampled::print_...
Definition seq_step_sampled.hpp:242
PEvaluatorEngine _engine
Definition seq_step_sampled.hpp:246
bool sampled_forward(RETURNTYPE &result, const PSubset sub, const PCriterion crit, const DIMTYPE pool, const DIMTYPE cap, std::ostream &os)
Budgeted forward step: proposes exactly cap candidate features (see the class docs above for the samp...
Definition seq_step_sampled.hpp:392
bool evaluate_candidates(RETURNTYPE &result, const PSubset sub, const PCriterion crit, const DIMTYPE _generalization_level=1, std::ostream &os=std::cout) override
Performs one selection step on sub: routes to the budgeted forward path, the budgeted backward path o...
Definition seq_step_sampled.hpp:317
RETURNTYPE order_backward
Definition seq_step_sampled.hpp:312
bool sampled_backward(RETURNTYPE &result, const PSubset sub, const PCriterion crit, const DIMTYPE pool, const DIMTYPE cap, std::ostream &os)
Budgeted backward step, the removal mirror of sampled_forward (kept as a separate body on purpose — s...
Definition seq_step_sampled.hpp:537
RETURNTYPE order_forward
Definition seq_step_sampled.hpp:311
SamplerMode _sampler
Definition seq_step_sampled.hpp:252
Sequential_Step< RETURNTYPE, DIMTYPE, SUBSET, CRITERION > parent
Definition seq_step_sampled.hpp:158
DIMTYPE count_backward
Definition seq_step_sampled.hpp:310
DIMTYPE _cap
Definition seq_step_sampled.hpp:247
double get_cap_frac() const
current constant-percentage schedule fraction (0 = disabled, see set_cap_frac())
Definition seq_step_sampled.hpp:200
Sequential_Step_Sampled(PWeighter stats, const DIMTYPE cap=100, const double explore=0.2, const double tau=0.0, const SamplerMode sampler=SAMPLER_SOFTMAX, PEvaluatorEngine engine=PEvaluatorEngine())
Constructs the step with its statistics engine, per-step evaluation budget, proposal sampler and (opt...
Definition seq_step_sampled.hpp:184
std::shared_ptr< SUBSET > PSubset
Definition seq_step_sampled.hpp:160
DIMTYPE _cap_backward
Definition seq_step_sampled.hpp:248
bool full_sweep(RETURNTYPE &result, const PSubset sub, const PCriterion crit, const DIMTYPE g, const DIMTYPE pool, std::ostream &os)
Full candidate sweep (the Sequential_Step_Straight fallback): evaluates every candidate subset return...
Definition seq_step_sampled.hpp:348
std::shared_ptr< CRITERION > PCriterion
Definition seq_step_sampled.hpp:159
std::shared_ptr< EVALUATORENGINE > PEvaluatorEngine
Definition seq_step_sampled.hpp:163
void set_cap_frac(const double frac)
Switches the forward budget to a constant-PERCENTAGE schedule: when frac >0 the forward step cap beco...
Definition seq_step_sampled.hpp:199
double _explore
Definition seq_step_sampled.hpp:250
double frand()
uniform [0,1); fst_rand()-based per the --seed contract
Definition seq_step_sampled.hpp:301
unsigned long long all_evals
Definition seq_step_sampled.hpp:313
PWeighter get_stats()
shared statistics engine (fst4 feeds warm-up probes through it)
Definition seq_step_sampled.hpp:222
double _cap_frac
Definition seq_step_sampled.hpp:249
double _tau
Definition seq_step_sampled.hpp:251
Candidate_Evaluator< RETURNTYPE, DIMTYPE, SUBSET, CRITERION > EVALUATORENGINE
Definition seq_step_sampled.hpp:162
PSubset tmp_cand
Definition seq_step_sampled.hpp:303
DIMTYPE get_cap_backward() const
current backward-step budget y_b (0 = full sweeps, see set_cap_backward())
Definition seq_step_sampled.hpp:206
void set_cap_backward(const DIMTYPE cap)
Sets the backward-step budget y_b: 0 (default) = full backward sweeps, which keeps the floating corre...
Definition seq_step_sampled.hpp:205
SamplerMode
Proposal-sampling policy for the forward/backward candidate batch (see the class docs above for the e...
Definition seq_step_sampled.hpp:170
std::shared_ptr< WEIGHTER_SAMPLED > PWeighter
Definition seq_step_sampled.hpp:161
virtual std::ostream & print(std::ostream &os) const override
Writes a human-readable identification of the step configuration (cap or the percentage schedule,...
Definition seq_step_sampled.hpp:228
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
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
FST4 specific error passing class.
FST4-owned pseudo-random number generator (UCRT-compatible LCG), replacing platform-specific std::ran...
The Feature Selection Toolbox 4 library: every library component – data access, criteria and classifi...
Definition data_accessor.hpp:80
int fst_rand()
Returns the next pseudo-random draw in 0..FST_RAND_MAX; use instead of std::rand().
Definition fst_rand.hpp:93
const int FST_RAND_MAX
Maximum value fst_rand() can return; use instead of the libc macro RAND_MAX.
Definition fst_rand.hpp:101
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
Online per-feature statistics for budgeted (sampled) sequential steps — discounted batch-standardized...
Defines interface for implementations of one selection step in sequential search type of methods.