persistable sclass PStack is Steppable {
settable new ProbabilisticScheduler scheduler;
settable bool verbose;
sclass NoOptionsException extends RuntimeException {}
*(VStack.Computable computable) { add(computable); }
srecord noeq ExecuteOption(IVF1 option) is VStack.Computable {
public void step(VStack stack, O subComputationResult) {
O target = stack.caller();
stack.return();
option.get(target);
}
}
class SingleStack extends VStack is IPStack, Runnable {
double probability = 1.0;
*() {}
*(VStack.Computable computable) { super(computable); }
run {
if (verbose) print("Stepping " + last(stack));
if (step() && !isEmpty()) {
if (verbose) print("Re-scheduling at " + probability + ": " + last(stack));
// re-add myself to scheduler to continue
scheduler.add(probability, this);
}
}
// give each option the probability 1/n (with n=number of options)
public void options(B function, Iterable> options) {
L> optionsList = nonNulls(options);
if (empty(optionsList))
throw new NoOptionsException;
// probability penalty according to number of options
probability = probability/l(optionsList);
// Schedule all options except first in cloned stacks
int n = l(optionsList)-1;
for (int i = 0; i < n; i++) {
new SingleStack s;
s.stack = shallowCloneElements(stack);
s.push(new ExecuteOption(optionsList.get(i)));
s.probability = probability;
scheduler.at(probability, s);
}
// Last option is executed in same stack
push(new ExecuteOption(last(optionsList));
}
// give each option its own probability
public void probabilisticOptions(B currentFrame, Iterable>> options) {
L>> optionsList = nonNulls(options);
if (empty(optionsList))
throw new NoOptionsException;
// Schedule all options except first in cloned stacks
int n = l(optionsList)-1;
for (int i = 0; i < n; i++) {
new SingleStack s;
s.stack = shallowCloneElements(stack);
var option = optionsList.get(i);
s.push(new ExecuteOption(option!));
s.probability = probability*option.probability();
scheduler.at(s.probability, s);
}
// Last option is executed in same stack
var option = last(optionsList);
probability *= option.probability();
push(new ExecuteOption(option!));
}
}
srecord noeq FollowUp(VStack.Computable computable, IVF1 onCompletion) extends PStackComputableWithStep {
// !customConstructor
*(VStack.Computable *computable, IVF1 *onCompletion) {
probability = getProbability(computable);
}
void step(IPStack stack) {
if (step == 0) {
stack.push(computable);
++step;
} else {
onCompletion.get((A) stack.subResult());
stack.return();
}
}
}
// also takes a PStackComputable
void add(VStack.Computable computable) {
scheduler.at(getProbability(computable), new SingleStack(computable));
}
// also takes a PStackComputable
void add(VStack.Computable computable, IVF1 onCompletion) {
if (onCompletion != null)
add(new FollowUp<>(computable, onCompletion));
else
add(computable);
}
public bool step() { ret scheduler.step(); }
meta-for run also as runWithStats {
public void run() { scheduler.run(); }
void run(VStack.Computable computable) { add(computable); run(); }
}
static double getProbability(VStack.Computable computable) {
ret computable cast PStackComputable ?
computable.probability : 1.0;
}
}