Fleet  0.0.9
Inference in the LOT
Builtins.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "Numerics.h"
4 #include "IO.h"
5 #include "Errors.h"
6 #include "Primitive.h"
7 
8 // Define this because it's an ugly expression to keep typing and we might want to change all at once
9 #define BUILTIN_LAMBDA +[](typename Grammar_t::VirtualMachineState_t* vms, int arg) -> void
10 
11 namespace Builtins {
12 
13  // return a pointer to the current hypothesis being evaluated
14  template<typename Grammar_t, typename HYP>
16 
17  assert(vms->program.loader != nullptr);
18 
19  // We access self via the proram.loader, so pay attention
20  // to that when we call recursive lexica and stuff
21  vms->template push<HYP*>(dynamic_cast<HYP*>(vms->program.loader));
22  });
23 
24 
25  template<typename Grammar_t>
27  assert(!vms->xstack.empty());
28  vms->template push<typename Grammar_t::input_t>(vms->xstack.top()); // not a pop!
29  });
30 
31  template<typename Grammar_t>
33 
34  // process the short circuitF
35  bool b = vms->template getpop<bool>(); // bool has already evaluated
36 
37  if(!b) {
38  vms->program.popn(arg); // pop off the other branch
39  vms->template push<bool>(false); // entire and must be false
40  }
41  else {
42  // else our value is just the other value -- true when its true and false when its false
43  }
44  });
45 
46  template<typename Grammar_t>
48 
49  // process the short circuit
50  bool b = vms->template getpop<bool>(); // bool has already evaluated
51 
52  if(b) {
53  vms->program.popn(arg); // pop off the other branch
54  vms->template push<bool>(true);
55  }
56  else {
57  // else our value is just the other value -- true when its true and false when its false
58  }
59  });
60 
61  template<typename Grammar_t>
63  vms->push(not vms->template getpop<bool>());
64  });
65 
66 
67  template<typename Grammar_t>
69  bool x = vms->template getpop<bool>();
70  bool y = vms->template getpop<bool>();
71  vms->template push<bool>( (not x) or y);
72  });
73 
74 
75  template<typename Grammar_t>
77  bool x = vms->template getpop<bool>();
78  bool y = vms->template getpop<bool>();
79  vms->template push<bool>( x==y );
80  });
81 
82 
83  template<typename Grammar_t, typename T>
85  // Op::If has to short circuit and skip (pop some of the stack)
86  bool b = vms->template getpop<bool>(); // bool has already evaluted
87 
88  // now ops must skip the xbranch
89  if(!b) vms->program.popn(arg);
90  else {}; // do nothing, we pass through and then get to the jump we placed at the end of the x branch
91  });
92 
93  template<typename Grammar_t>
95  vms->program.popn(arg);
96  });
97 
98  template<typename Grammar_t>
100  vms->xstack.pop();
101  });
102 
103  template<typename Grammar_t>
105  assert(vms->pool != nullptr);
106 
107  // push both routes onto the stack
108  vms->pool->copy_increment_push(vms, true, -LOG2);
109  bool b = vms->pool->increment_push(vms, false, -LOG2);
110 
111  // TODO: This is clumsy, ugly mechanism -- need to re-do
112 
113  // since we pushed this back onto the queue (via increment_push), we need to tell the
114  // pool not to delete this, so we send back this special signal
115  if(b) { // theoutcome of increment_push decides whether I am deleted or not
117  }
118  else {
119  vms->status = vmstatus_t::RANDOM_CHOICE;
120  }
121  });
122 
123  template<typename Grammar_t>
125  assert(vms->pool != nullptr);
126 
127  // get the coin weight
128  double p = vms->template getpop<double>();
129 
130  // some checking
131  if(std::isnan(p)) { p = 0.0; } // treat nans as 0s
132  if(p > 1.0 or p < 0.0) {
133  print("*** Error, received p not in [0,1]:", p);
134  assert(false);
135  }
136 
137  // push both routes onto the stack
138  vms->pool->copy_increment_push(vms, true, log(p));
139  bool b = vms->pool->increment_push(vms, false, log(1.0-p));
140 
141  // TODO: This is clumsy, ugly mechanism -- need to re-do
142 
143  // since we pushed this back onto the queue (via increment_push), we need to tell the
144  // pool not to delete this, so we send back this special signal
145  if(b) { // theoutcome of increment_push decides whether I am deleted or not
147  }
148  else {
149  vms->status = vmstatus_t::RANDOM_CHOICE;
150  }
151  });
152 
153 
154  // This is a version of FlipP that doesn't complain if p>1 or p<0 -- it
155  // just sets them to those values
156  template<typename Grammar_t>
158  assert(vms->pool != nullptr);
159 
160  // get the coin weight
161  double p = vms->template getpop<double>();
162 
163  // some checking
164  if(std::isnan(p)) p = 0.0; // treat nans as 0s
165  else if(p > 1.0) p = 1.0;
166  else if(p < 0.0) p = 0.0;
167 
168  // push both routes onto the stack
169  vms->pool->copy_increment_push(vms, true, log(p));
170  bool b = vms->pool->increment_push(vms, false, log(1.0-p));
171 
172  // TODO: This is clumsy, ugly mechanism -- need to re-do
173 
174  // since we pushed this back onto the queue (via increment_push), we need to tell the
175  // pool not to delete this, so we send back this special signal
176  if(b) { // theoutcome of increment_push decides whether I am deleted or not
178  }
179  else {
180  vms->status = vmstatus_t::RANDOM_CHOICE;
181  }
182  });
183 
184  template<typename Grammar_t, typename t, typename T=std::set<t>>
186 
187  // implement sampling from the set.
188  // to do this, we read the set and then push all the alternatives onto the stack
189  auto s = vms->template getpop<T>();
190 
191  // One useful optimization here is that sometimes that set only has one element. So first we check that, and if so we don't need to do anything
192  // also this is especially convenient because we only have one element to pop
193  if(s.size() == 1) {
194  auto v = std::move(*s.begin());
195  vms->template push<t>(std::move(v));
196  }
197  else {
198  // else there is more than one, so we have to copy the stack and increment the lp etc for each
199  // NOTE: The function could just be this latter branch, but that's much slower because it copies vms
200  // even for single stack elements
201 
202  // now just push on each, along with their probability
203  // which is here decided to be uniform.
204  const double lp = -log(s.size());
205  for(const auto& x : s) {
206  bool b = vms->pool->copy_increment_push(vms,x,lp);
207  if(not b) break; // we can break since all of these have the same lp -- if we don't add one, we won't add any!
208  }
209 
210  vms->status = vmstatus_t::RANDOM_CHOICE; // we don't continue with this context
211  }
212  });
213 
214  template<typename T, typename Grammar_t, size_t MX>
216  // sample 0,1,2,3, ... <first argument>-1
217 
218  const auto mx = vms->template getpop<T>();
219  if(mx >= MX) throw VMSRuntimeError(); // MX stops us from having stupidly high values
220 
221  const double lp = -log(mx);
222  for(T i=0;i<mx;i++) {
223  bool b = vms->pool->copy_increment_push(vms,i,lp);
224  if(not b) break; // we can break since all of these have the same lp -- if we don't add one, we won't add any!
225  }
226  vms->status = vmstatus_t::RANDOM_CHOICE; // we don't continue with this context
227  });
228 
229 
230 
231  template<typename T, typename Grammar_t, size_t MX>
233  // sample 0,1,2,3, ... <first argument>-1
234 
235  const auto mx = vms->template getpop<T>();
236  if(mx >= MX) throw VMSRuntimeError(); // MX stops us from having stupidly high values
237  const auto p = vms->template getpop<double>();
238 
239  // find the normalizing constant (NOTE: not in log space for now)
240  double z = 0.0;
241  for(size_t i=0;i<mx;i++)
242  z += pow(p,i)*(1-p);
243  const double lz = log(z);
244 
245  for(T i=0;i<mx;i++) {
246  const double lp = i * log(p) + log(1-p) - lz;
247  bool b = vms->pool->copy_increment_push(vms,i,lp);
248  if(not b) break; // we can break since all of these have the same lp -- if we don't add one, we won't add any!
249  }
250  vms->status = vmstatus_t::RANDOM_CHOICE; // we don't continue with this context
251  });
252 
253  template<typename Grammar_t, typename key_t, typename output_t=typename Grammar_t::output_t>
255  auto memindex = vms->template memstack<key_t>().top(); vms->template memstack<key_t>().pop();
256  if(vms->template mem<key_t>().count(memindex)==0) { // you might actually have already placed mem in crazy recursive situations, so don't overwrite if you have
257  vms->template mem<key_t>()[memindex] = vms->template gettop<output_t>(); // what I should memoize should be on top here, but don't remove because we also return it
258  }
259  });
260 
261 
262  template<typename Grammar_t>
264  });
265 
266  template<typename Grammar_t>
268  assert(false);
269  });
270 
271  template<typename Grammar_t,
272  typename input_t=typename Grammar_t::input_t,
273  typename output_t=typename Grammar_t::output_t>
275 
276  assert(vms->program.loader != nullptr);
277 
278  if(vms->recursion_depth++ > vms->MAX_RECURSE) { // there is one of these for each recurse
279  throw VMSRuntimeError();
280  }
281 
282  // if we get here, then we have processed our arguments and they are stored in the input_t stack.
283  // so we must move them to the x stack (where there are accessible by op_X)
284  auto mynewx = vms->template getpop<input_t>();
285  vms->xstack.push(std::move(mynewx));
286  vms->program.push(Builtins::PopX<Grammar_t>.makeInstruction()); // we have to remember to remove X once the other program evaluates, *after* everything has evaluated
287 
288  // push this program
289  // but we give i.arg so that we can pass factorized recursed
290  // in argument if we want to
291  vms->program.loader->push_program(vms->program);
292 
293  // after execution is done, the result will be pushed onto output_t
294  // which is what gets returned when we are all done
295 
296  });
297 
298 
299 
300 
301 
302  template<typename Grammar_t,
303  typename input_t=typename Grammar_t::input_t,
304  typename output_t=typename Grammar_t::output_t>
306  assert(not vms->template stack<input_t>().empty());
307 
308  // if the size of the top is zero, we return output{}
309  if(vms->template stack<input_t>().top().size() == 0) {
310  vms->template getpop<input_t>(); // this would have been the argument
311  vms->template push<output_t>(output_t{}); //push default (null) return
312  }
313  else {
314  Recurse<Grammar_t>.call(vms,arg);
315  }
316  });
317 
318 
319 
320  template<typename Grammar_t,
321  typename input_t=typename Grammar_t::input_t,
322  typename output_t=typename Grammar_t::output_t>
323  Primitive<output_t,input_t> MemRecurse(Op::MemRecurse, BUILTIN_LAMBDA { // note the order switch -- that's right!
324  assert(vms->program.loader != nullptr);
325 
326  using mykey_t = short; // this is just the default type used for non-lex recursion
327 
328  if(vms->recursion_depth++ > vms->MAX_RECURSE) { // there is one of these for each recurse
329  throw VMSRuntimeError();
330  }
331 
332  auto x = vms->template getpop<input_t>(); // get the argument
333  auto memindex = std::make_pair(arg,x);
334 
335  if(vms->template mem<mykey_t>().count(memindex)){
336  vms->push(vms->template mem<mykey_t>()[memindex]); // hmm probably should not be a move?
337  }
338  else {
339  vms->xstack.push(x);
340  vms->program.push(Builtins::PopX<Grammar_t>.makeInstruction());
341 
342  vms->template memstack<mykey_t>().push(memindex); // popped off by op_MEM
343  vms->program.push(Builtins::Mem<Grammar_t,mykey_t,output_t>.makeInstruction());
344 
345  vms->program.loader->push_program(vms->program); // this leaves the answer on top
346  }
347  });
348 
349 
350  template<typename Grammar_t,
351  typename input_t=typename Grammar_t::input_t,
352  typename output_t=typename Grammar_t::output_t>
354  assert(not vms->template stack<input_t>().empty());
355 
356  // if the size of the top is zero, we return output{}
357  if(vms->template stack<input_t>().top().size() == 0) {
358  vms->template getpop<input_t>(); // this would have been the argument
359  vms->template push<output_t>(output_t{}); //push default (null) return
360  }
361  else {
362  MemRecurse<Grammar_t>.call(vms, arg);
363  }
364  });
365 
371  template<typename Grammar_t,
372  typename input_t=typename Grammar_t::input_t,
373  typename output_t=typename Grammar_t::output_t>
375 
376  assert(vms->program.loader != nullptr);
377 
378  if(vms->recursion_depth++ > vms->MAX_RECURSE) { // there is one of these for each recurse
379  auto mynewx = vms->template getpop<input_t>();
380  vms->template push<output_t>(output_t{});
381  }
382  else {
383 
384  // if we get here, then we have processed our arguments and they are stored in the input_t stack.
385  // so we must move them to the x stack (where there are accessible by op_X)
386  auto mynewx = vms->template getpop<input_t>();
387  vms->xstack.push(std::move(mynewx));
388  vms->program.push(Builtins::PopX<Grammar_t>.makeInstruction()); // we have to remember to remove X once the other program evaluates, *after* everything has evaluated
389 
390  // push this program
391  // but we give i.arg so that we can pass factorized recursed
392  // in argument if we want to
393  vms->program.loader->push_program(vms->program);
394 
395  // after execution is done, the result will be pushed onto output_t
396  // which is what gets returned when we are all done
397  }
398  });
399 
400 
401 
402  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
403 
404 
405 
406  template<typename Grammar_t,
407  typename key_t,
408  typename input_t=typename Grammar_t::input_t,
409  typename output_t=typename Grammar_t::output_t>
411 
412  assert(vms->program.loader != nullptr);
413 
414  if(vms->recursion_depth++ > vms->MAX_RECURSE) { // there is one of these for each recurse
415  throw VMSRuntimeError();
416  }
417 
418  // the key here is the index into the lexicon
419  // NOTE: this is popped before the argument (which is relevant when they are the same type)
420  auto key = vms->template getpop<key_t>();
421 
422  // if we get here, then we have processed our arguments and they are stored in the input_t stack.
423  // so we must move them to the x stack (where there are accessible by op_X)
424  auto mynewx = vms->template getpop<input_t>();
425  vms->xstack.push(std::move(mynewx));
426  vms->program.push(Builtins::PopX<Grammar_t>.makeInstruction()); // we have to remember to remove X once the other program evaluates, *after* everything has evaluated
427 
428  // push this program
429  // but we give i.arg so that we can pass factorized recursed
430  // in argument if we want to
431  vms->program.loader->push_program(vms->program,key);
432  });
433 
434 
435  template<typename Grammar_t,
436  typename key_t,
437  typename input_t=typename Grammar_t::input_t,
438  typename output_t=typename Grammar_t::output_t>
440  assert(not vms->template stack<input_t>().empty());
441  assert(vms->program.loader != nullptr);
442 
443  // if the size of the top is zero, we return output{}
444  if(vms->template stack<input_t>().top().size() == 0) {
445  vms->template getpop<key_t>();
446  vms->template getpop<input_t>(); // this would have been the argument
447 
448  vms->template push<output_t>(output_t{}); //push default (null) return
449  }
450  else {
451  LexiconRecurse<Grammar_t,key_t>.call(vms,arg); // NOTE: Key is popped in this call
452  }
453 
454  });
455 
456 
457  template<typename Grammar_t,
458  typename key_t,
459  typename input_t=typename Grammar_t::input_t,
460  typename output_t=typename Grammar_t::output_t>
462  assert(vms->program.loader != nullptr);
463 
464  if(vms->recursion_depth++ > vms->MAX_RECURSE) { // there is one of these for each recurse
465  throw VMSRuntimeError();
466  }
467 
468  auto key = vms->template getpop<key_t>();
469  auto x = vms->template getpop<input_t>(); // get the argument
470 
471  auto memindex = std::make_pair(key,x);
472 
473  if(vms->template mem<key_t>().count(memindex)){
474  vms->push(vms->template mem<key_t>()[memindex]); // copy over here
475  }
476  else {
477  vms->xstack.push(x);
478  vms->program.push(Builtins::PopX<Grammar_t>.makeInstruction());
479 
480  vms->template memstack<key_t>().push(memindex); // popped off by op_MEM
481  vms->program.push(Builtins::Mem<Grammar_t,key_t,output_t>.makeInstruction());
482 
483  vms->program.loader->push_program(vms->program,key); // this leaves the answer on top
484  }
485  });
486 
487 
488  template<typename Grammar_t,
489  typename key_t,
490  typename input_t=typename Grammar_t::input_t,
491  typename output_t=typename Grammar_t::output_t>
493  assert(not vms->template stack<input_t>().empty());
494  assert(vms->program.loader != nullptr);
495 
496  // if the size of the top is zero, we return output{}
497  if(vms->template stack<input_t>().top().size() == 0) {
498 
499  vms->template getpop<key_t>();
500  vms->template getpop<input_t>(); // this would have been the argument
501 
502  vms->template push<output_t>(output_t{}); //push default (null) return
503  }
504  else {
505  LexiconMemRecurse<Grammar_t,key_t>.call(vms,arg);
506  }
507 
508  });
509 }
510 
Primitive< output_t, key_t, input_t > LexiconSafeMemRecurse(Op::LexiconSafeMemRecurse, BUILTIN_LAMBDA { assert(not vms->template stack< input_t >().empty());assert(vms->program.loader !=nullptr);if(vms->template stack< input_t >().top().size()==0) { vms->template getpop< key_t >();vms->template getpop< input_t >();vms->template push< output_t >(output_t{});} else { LexiconMemRecurse< Grammar_t, key_t >.call(vms, arg);} })
Definition: VMSRuntimeError.h:13
Primitive< output_t, input_t > MemRecurse(Op::MemRecurse, BUILTIN_LAMBDA { assert(vms->program.loader !=nullptr);using mykey_t=short;if(vms->recursion_depth++> vms->MAX_RECURSE) { throw VMSRuntimeError();} auto x=vms->template getpop< input_t >();auto memindex=std::make_pair(arg, x);if(vms->template mem< mykey_t >().count(memindex)){ vms->push(vms->template mem< mykey_t >()[memindex]);} else { vms->xstack.push(x);vms->program.push(Builtins::PopX< Grammar_t >.makeInstruction());vms->template memstack< mykey_t >().push(memindex);vms->program.push(Builtins::Mem< Grammar_t, mykey_t, output_t >.makeInstruction());vms->program.loader->push_program(vms->program);} })
Primitive< output_t, key_t, input_t > LexiconMemRecurse(Op::LexiconMemRecurse, BUILTIN_LAMBDA { assert(vms->program.loader !=nullptr);if(vms->recursion_depth++> vms->MAX_RECURSE) { throw VMSRuntimeError();} auto key=vms->template getpop< key_t >();auto x=vms->template getpop< input_t >();auto memindex=std::make_pair(key, x);if(vms->template mem< key_t >().count(memindex)){ vms->push(vms->template mem< key_t >()[memindex]);} else { vms->xstack.push(x);vms->program.push(Builtins::PopX< Grammar_t >.makeInstruction());vms->template memstack< key_t >().push(memindex);vms->program.push(Builtins::Mem< Grammar_t, key_t, output_t >.makeInstruction());vms->program.loader->push_program(vms->program, key);} })
Primitive< bool, bool, bool > And(Op::And, BUILTIN_LAMBDA { bool b=vms->template getpop< bool >();if(!b) { vms->program.popn(arg);vms->template push< bool >(false);} else { } })
Primitive< bool, bool > Not(Op::Not, BUILTIN_LAMBDA { vms->push(not vms->template getpop< bool >());})
Primitive< output_t, key_t, input_t > LexiconSafeRecurse(Op::LexiconSafeRecurse, BUILTIN_LAMBDA { assert(not vms->template stack< input_t >().empty());assert(vms->program.loader !=nullptr);if(vms->template stack< input_t >().top().size()==0) { vms->template getpop< key_t >();vms->template getpop< input_t >();vms->template push< output_t >(output_t{});} else { LexiconRecurse< Grammar_t, key_t >.call(vms, arg);} })
Definition: Primitive.h:13
Primitive< HYP * > selfptr(Op::selfptr, BUILTIN_LAMBDA { assert(vms->program.loader !=nullptr);vms->template push< HYP *>(dynamic_cast< HYP *>(vms->program.loader));})
Primitive Mem(Op::Mem, BUILTIN_LAMBDA { auto memindex=vms->template memstack< key_t >().top();vms->template memstack< key_t >().pop();if(vms->template mem< key_t >().count(memindex)==0) { vms->template mem< key_t >()[memindex]=vms->template gettop< output_t >();} })
Primitive< T, bool, T, T > If(Op::If, BUILTIN_LAMBDA { bool b=vms->template getpop< bool >();if(!b) vms->program.popn(arg);else {};})
Primitive< t, T > Sample(Op::Sample, BUILTIN_LAMBDA { auto s=vms->template getpop< T >();if(s.size()==1) { auto v=std::move(*s.begin());vms->template push< t >(std::move(v));} else { const double lp=-log(s.size());for(const auto &x :s) { bool b=vms->pool->copy_increment_push(vms, x, lp);if(not b) break;} vms->status=vmstatus_t::RANDOM_CHOICE;} })
Primitive< bool, bool, bool > Or(Op::Or, BUILTIN_LAMBDA { bool b=vms->template getpop< bool >();if(b) { vms->program.popn(arg);vms->template push< bool >(true);} else { } })
Primitive NoOp(Op::NoOp, BUILTIN_LAMBDA { })
Primitive< bool > Flip(Op::Flip, BUILTIN_LAMBDA { assert(vms->pool !=nullptr);vms->pool->copy_increment_push(vms, true, -LOG2);bool b=vms->pool->increment_push(vms, false, -LOG2);if(b) { vms->status=vmstatus_t::RANDOM_CHOICE_NO_DELETE;} else { vms->status=vmstatus_t::RANDOM_CHOICE;} })
void print(FIRST f, ARGS... args)
Lock output_lock and print to std:cout.
Definition: IO.h:53
Primitive< bool, bool, bool > Iff(Op::Iff, BUILTIN_LAMBDA { bool x=vms->template getpop< bool >();bool y=vms->template getpop< bool >();vms->template push< bool >(x==y);})
Primitive< bool, double > SafeFlipP(Op::SafeFlipP, BUILTIN_LAMBDA { assert(vms->pool !=nullptr);double p=vms->template getpop< double >();if(std::isnan(p)) p=0.0;else if(p > 1.0) p=1.0;else if(p< 0.0) p=0.0;vms->pool->copy_increment_push(vms, true, log(p));bool b=vms->pool->increment_push(vms, false, log(1.0-p));if(b) { vms->status=vmstatus_t::RANDOM_CHOICE_NO_DELETE;} else { vms->status=vmstatus_t::RANDOM_CHOICE;} })
Primitive< T, T, double > Sample_int_geom(Op::Sample, BUILTIN_LAMBDA { const auto mx=vms->template getpop< T >();if(mx >=MX) throw VMSRuntimeError();const auto p=vms->template getpop< double >();double z=0.0;for(size_t i=0;i< mx;i++) z+=pow(p, i) *(1-p);const double lz=log(z);for(T i=0;i< mx;i++) { const double lp=i *log(p)+log(1-p) - lz;bool b=vms->pool->copy_increment_push(vms, i, lp);if(not b) break;} vms->status=vmstatus_t::RANDOM_CHOICE;})
const double LOG2
Definition: Numerics.h:18
Primitive Jmp(Op::Jmp, BUILTIN_LAMBDA { vms->program.popn(arg);})
Definition: Builtins.h:11
Primitive< output_t, input_t > SafeMemRecurse(Op::SafeMemRecurse, BUILTIN_LAMBDA { assert(not vms->template stack< input_t >().empty());if(vms->template stack< input_t >().top().size()==0) { vms->template getpop< input_t >();vms->template push< output_t >(output_t{});} else { MemRecurse< Grammar_t >.call(vms, arg);} })
Primitive< typename Grammar_t::input_t > X(Op::X, BUILTIN_LAMBDA { assert(!vms->xstack.empty());vms->template push< typename Grammar_t::input_t >(vms->xstack.top());})
#define BUILTIN_LAMBDA
Definition: Builtins.h:9
Primitive UnusedNoOp(Op::NoOp, BUILTIN_LAMBDA { assert(false);})
Primitive< output_t, input_t > RecurseEmptyOnDepthException(Op::Recurse, BUILTIN_LAMBDA { assert(vms->program.loader !=nullptr);if(vms->recursion_depth++> vms->MAX_RECURSE) { auto mynewx=vms->template getpop< input_t >();vms->template push< output_t >(output_t{});} else { auto mynewx=vms->template getpop< input_t >();vms->xstack.push(std::move(mynewx));vms->program.push(Builtins::PopX< Grammar_t >.makeInstruction());vms->program.loader->push_program(vms->program);} })
This is a kind of recursion that, when it reaches the max recursion depth, returns empty string...
Primitive< output_t, input_t > Recurse(Op::Recurse, BUILTIN_LAMBDA { assert(vms->program.loader !=nullptr);if(vms->recursion_depth++> vms->MAX_RECURSE) { throw VMSRuntimeError();} auto mynewx=vms->template getpop< input_t >();vms->xstack.push(std::move(mynewx));vms->program.push(Builtins::PopX< Grammar_t >.makeInstruction());vms->program.loader->push_program(vms->program);})
Primitive< output_t, input_t > SafeRecurse(Op::SafeRecurse, BUILTIN_LAMBDA { assert(not vms->template stack< input_t >().empty());if(vms->template stack< input_t >().top().size()==0) { vms->template getpop< input_t >();vms->template push< output_t >(output_t{});} else { Recurse< Grammar_t >.call(vms, arg);} })
Primitive< T, T > Sample_int(Op::Sample, BUILTIN_LAMBDA { const auto mx=vms->template getpop< T >();if(mx >=MX) throw VMSRuntimeError();const double lp=-log(mx);for(T i=0;i< mx;i++) { bool b=vms->pool->copy_increment_push(vms, i, lp);if(not b) break;} vms->status=vmstatus_t::RANDOM_CHOICE;})
Primitive< bool, double > FlipP(Op::FlipP, BUILTIN_LAMBDA { assert(vms->pool !=nullptr);double p=vms->template getpop< double >();if(std::isnan(p)) { p=0.0;} if(p > 1.0 or p< 0.0) { print("*** Error, received p not in [0,1]:", p);assert(false);} vms->pool->copy_increment_push(vms, true, log(p));bool b=vms->pool->increment_push(vms, false, log(1.0-p));if(b) { vms->status=vmstatus_t::RANDOM_CHOICE_NO_DELETE;} else { vms->status=vmstatus_t::RANDOM_CHOICE;} })
Primitive PopX(Op::PopX, BUILTIN_LAMBDA { vms->xstack.pop();})
Primitive< output_t, key_t, input_t > LexiconRecurse(Op::LexiconRecurse, BUILTIN_LAMBDA { assert(vms->program.loader !=nullptr);if(vms->recursion_depth++> vms->MAX_RECURSE) { throw VMSRuntimeError();} auto key=vms->template getpop< key_t >();auto mynewx=vms->template getpop< input_t >();vms->xstack.push(std::move(mynewx));vms->program.push(Builtins::PopX< Grammar_t >.makeInstruction());vms->program.loader->push_program(vms->program, key);})
Primitive< bool, bool, bool > Implies(Op::Implies, BUILTIN_LAMBDA { bool x=vms->template getpop< bool >();bool y=vms->template getpop< bool >();vms->template push< bool >((not x) or y);})