Fleet  0.0.9
Inference in the LOT
BaseGrammarHypothesis.h
Go to the documentation of this file.
1 #pragma once
2 
3  // Tune up eigen wrt thread safety
4 #include <assert.h>
5 #include <utility>
6 #include <regex>
7 #include <signal.h>
8 #include <unordered_map>
9 
10 #include "EigenLib.h"
11 #include "Errors.h"
12 #include "Numerics.h"
13 #include "DiscreteDistribution.h"
14 
15 #include "Vector2D.h"
16 #include "HumanDatum.h"
17 #include "Control.h"
18 #include "TopN.h"
19 #include "MCMCChain.h"
20 
21 //extern volatile sig_atomic_t CTRL_C;
22 
24 #include "VectorNormalHypothesis.h"
25 #include "TNormalVariable.h"
26 #include "Batch.h"
27 #include "LOTHypothesis.h"
28 #include "Grammar.h"
29 
43 template<typename this_t,
44  typename _HYP,
45  typename datum_t=HumanDatum<_HYP>,
46  typename data_t=std::vector<datum_t>,
47  typename _Predict_t=Vector2D<DiscreteDistribution<typename _HYP::output_t>> > // The type here for Predict_t will depend on the subtype (deterministic or not; thunk or not)
48 class BaseGrammarHypothesis : public MCMCable<this_t, datum_t, data_t>,
49  public Serializable<this_t> {
50 public:
51  using HYP = _HYP;
52 
53  // The type for predictions varies between subclasses -- might be a Vector2D of DiscreteDistribution (for FullGrammarHypothesis),
54  // a Vector2D of single outputs (for deterministic), or a Vector2D with only one value for the second dimension when it
55  // is a thunk. These variants are the whole reason we have subclasses, although there is a lot of repeated code
56  // so this might change in the future.
57  // NOTE: These do NOT mix in alpha -- that happens in compute_likelihood
58  using Predict_t = _Predict_t;
59 
60  // take a data pointer and map it to a hypothesis x i'th item for that data point
61  using LL_t = std::unordered_map<typename datum_t::data_t*, std::vector<Vector> >;
62 
63  typename HYP::Grammar_t* grammar;
64 
65  // Here is a list of built-in parameters that we can use. Each stores a standard
66  // normal and a value under the specified transformation, which is chosen here to give
67  // a reasonably shaped prior
68 public:
69  // if this is true, then we don't propose to any of logA, and we treat logA just as a bunch of zeros
70  bool flat_prior;
71 
72  // where we store the logA values
74 
75 protected:
76  // these are now protected because when they are set, we have to recompute stuff sometimes
77  // Parameters for inference
78  UniformVariable alpha; // uniform in [0,1]
79  ExponentialVariable decay; // expoential decay parameter
80 // TNormalVariable< +[](float x)->float { return expf((x-0.33)/1.50); }> llt;
81 // TNormalVariable< +[](float x)->float { return expf(x/5.0); }> pt; // NOTE: Pt is not currently in use!
82 
83 public:
84 
85  // All of these are shared_ptr so that we can copy hypotheses quickly
86  // without recomputing them. NOTE that this assumes that the data does not change
87  // between hypotheses of this class.
88 
89  std::shared_ptr<Matrix> C;
90  std::shared_ptr<LL_t> LL; // type for the likelihood
91 
92  std::shared_ptr<Predict_t> P;
93 
94  // These variables store some parameters and get recomputed
95  // in proposal when necessary
96  std::shared_ptr<Matrix> decayedLikelihood;
97 
98  // stored so we can remember what we computed for.
99  const data_t* which_data;
100  std::vector<HYP>* which_hypotheses;
101 
102 
103  BaseGrammarHypothesis() : flat_prior(false) {
104  decay.set_untransformed(0.1);
105  alpha.set_untransformed(1.0);
106  }
107 
108  BaseGrammarHypothesis(std::vector<HYP>& hypotheses, const data_t* human_data) : flat_prior(false) {
109  // This has to take human_data as a pointer because of how MCMCable::make works -- can't forward a reference
110  // but the rest of this class likes the references, so we convert here
111  decay.set_untransformed(0.1);
112  alpha.set_untransformed(1.0);
113  this->set_hypotheses_and_data(hypotheses, *human_data);
114  }
115 
116  // must do these together
117  void set_decay(const ExponentialVariable& ev) {
118  if(ev != decay) {
119  decay = ev;
120  this->recompute_decayedLikelihood(*which_data);
121  }
122  }
123 
124  void set_decay_untransformed(double v) {
125  if(v != decay.get_untransformed()){
126  decay.set_untransformed(v);
127  this->recompute_decayedLikelihood(*which_data);
128  }
129  }
130 
131  void set_alpha(const UniformVariable& a ) {
132  if(a != alpha) {
133  alpha = a;
134  this->recompute_LL(*which_hypotheses, *which_data);
135  }
136  }
137  void set_alpha_untransformed(double v) {
138  if(v != alpha.get_untransformed()){
139  alpha.set_untransformed(v);
140  this->recompute_LL(*which_hypotheses, *which_data);
141  }
142  }
143 
145  // sometimes we want the parameters of h, but on some new (e.g. heldout) data
146  this->logA = h.logA;
147 // this->llt = h.llt;
148 // this->pt = h.pt;
149  this->set_alpha(h.alpha);
150  this->set_decay(h.decay); // NOTE: this calls recompute_decayedLikelihood on my OWN data
151  }
152 
153  // we write this as a function so that we can override (and remove llt if we want)
154 // float get_llt() const { return llt.get(); }
155  float get_alpha() const { return alpha.get(); }
156  float get_decay() const { return decay.get(); }
157 
158  size_t ndata() const { return which_data->size(); }
159 
160  // we overwrite this because in MCMCable, this wants to check get_value, which is not defined here
161  [[nodiscard]] static this_t sample(std::vector<HYP>& hypotheses, const data_t* human_data) {
162  // NOTE: Cannot use templates because then it doesn't pass my hypotheses ref the right way
163  auto h = this_t(hypotheses, human_data);
164  return h.restart();
165  }
166 
172  virtual void set_hypotheses_and_data(std::vector<HYP>& hypotheses, const data_t& human_data) {
173 
174  // set first because it's required below
175  which_data = std::addressof(human_data);
176  which_hypotheses = std::addressof(hypotheses);
177 
178  // read the hypothesis from the first grammar, and check its the same for everyone
179  grammar = hypotheses.at(0).get_grammar();
180  for(auto& h: hypotheses) {
181  assert(h.get_grammar() == grammar && "*** It's bad news for GrammarHypothesis if your hypotheses don't all have the same grammar.");
182  }
183 
184  if(logA.size() != grammar->count_rules()) {
185  if(logA.size() > 0) print("*** Warning: resizing and zeroing logA");
186  logA.set_size(grammar->count_rules());
187  }
188 
189  // when we are initialized this way, we compute C, LL, P, and the decayed ll.
190  COUT "# Computing prior counts" ENDL;
191  this->recompute_C(hypotheses);
192  COUT "# Computing model predictions" ENDL;
193  this->recompute_P(hypotheses, human_data); // note this comes before LL because LL might use P
194  COUT "# Computing incremental likelihoods " ENDL;
195  this->recompute_LL(hypotheses, human_data);
196  COUT "# Computing decayedLikelihood" ENDL;
197  this->recompute_decayedLikelihood(human_data);
198  COUT "# Done. " ENDL;
199 
200  }
201 
208  virtual void set_can_propose(size_t i, bool b) {
209  logA.set_can_propose(i,b);
210 
211  if(logA(i) != 0.0) { CERR "# Warning, set_can_propose is setting false to logA(" << str(i) << ") != 0.0 (this is untransformed space)" ENDL; }
212  }
213 
214 
215  void set_flat_prior(bool fp) {
216  flat_prior = fp;
217  if(flat_prior) {
218  for(size_t i=0;i<logA.size();i++) {
219  logA.set(i,0.0);
220  }
221  }
222  }
223 
228  virtual size_t nhypotheses() const { return C->rows(); }
229 
235  virtual void recompute_C(const std::vector<HYP>& hypotheses) {
236 
237  assert(hypotheses.size() > 0);
238 
239  size_t nRules = hypotheses[0].get_grammar()->count_rules();
240 
241  C.reset(new Matrix(hypotheses.size(), nRules));
242 
243  const auto indexer = grammar->get_rule_indexer(); // map rules to
244  const auto R = grammar->count_rules();
245 
246  #pragma omp parallel for
247  for(size_t i=0;i<hypotheses.size();i++) {
248  assert(hypotheses[i].get_grammar() == grammar); // this only works if they have the same grammar, since they share an indexer
249 
250  // hypotheses here are factors so we have to sum them
251  Vector cv = Vector::Zero(R);
252 
253  auto c = grammar->get_counts(hypotheses[i].get_value(), indexer); // extract counts using indexer
254  for(size_t r=0;r<R;r++) // update cv
255  cv[r] += c[r];
256 
257  #pragma omp critical
258  C->row(i) = std::move(cv);
259  }
260 
261  assert( (size_t)C->rows() == hypotheses.size());
262  }
263 
271  virtual void recompute_LL(std::vector<HYP>& hypotheses, const data_t& human_data) {
272  assert(which_data == std::addressof(human_data));
273 // print("*** Recomputing LL");
274 
275  // For each HumanDatum::data, figure out the max amount of data it contains
276  std::unordered_map<typename datum_t::data_t*, size_t> max_sizes;
277  for(auto& d : human_data) {
278  if( (not max_sizes.contains(d.data)) or max_sizes[d.data] < d.ndata) {
279  max_sizes[d.data] = d.ndata;
280  }
281  }
282 
283  auto a = this->alpha.get();
284 
285  LL.reset(new LL_t());
286  LL->reserve(max_sizes.size()); // reserve for the same number of elements
287 
288  // now go through and compute the likelihood of each hypothesis on each data set
289  for(const auto& [dptr, sz] : max_sizes) {
290  if(CTRL_C) break;
291 
292  LL->emplace(dptr, nhypotheses()); // in this place, make something of size nhypotheses
293 
294  #pragma omp parallel for
295  for(size_t h=0;h<nhypotheses();h++) {
296 
297  // set up all the likelihoods here
298  Vector data_lls = Vector::Zero(sz);
299 
300  // read the max size from above and compute all the likelihoods
301  for(size_t i=0;i<max_sizes[dptr];i++) {
302 
303  // here we could do
304  // data_lls(i) = hypotheses[h].compute_single_likelihood(x.first->at(i));
305  // but the problem is that isn't defined for some hypotheses. So we'll use
306  // the slightly slower
307  typename HYP::data_t d = { dptr->at(i) };
308  for(auto& di : d) {
309  di.reliability = a; // set to our alpha value
310  }
311 
312  data_lls(i) = hypotheses[h].compute_likelihood(d);
313 
314  //print(hypotheses[h].string(), data_lls(i) , str(dptr->at(i)), hypotheses[h].call(dptr->at(i).input), dptr->at(i).output);
315 
316  assert(not std::isnan(data_lls(i))); // NaNs will really mess everything up
317  }
318 
319  #pragma omp critical
320  //print(h, max_sizes[dptr], data_lls.transpose(), hypotheses[h].string());
321  LL->at(dptr)[h] = std::move(data_lls);
322 
323  }
324  }
325 
326 
327 
328 
329 
330  //print("HEERRRE", LL->at(human_data[87].data)[1], str(*human_data[87].data));
331  //print("HEERRRE", LL->at(human_data[8].data)[1], str(*human_data[8].data));
332 
333 
334  }
335 
343  virtual void recompute_decayedLikelihood(const data_t& human_data) {
344  assert(which_data == std::addressof(human_data));
345 
346  // we need a NEW decayed ll if we change it
347  decayedLikelihood.reset(new Matrix(nhypotheses(), human_data.size()));
348 
349  // find the max power we'll ever need
350  int MX = 0; // we could start this at -1 but then for zero data things go bad
351  for(auto& di : human_data) {
352  MX = std::max(MX, di.decay_index+1); // need +1 since 0 decay needs one value
353  }
354 
355  // just compute this once -- should be faster to use vector intrinsics?
356  // we store these in reverse order from some max data size
357  // so that we can just take the tail for what we need
358  Vector powers = Vector::Ones(MX);
359  auto dc = get_decay();
360  for(int i=1;i<MX;i++) { // intentionally leaving powers(0) = 1 here
361  powers(i) = powf(i,-dc);
362  }
363 
364  // sum up with the memory decay
365  #pragma omp parallel for
366  for(size_t h=0;h<nhypotheses();h++) {
367  for(int di=0;di<(int)human_data.size();di++) {
368  const datum_t& d = human_data[di];
369  const Vector& v = LL->at(d.data)[h]; // get the pre-computed vector of data here
370 
371  double dl = 0.0; // the decayed likelihood value
372  for(size_t k=0;k<d.ndata;k++) {
373  dl += v(k) * powers(d.decay_index - d.decay_position->at(k)); // TODO: This could be stored as a vector -- might be faster w/o loop?
374  }
375 
376  // #pragma may not be needed?
377  #pragma omp critical
378  assert(not std::isnan(dl));
379  (*decayedLikelihood)(h,di) = dl;
380  }
381  }
382  }
383 
390  virtual void recompute_P(std::vector<HYP>& hypotheses, const data_t& human_data) = 0;
391 
399  virtual std::map<typename HYP::output_t, double> compute_model_predictions(const data_t& human_data, const size_t i, const Matrix& hposterior) const = 0;
400 
401 
402  virtual const HYP& computeMAP( const size_t di, const Matrix& hposterior) const {
403  // compute the MAP hypothesis at a given data amount
404  int best_idx = 0;
405  double best_score = -infinity;
406 
407  for(int h=0;h<hposterior.rows();h++) {
408  if(hposterior(h,di) > best_score) {
409  best_idx = h;
410  best_score = hposterior(h,di);
411  }
412  }
413  return std::ref(which_hypotheses->at(best_idx));
414  }
415 
422  virtual double human_chance_lp(const typename datum_t::output_t& r, const datum_t& hd) const {
423  return log(hd.chance);
424  }
425 
426 
427  virtual double compute_prior() override {
428  return this->prior = logA.compute_prior() +
429  alpha.compute_prior() +
430 // llt.compute_prior() +
431  //pt.compute_prior() +
432  decay.compute_prior();
433  }
434 
441 
442  // the model's posterior
443  // do we need to normalize the prior here? The answer is no -- because its just a constant
444  // and that will get normalized away in posterior
445  const auto hprior = this->hypothesis_prior();
446  const auto hlikelihood = (*decayedLikelihood );
447  Matrix hposterior = hlikelihood.colwise() + hprior;
448  //Matrix hposterior = (*decayedLikelihood).colwise() + hprior;
449 
450  // now normalize it and convert to probabilities
451  #pragma omp parallel for
452  for(int di=0;di<hposterior.cols();di++) {
453 
454  // here we normalize and convert it to *probability* space
455  const Vector& v = hposterior.col(di);
456  const Vector lv = lognormalize(v).array().exp();
457  // wow it's a real mystery that the below does not work
458  // (it compiles, but gives weirdo answers...)
459  // const auto& lv = lognormalize(hposterior.col(di)).array().exp();
460 
461  #pragma omp critical
462  hposterior.col(di) = lv;
463  }
464 
465  return hposterior;
466  }
467 
474  virtual double compute_likelihood(const data_t& human_data, const double breakout=-infinity) override {
475 
476  // recompute our likelihood if its the wrong size or not using this data
477  if(which_data != std::addressof(human_data)) {
478  CERR "*** You are computing likelihood on a dataset that the BaseGrammarHypothesis was not constructed with." ENDL
479  CERR " You must call set_hypotheses_and_data before calling this likelihood, but note that when you" ENDL
480  CERR " do that, it will need to recompute everything (which might take a while)." ENDL;
481  assert(false);
482  }
483 
484  // Ok this needs a little explanation. If we have overwritten the types, then we can get compilation
485  // errors below because for instance r.first won't be of the right type to index into model_predictions.
486  // So this line catches that and removes this chunk of code at compile time if we have removed
487  // those types. In its place, we add a runtime assertion fail, meaning you should have overwritten
488  // compute_likelihood if you change these types
489  if constexpr(std::is_same<std::vector<std::pair<typename HYP::output_t,size_t>>, typename datum_t::response_t>::value) {
490 
491  const Matrix hposterior = this->compute_normalized_posterior();
492 
493  this->likelihood = 0.0; // for all the human data
494 
495  // precompute these so we don't keep doing it
496  const auto log_alpha = log(get_alpha());
497  const auto log_1malpha = log(1.0-get_alpha());
498 
499  #pragma omp parallel for
500  for(size_t i=0;i<human_data.size();i++) {
501 
502  const auto model_predictions = compute_model_predictions(human_data, i, hposterior);
503  //print(str(model_predictions));
504 
505  double ll = 0.0; // the likelihood here
506  auto& di = human_data[i];
507  for(const auto& [r,cnt] : di.responses) {
508  ll += cnt * logplusexp_full( log_1malpha + human_chance_lp(r,di),
509  log_alpha + log(get(model_predictions, r, 0.0)));
510  }
511 
512  #pragma omp atomic
513  this->likelihood += ll;
514  }
515 
516  return this->likelihood;
517  }
518  else {
519  assert(false && "*** If you use BaseGrammarHypothesis with non-default types, you need to overwrite compute_likelihood so it does the right thing.");
520  }
521 
522  }
523 
524  [[nodiscard]] virtual this_t restart() const override {
525  this_t out(*static_cast<const this_t*>(this)); // copy
526 
527  out.logA = logA.restart();
528 
529  out.set_alpha(alpha.restart());
530  out.set_decay(decay.restart());
531 // out.llt = llt.restart();
532  //out.pt = pt.restart();
533 
534  return out;
535  }
536 
545  [[nodiscard]] virtual std::optional<std::pair<this_t,double>> propose() const override {
546 
547  // TODO: Can probably speed this up by not making the copy if the proposal fails
548 
549  // make a copy
550  this_t out(*static_cast<const this_t*>(this));
551 
552  if(flat_prior or flip(0.15)){ // if flat, we NEVER propose to logA
553 
554  double myfb = 0.0;
555  auto which = random_nonempty_subset(2, 0.25);
556 
557  if(which.at(0)) {
558  auto p = alpha.propose();
559  if(not p) return {}; // Hmm can change this -- failed proposals can just be skipped here
560  auto [ v, fb ] = p.value();
561  out.set_alpha(v);
562  myfb += fb;
563  }
564 
565  if(which.at(1)) {
566  auto p = decay.propose();
567  if(not p) return {};
568  auto [ v, fb ] = p.value();
569  out.set_decay(v);
570  myfb += fb;
571  }
572 
573  return std::make_pair(out, myfb);
574  }
575  else {
576  auto p = logA.propose();
577  if(not p) return {};
578  auto [ v, fb ] = p.value();
579  out.logA = v;
580  return std::make_pair(out, fb);
581  }
582  }
589  virtual Vector hypothesis_prior() const {
590 
591  if(flat_prior) {
592  return Vector::Zero(C->rows());
593  }
594 
595  // We might want this version, but actually if we normalize, I think
596  // that the prior then becomes underdetermined because we can scale
597  // everything by a constant; otoh without this it isn't normalized,
598  // which is probably fine
599 // return lognormalize( (*C) * (-logA.value) / pt.get() );
600 
601  // The unnormalized version -- note that pt here also lets us scale to possibly weird
602  // value.
603  //return (*C) * (-logA.value) / pt.get();
604 
605  return (*C) * (-logA.value);
606 
607  // One alternative is to have "pt" be the amount of heldout mass?
608  //return lognormalize( (*C) * (-logA.value) - pt.get() );
609 
610 
611  // This version does the rational-rule thing and requires that logA store the log of the A values
612  // that ends up giving kinda crazy values. NOTE: This version also constrains each NT to sum to 1,
613  // which our general version below does not.
614 
615  // Vector out(nhypotheses()); // one for each hypothesis
616 
617  // get the marginal probability of the counts via dirichlet-multinomial
618  //Vector allA = logA.value.array().exp(); // translate [-inf,inf] into [0,inf]
619 
620 // #pragma omp parallel for
621 // for(auto i=0;i<myC.rows();i++) {
622 //
623 // double lp = 0.0;
624 // size_t offset = 0; //
625 // for(size_t nt=0;nt<grammar->count_nonterminals();nt++) { // each nonterminal in the grammar is a DM
626 // size_t nrules = grammar->count_rules( (nonterminal_t) nt);
627 // if(nrules > 1) { // don't need to do anything if only one rule (but must incremnet offset)
628 // Vector a = eigenslice(allA,offset,nrules); // TODO: seqN doesn't seem to work with this eigen version
629 // Vector c = eigenslice(myC.row(i),offset,nrules);
630 //
631 // // This version does RR marginalization and requires us to use logA.value.array().exp() above.
632 // double n = a.sum(); assert(n > 0.0);
633 // double c0 = c.sum();
634 // if(c0 != 0.0) { // TODO: Check this...
635 // // NOTE: std::lgamma here is not thread safe, so we use mylgamma defined in Numerics
636 // lp += mylgamma(n+1) + mylgamma(c0) - mylgamma(n+c0)
637 // + (c.array() + a.array()).array().lgamma().sum()
638 // - (c.array()+1).array().lgamma().sum()
639 // - a.array().lgamma().sum();
640 // }
641 // }
642 // offset += nrules;
643 // }
644 //
645 // #pragma omp critical
646 // out(i) = lp / temp; // NOTE: we use the temp before we lognormalize
647 // }
648 
649  }
650 
651  virtual bool operator==(const this_t& h) const override {
652  return (C == h.C and LL == h.LL and P == h.P) and
653  (logA == h.logA) and
654  (alpha == h.alpha) and
655  (decay == h.decay);
656  }
657 
664  virtual std::string string(std::string prefix="") const override {
665  // For now we just provide partial information
666  //return "GrammarHypothesis["+str(this->posterior) + params.string() + ", " + logA.string() + "]";
667  std::string out = "";
668 
669  // the -1 here is just to contrast with the nt printed below
670  out += prefix + "-1\tposterior.score" +"\t"+ str(this->posterior) + "\n";
671  out += prefix + "-1\tparameter.prior" +"\t"+ str(this->prior) + "\n";
672  out += prefix + "-1\thuman.likelihood" +"\t"+ str(this->likelihood) + "\n";
673  out += prefix + "-1\talpha" +"\t"+ str(get_alpha()) + "\n";
674 // out += prefix + "-1\tllt" +"\t"+ str(get_llt()) + "\n";
675 // out += prefix + "-1\tpt" +"\t"+ str(pt.get()) + "\n";
676  out += prefix + "-1\tdecay" +"\t"+ str(get_decay()) + "\n";
677 
678  // now add the grammar operations
679  size_t xi=0;
680  for(auto& r : *grammar) {
681  if(logA.can_propose[xi]) { // we'll skip the things we set as effectively constants (but still increment xi)
682  std::string rs = r.format;
683  rs = std::regex_replace(rs, std::regex("\\%s"), "X");
684  out += prefix + str(r.nt) + "\t" + QQ(rs) +"\t" + str(flat_prior ? 0.0 : logA(xi)) + "\n"; // unlogged here
685  }
686  xi++;
687  }
688  out.erase(out.size()-1,1); // delete the final newline
689 
690  return out;
691  }
692 
697  virtual void show(std::string prefix="") override {
698  print(string(prefix));
699  }
700 
701  virtual size_t hash() const override {
702  size_t output = logA.hash();
703  hash_combine(output, alpha.hash(), decay.hash());
704  return output;
705  }
706 
707  virtual std::string serialize() const override { throw NotImplementedError();}
708  static this_t deserialize(const std::string& s) { throw NotImplementedError(); }
709 
710 };
std::vector< bool > random_nonempty_subset(const size_t n, const double p)
Returns a random nonempty subset of n elements, as a vector<bool> of length n with trues for elements...
Definition: Random.h:220
virtual double compute_prior() override
Definition: VectorHalfNormalHypothesis.h:65
std::shared_ptr< LL_t > LL
Definition: BaseGrammarHypothesis.h:90
virtual const HYP & computeMAP(const size_t di, const Matrix &hposterior) const
Definition: BaseGrammarHypothesis.h:402
std::string QQ(const std::string &x)
Definition: Strings.h:190
virtual Matrix compute_normalized_posterior() const
This returns a matrix hposterior[h,di] giving the posterior on the h&#39;th element. NOTE: not output is ...
Definition: BaseGrammarHypothesis.h:440
double likelihood
Definition: Bayesable.h:43
float get_untransformed()
Definition: TNormalVariable.h:45
std::shared_ptr< Matrix > decayedLikelihood
Definition: BaseGrammarHypothesis.h:96
virtual void recompute_decayedLikelihood(const data_t &human_data)
Recomputes the decayed likelihood (e.g. at the given decay level, the total ll for each data point...
Definition: BaseGrammarHypothesis.h:343
virtual void recompute_LL(std::vector< HYP > &hypotheses, const data_t &human_data)
Recompute LL[h,di] a hypothesis from each hypothesis and data point to a vector of prior responses...
Definition: BaseGrammarHypothesis.h:271
virtual std::optional< std::pair< this_t, double > > propose() const override
Propose to the hypothesis. The sometimes does grammar parameters and sometimes other parameters...
Definition: BaseGrammarHypothesis.h:545
A little trick here to force bools to act like chars and have normal std::vector iterators etc...
virtual void recompute_P(std::vector< HYP > &hypotheses, const data_t &human_data)=0
Recompute the predictions for the hypotheses and data.
void copy_parameters(const BaseGrammarHypothesis &h)
Definition: BaseGrammarHypothesis.h:144
Definition: MCMCable.h:14
virtual void set_hypotheses_and_data(std::vector< HYP > &hypotheses, const data_t &human_data)
This is the primary function for setting hypothese and data on construction.
Definition: BaseGrammarHypothesis.h:172
virtual double compute_likelihood(const data_t &human_data, const double breakout=-infinity) override
This computes the likelihood of the human data.
Definition: BaseGrammarHypothesis.h:474
virtual std::string string(std::string prefix="") const override
This returns a string for this hypothesis. Defaulty, now, just in tidy format with all the parameters...
Definition: BaseGrammarHypothesis.h:664
ExponentialVariable decay
Definition: BaseGrammarHypothesis.h:79
virtual self_t restart() const override
Definition: VectorHalfNormalHypothesis.h:107
virtual void show(std::string prefix="") override
Need to override print since it will print in a different format.
Definition: BaseGrammarHypothesis.h:697
void set_alpha(const UniformVariable &a)
Definition: BaseGrammarHypothesis.h:131
size_t ndata() const
Definition: BaseGrammarHypothesis.h:158
virtual size_t hash() const override
Definition: BaseGrammarHypothesis.h:701
Half-normal hypothese are bounded at zero, normal proposals wrap around.
VectorHalfNormalHypothesis logA
Definition: BaseGrammarHypothesis.h:73
virtual void set_can_propose(size_t i, bool b)
Set whether I can propose to a value in logA – this is handled by VectorNormalHypothesis Here...
Definition: BaseGrammarHypothesis.h:208
Definition: Serializable.h:4
void set_can_propose(size_t i, bool b)
Set whether we can propose to each element of b or not.
Definition: VectorHalfNormalHypothesis.h:46
Eigen::MatrixXf Matrix
Definition: EigenLib.h:18
float get_alpha() const
Definition: BaseGrammarHypothesis.h:155
double prior
Definition: Bayesable.h:42
virtual double human_chance_lp(const typename datum_t::output_t &r, const datum_t &hd) const
Get the chance probability of response r in hd (i.e. of a human response). This may typically be pret...
Definition: BaseGrammarHypothesis.h:422
bool flip(float p=0.5)
Definition: Random.h:25
Definition: TNormalVariable.h:17
std::string str(BindingTree *t)
Definition: BindingTree.h:195
double posterior
Definition: Bayesable.h:44
Definition: BaseGrammarHypothesis.h:48
virtual bool operator==(const this_t &h) const override
Definition: BaseGrammarHypothesis.h:651
void set_untransformed(const T v)
Definition: TNormalVariable.h:38
virtual size_t nhypotheses() const
A convenient function that uses C to say how many hypotheses.
Definition: BaseGrammarHypothesis.h:228
we don&#39;t need inputs/outputs for out MyHypothesis
Definition: MyHypothesis.h:6
volatile sig_atomic_t CTRL_C
T logplusexp_full(const T a, const T b)
logsumexp with no shortcuts for precision
Definition: Numerics.h:163
virtual void recompute_C(const std::vector< HYP > &hypotheses)
Computes our matrix C[h,r] of hypotheses (rows) by counts of each grammar rule. (requires that each h...
Definition: BaseGrammarHypothesis.h:235
static this_t deserialize(const std::string &s)
Definition: BaseGrammarHypothesis.h:708
void print(FIRST f, ARGS... args)
Lock output_lock and print to std:cout.
Definition: IO.h:53
virtual std::optional< std::pair< self_t, double > > propose() const override
Definition: VectorHalfNormalHypothesis.h:82
constexpr double infinity
Definition: Numerics.h:20
void set_alpha_untransformed(double v)
Definition: BaseGrammarHypothesis.h:137
A TNormalVariable encapsulates MCMC operations on a single real number with a standard normal prior...
Definition: HumanDatum.h:19
virtual std::map< typename HYP::output_t, double > compute_model_predictions(const data_t &human_data, const size_t i, const Matrix &hposterior) const =0
This uses hposterior (computed via this->compute_normalized_posterior()) to compute the model predict...
std::shared_ptr< Matrix > C
Definition: BaseGrammarHypothesis.h:89
virtual self_t restart() const override
Definition: TNormalVariable.h:76
virtual double compute_prior() override
Definition: TNormalVariable.h:56
#define CERR
Definition: IO.h:23
Args... datum_t
Definition: Bayesable.h:38
std::vector< HYP > * which_hypotheses
Definition: BaseGrammarHypothesis.h:100
std::shared_ptr< Predict_t > P
Definition: BaseGrammarHypothesis.h:92
virtual std::optional< std::pair< self_t, double > > propose() const override
Definition: TNormalVariable.h:67
Just a little wrapper to allow vectors to be handled as 2D arrays, which simplifie some stuff in Gram...
Definition: Vector2D.h:14
BaseGrammarHypothesis()
Definition: BaseGrammarHypothesis.h:103
Definition: Errors.h:7
virtual Vector hypothesis_prior() const
Compute a vector of the prior (one for each hypothesis) using the given counts matrix (hypotheses x r...
Definition: BaseGrammarHypothesis.h:589
#define ENDL
Definition: IO.h:21
A LOTHypothesis is the basic unit for doing LOT models. It store a Node as its value, and handles all of the proposing and computing priors, likelihoods, etc. It compiles this Node into a "program" which is used to make function calls, which means that the value should only be changed via LOTHypothesis::set_value.
virtual size_t hash() const override
Definition: VectorHalfNormalHypothesis.h:117
This stores a distribution from values of T to log probabilities. It is used as the return value from...
bool flat_prior
Definition: BaseGrammarHypothesis.h:70
const data_t * which_data
Definition: BaseGrammarHypothesis.h:99
float get_decay() const
Definition: BaseGrammarHypothesis.h:156
std::vector< Args... > data_t
Definition: Bayesable.h:39
virtual this_t restart() const override
Definition: BaseGrammarHypothesis.h:524
void set_decay_untransformed(double v)
Definition: BaseGrammarHypothesis.h:124
std::unordered_map< typename MyHumanDatum ::std::vector< MyHumanDatum > *, std::vector< Vector > > LL_t
Definition: BaseGrammarHypothesis.h:61
Distribution on half-normals. Man, it was a pain to try to make this inherit from VectorNormalHypothe...
Vector value
Definition: VectorHalfNormalHypothesis.h:24
std::vector< bool > can_propose
Definition: VectorHalfNormalHypothesis.h:28
UniformVariable alpha
Definition: BaseGrammarHypothesis.h:78
HYP::Grammar_t * grammar
Definition: BaseGrammarHypothesis.h:63
Definition: VectorHalfNormalHypothesis.h:13
static this_t sample(std::vector< HYP > &hypotheses, const data_t *human_data)
Definition: BaseGrammarHypothesis.h:161
void set_decay(const ExponentialVariable &ev)
Definition: BaseGrammarHypothesis.h:117
BaseGrammarHypothesis(std::vector< HYP > &hypotheses, const data_t *human_data)
Definition: BaseGrammarHypothesis.h:108
#define COUT
Definition: IO.h:24
void set_flat_prior(bool fp)
Definition: BaseGrammarHypothesis.h:215
void set_size(size_t n)
Definition: VectorHalfNormalHypothesis.h:56
This represents an MCMC hain on a hypothesis of type HYP. It uses HYP::propose and HYP::compute_poste...
Vector lognormalize(const Vector &v)
Definition: EigenLib.h:35
A human data series contains a list of human data points, some of which may be presented at the same ...
This class has all the information for running MCMC or MCTS in a little package. It defaultly constru...
Eigen::VectorXf Vector
Definition: EigenLib.h:17
virtual std::string serialize() const override
Definition: BaseGrammarHypothesis.h:707
float get() const
Get interfaces to the transformed variable.
Definition: TNormalVariable.h:52
virtual double compute_prior() override
Definition: BaseGrammarHypothesis.h:427
A grammar stores all of the rules associated with any kind of nonterminal and permits us to sample as...
virtual size_t hash() const override
Definition: TNormalVariable.h:87
void set(int i, double v)
Definition: VectorHalfNormalHypothesis.h:38
size_t size() const
Definition: VectorHalfNormalHypothesis.h:61