42 using Vec=std::vector<double>;
47 std::vector<int> nsteps;
48 Vec steps,tol,initial;
51 [[noreturn]]
static void fail(
const char* s) {
throw std::invalid_argument(s); }
52 Vec rates(
const Vec& x) {
53 Vec a=p.rates(x);
double sum=0;
54 if(a.size()!=k) fail(
"MLMC rate dimension changed");
55 for(
double v:a) {
if(!std::isfinite(v)||v<0) fail(
"MLMC rates must be finite and nonnegative on auxiliary states");
sum+=v; }
56 if(!std::isfinite(
sum)) fail(
"MLMC total rate overflow");
59 Vec observe(
const Vec& x) {
61 if(f.empty()) fail(
"Define at least one MLMC reward");
62 for(
double v:f)
if(!std::isfinite(v)) fail(
"MLMC rewards must be finite on auxiliary states");
65 double uniform() {
return std::generate_canonical<double,53>(rng); }
66 double poisson(
double mean) {
68 if(!std::isfinite(mean)||mean>std::numeric_limits<int>::max()/4.0)
69 fail(
"MLMC Poisson mean exceeds supported range; refine the grid");
70 return static_cast<double>(std::poisson_distribution<int>(mean)(rng));
72 void jump(Vec& x,std::size_t channel,
double count) {
73 for(std::size_t i=0;i<d;++i) x[i]+=p.nu[i][channel]*count;
75 Vec difference(
const Vec& x,
const Vec& c) {
76 Vec a=observe(x),b=observe(c);
77 if(a.size()!=q||b.size()!=q) fail(
"MLMC reward dimension changed");
78 for(std::size_t i=0;i<q;++i) a[i]-=b[i];
81 Vec sample(
int level) {
82 Vec x=p.x0,c=p.x0; work=0;
84 for(
int j=0;j<nsteps[0];++j) {
86 for(std::size_t r=0;r<k;++r) jump(x,r,poisson(a[r]*steps[0]));
87 work+=std::max<std::size_t>(k,1);
92 Vec ac;
double h=steps[level];
93 for(
int j=0;j<nsteps[level];++j) {
94 if(j%o.refinementFactor==0) ac=rates(c);
96 for(std::size_t r=0;r<k;++r) {
97 double shared=std::min(af[r],ac[r]),common=poisson(shared*h);
98 jump(x,r,common+poisson((af[r]-shared)*h));
99 jump(c,r,common+poisson((ac[r]-shared)*h));
101 work+=3*std::max<std::size_t>(k,1);
103 return difference(x,c);
105 double t=0,h=steps.back();
int events=0;
106 for(
int j=1;j<=nsteps.back();++j) {
107 Vec ac=rates(c);
double boundary=j*h;
109 Vec ax=rates(x),a(3*k);
double total=0;
110 for(std::size_t r=0;r<k;++r) {
111 a[r]=std::min(ax[r],ac[r]); a[k+r]=ax[r]-a[r]; a[2*k+r]=ac[r]-a[r];
112 total+=ax[r]+ac[r]-a[r];
114 work+=3*std::max<std::size_t>(k,1);
115 if(!std::isfinite(total)) fail(
"MLMC split rate overflow");
116 if(total==0) { t=boundary;
break; }
117 double dt=-std::log(std::max(std::numeric_limits<double>::min(),uniform()))/total;
118 if(t+dt>=boundary) { t=boundary;
break; }
119 if(t+dt==t) fail(
"MLMC event time cannot advance");
120 double u=uniform()*total,cs=0; std::size_t channel=0;
121 for(;channel+1<a.size();++channel) { cs+=a[channel];
if(u<cs)
break; }
122 if(channel<2*k) jump(x,channel%k,1);
123 if(channel<k||channel>=2*k) jump(c,channel%k,1);
124 for(
double v:x)
if(v<0) fail(
"MLMC exact process left the nonnegative domain");
126 if(++events>o.maxEvents) fail(
"MLMC exact correction exceeds maxEvents");
129 return difference(x,c);
131 struct Batch { Vec mean,var;
double cost; };
132 Batch batch(
int level,
int n) {
133 Batch b{Vec(q),Vec(q),0};
134 for(
int i=1;i<=n;++i) {
135 Vec y=sample(level); b.cost+=work;
136 for(
double v:y)
if(!std::isfinite(v)) fail(
"MLMC reward difference overflow");
137 if(y.size()!=q) fail(
"MLMC reward dimension changed");
138 for(std::size_t r=0;r<q;++r) {
139 double delta=y[r]-b.mean[r]; b.mean[r]+=delta/i; b.var[r]+=delta*(y[r]-b.mean[r]);
142 for(
double v:b.mean)
if(!std::isfinite(v)) fail(
"MLMC moment overflow");
143 for(
double& v:b.var) {
144 if(!std::isfinite(v)) fail(
"MLMC moment overflow");
145 v=std::max(0.0,v/(n-1));
147 b.cost=std::max(1.0,b.cost/n);
return b;
151 if(!std::isfinite(time)||time<0||o.levels<0||o.levels>20||o.baseSteps<1||o.refinementFactor<2
152 ||o.pilotPaths<2||o.minPaths<2||o.maxPaths<2||o.maxEvents<1||!(o.confidenceLevel>0&&o.confidenceLevel<1))
153 fail(
"Invalid MLMC time, hierarchy or sampling options");
155 if(d==0||p.nu.size()!=d) fail(
"Invalid MLMC state dimension");
157 for(std::size_t i=0;i<d;++i) {
158 if(!std::isfinite(p.x0[i])||p.x0[i]<0||p.x0[i]!=std::floor(p.x0[i])||p.nu[i].size()!=k)
159 fail(
"MLMC needs nonnegative integer initial counts");
160 for(
double v:p.nu[i])
if(!std::isfinite(v)||v!=std::floor(v)) fail(
"MLMC needs integer increments");
162 initial=observe(p.x0); q=initial.size(); nl=o.levels+2;
163 if(o.absTol.size()!=1&&o.absTol.size()!=q) fail(
"absTol must be scalar or one per reward");
164 for(std::size_t r=0;r<q;++r) {
165 double v=o.absTol[o.absTol.size()==1?0:r];
166 if(!std::isfinite(v)||v<=0) fail(
"absTol must be positive");
169 long long n=o.baseSteps;
170 for(
int l=0;l<=o.levels;++l) {
171 if(n>o.maxEvents) fail(
"MLMC hierarchy exceeds maxEvents");
172 nsteps.push_back(
static_cast<int>(n)); steps.push_back(time/n);
173 if(time>0 && steps.back()==0) fail(
"MLMC time steps underflow; use a coarser grid"); n*=o.refinementFactor;
175 z=-boost::math::quantile(boost::math::normal(),(1-o.confidenceLevel)/2);
185 if(
static_cast<long long>(nl)*(
static_cast<long long>(o.pilotPaths)+o.minPaths)>o.maxPaths)
186 fail(
"MLMC minimum sampling allocation exceeds maxPaths");
187 for(std::size_t l=0;l<nl;++l) { Batch b=batch(
static_cast<int>(l),o.pilotPaths); e.
costsPerSample[l]=b.cost;
190 for(std::size_t r=0;r<q;++r) {
193 for(std::size_t l=0;l<nl;++l) {
195 if(!std::isfinite(n)||n>o.maxPaths) fail(
"MLMC pilot allocation exceeds maxPaths");
199 long long total=nl*o.pilotPaths;
for(
int n:e.
pathsPerLevel) total+=n;
200 if(total>o.maxPaths) fail(
"MLMC pilot allocation exceeds maxPaths");
201 for(std::size_t l=0;l<nl;++l) { Batch b=batch(
static_cast<int>(l),e.
pathsPerLevel[l]);
202 for(std::size_t r=0;r<q;++r) {
208 for(std::size_t r=0;r<q;++r) {
214 e.
biasStatus=time==0?
"zero":
"zero-discretization-bias";