[docs]defMC_integral(p,q,n_draws=1e4,error=True):""" Monte Carlo integration using FIGARO reconstructions. ∫p(x)q(x)dx ~ ∑p(x_i)/N with x_i ~ q(x) p(x) must have a pdf() method and q(x) must have a rvs() method. Lists of p and q are also accepted. Arguments: list or class instance p: the probability density to evaluate. Must have a pdf() method. list or class instance q: the probability density to sample from. Must have a rvs() method. int n_draws: number of MC draws bool error: whether to return the uncertainty on the integral value or not. Return: double: integral value double: uncertainty (if error = True) """# Check that both p and q are iterables or callables:ifnot((hasattr(p,'pdf')ornp.iterable(p))and(hasattr(q,'rvs')ornp.iterable(q))):raiseFIGAROException("p and q must be list of callables or having pdf/rvs methods")# Number of p draws and methods checkiter_p=Falseiter_q=Falseifnp.iterable(p):ifnotnp.alltrue([hasattr(pi,'pdf')forpiinp]):raiseFIGAROException("p must have pdf method")n_p=len(p)np.random.shuffle(p)iter_p=Trueelse:ifnothasattr(p,'pdf'):raiseFIGAROException("p must have pdf method")# Number of q draws and methods checkifnp.iterable(q):ifnotnp.alltrue([hasattr(qi,'rvs')forqiinq]):raiseFIGAROException("q must have rvs method")n_q=len(q)np.random.shuffle(q)iter_q=Trueelse:ifnothasattr(q,'rvs'):raiseFIGAROException("q must have rvs method")n_draws=int(n_draws)# Integralsifiter_panditer_q:shortest=np.min([n_p,n_q])probabilities=np.array([pi.pdf(qi.rvs(n_draws))forpi,qiinzip(p[:shortest],q[:shortest])])elifiter_qandnotiter_p:probabilities=np.array([p.pdf(qi.rvs(n_draws))forqiinq])elifiter_pandnotiter_q:samples=q.rvs(n_draws)probabilities=np.array([pi.pdf(samples)forpiinp])else:probabilities=np.atleast_2d(p.pdf(q.rvs(n_draws)))means=probabilities.mean(axis=1)I=means.mean()ifnoterror:returnImc_error=(probabilities.var(axis=1)/n_draws).mean()figaro_error=means.var()/len(means)returnI,np.sqrt(mc_error+figaro_error)