{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Monte Carlo integration by Vegas" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Brute force Monte Carlo" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First we will implement the simple Monte Carlo method." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# simple class to take care of statistically determined quantities\n", "class Cumulants:\n", " def __init__(self):\n", " self.sum=0.0 # f_0 + f_1 +.... + f_N\n", " self.sqsum=0.0 # f_0^2 + f_1^2 +....+ f_N^2\n", " self.avg = 0.0 # I_best when many iterations, otherwise = 1/N\\sum_i f_i\n", " self.err = 0.0 # sigma of I_best when many iterations, otherwise sqrt( -^2 )/sqrt(N)\n", " self.chisq = 0.0\n", " self.weightsum=0.0 # \\sum_i 1/sigma_i^2\n", " self.avgsum=0.0 # \\sum_i _i/sigma_i^2\n", " self.avg2sum=0.0 # \\sum_i _i^2/sigma_i^2\n", "\n", "def SimpleMC(integrant, ndim, unit, maxeval, cum):\n", " nbatch=1000 # function will be evaluated in bacthes of 1000 evaluations at one time (for efficiency and storage issues)\n", " neval=0\n", " for nsamples in range(maxeval,0,-nbatch): # loop over all_nsample evaluations in batches of nbatch\n", " n = min(nbatch,nsamples) # How many evaluations in this pass?\n", " xr = unit*random.random((n,ndim)) # generates 2-d array of random numbers in the interval [0,1)\n", " wfun = integrant(xr) # n function evaluations required in single call\n", " neval += n # We just added so many fuction evaluations\n", " cum.sum += sum(wfun) # sum_i f_i = * neval\n", " cum.sqsum += sum(wfun*wfun) # sum_i f_i^2 = * neval\n", " \n", " cum.avg = cum.sum/neval\n", " w0 = sqrt(cum.sqsum/neval) # sqrt()\n", " cum.err = sqrt((w0-cum.avg)*(w0+cum.avg)/neval) # sqrt(sqsum-sum**2)\n", " cum.avg *= unit**ndim # adding units if not [0,1] interval\n", " cum.err *= unit**ndim # adding units if not [0,1] interval" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We used here a simple trick to avoid overflow, i.e.,\n", "\n", "\\begin{eqnarray}\n", "\\sqrt{\\frac{\\langle f^2\\rangle-\\langle f\\rangle^2}{N}} = \n", "\\sqrt{\\frac{(\\sqrt{\\langle f^2\\rangle}-\\langle f\\rangle)(\\sqrt{\\langle f^2\\rangle}+\\langle f\\rangle)}{N}}\n", "\\end{eqnarray}" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "def my_integrant2(x):\n", " \"\"\" For testing, we are integration the function\n", " 1/(1-cos(x)*cos(y)*cos(z))/pi^3\n", " in the interval [0,pi]**3\n", " \"\"\"\n", " #nbatch,ndim = shape(x)\n", " return 1.0/(1.0-cos(x[:,0])*cos(x[:,1])*cos(x[:,2]))/pi**3" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.37945218006659 +- 0.009653985562123381 exact= 1.3932\n", "how many sigma away 1.42405640084531\n" ] } ], "source": [ "from scipy import *\n", "from numpy import *\n", "unit=pi\n", "ndim=3\n", "maxeval=200000\n", "exact = 1.3932 # exact value of the integral\n", " \n", "cum = Cumulants()\n", " \n", "SimpleMC(my_integrant2, ndim, pi, maxeval, cum)\n", "print(cum.avg, '+-', cum.err, 'exact=', exact)\n", "print('how many sigma away', abs(cum.avg-exact)/cum.err)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Vegas" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First we define the grid points $g(x)$. At the beginning, we just set $g(x)=x$." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "class Grid:\n", " \"\"\"Contains the grid points g_n(x) with x=[0...1], and g=[0...1]\n", " for Vegas integration. There are n-dim g_n functions.\n", " Constraints : g(0)=0 and g(1)=1.\n", " \"\"\"\n", " def __init__(self, ndim, nbins):\n", " self.g = zeros((ndim,nbins+1)) \n", " # a bit dirty trick: We will later use also g[-1] in interpolation, which should be set to zero, hence\n", " # we allocate dimension nbins+1, rather than nbinx\n", " self.ndim=ndim\n", " self.nbins=nbins\n", " # At the beginning we set g(x)=x\n", " # The grid-points are x_0 = 1/N, x_1 = 2/N, ... x_{N-1}=1.0. Note x_N=x_{-1}=0 \n", " # Note that g(0)=0, and we skip this point on the mesh.\n", " for idim in range(ndim):\n", " self.g[idim,:nbins] = arange(1,nbins+1)/float(nbins)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "def Vegas_step1(integrant, unit, maxeval, nstart, nincrease, grid, cum):\n", " ndim, nbins = grid.ndim,grid.nbins # dimension of the integral, size of the grid for binning in each direction\n", " unit_dim = unit**ndim # converts from unit cube integration to generalized cube with unit length\n", " nbatch=1000 # function will be evaluated in bacthes of 1000 evaluations at one time (for efficiency and storage issues)\n", " neval=0\n", " print (\"\"\"Vegas parameters:\n", " ndim = \"\"\"+str(ndim)+\"\"\"\n", " unit = \"\"\"+str(unit)+\"\"\"\n", " maxeval = \"\"\"+str(maxeval)+\"\"\"\n", " nstart = \"\"\"+str(nstart)+\"\"\"\n", " nincrease = \"\"\"+str(nincrease)+\"\"\"\n", " nbins = \"\"\"+str(nbins)+\"\"\"\n", " nbaths = \"\"\"+str(nbatch)+\"\\n\")\n", "\n", " bins = zeros((nbatch,ndim),dtype=int) # in which sampled bin does this point fall?\n", " \n", " all_nsamples = nstart\n", " for nsamples in range(all_nsamples,0,-nbatch): # loop over all_nsample evaluations in batches of nbatch\n", " n = min(nbatch,nsamples) # How many evaluations in this pass?\n", " # We are integrating f(g_1(x),g_2(y),g_3(z))*dg_1/dx*dg_2/dy*dg_3/dz dx*dy*dz\n", " # This is represented as 1/all_nsamples \\sum_{x_i,y_i,z_i} f(g_1(x_i),g_2(y_i),g_3(z_i))*dg_1/dx*dg_2/dy*dg_3/dz\n", " # where dg_1/dx = diff*NBINS\n", " wgh = zeros(nbatch) # weights for each random point in the batch\n", " xr = random.random((n,ndim)) # generates 2-d array of random numbers in the interval [0,1)\n", " # This part takes quite a lot of time and it would be nice to rewrite with numba!\n", " for i in range(n):\n", " weight = 1.0/all_nsamples\n", " for dim in range(ndim):\n", " # We want to evaluate the function f at point g(x), i.e, f(g_1(x),g_2(y),...)\n", " # Here we transform the points x,y,z -> g_1(x), g_2(y), g_3(z)\n", " # We hence want to evaluate g(x) ~ g(x[i]), where x is the random number and g is the grid function\n", " # The discretized g(t) is defined on the grid :\n", " # t[-1]=0, t[0]=1/N, t[1]=2/N, t[2]=3/N ... t[N-1]=1.\n", " # We know that g(0)=0 and g(1)=1, so that g[-1]=0.0 and g[N-1]=1.0\n", " # To interpolate g at x, we first compute i=int(x*N) and then we use linear interpolation\n", " # g(x) = g[i-1] + (g[i]-g[i-1])*(x*N-i) ; if i>0\n", " # g(x) = 0 + (g[0]-0)*(x*N-0) ; if i=0\n", " #\n", " pos = xr[i,dim]*nbins # which grid would it fit ? (x*N)\n", " ipos = int(pos) # the grid position is ipos : int(x*N)==i \n", " diff = grid.g[dim,ipos] - grid.g[dim,ipos-1] # g[i]-g[i-1]\n", " # linear interpolation for g(x) : \n", " xr[i,dim] = (grid.g[dim,ipos-1] + (pos-ipos)*diff)*unit # g(xr) ~ ( g[i-1]+(g[i]-g[i-1])*(x*N-i) )*[units]\n", " #gx = grid.g[dim,ipos-1] + (pos-ipos)*diff\n", " #xr[i,dim]= gx*(b-a) + a\n", " bins[i,dim]=ipos # remember in which bin this random number falls.\n", " weight *= diff*nbins # weight for this dimension is dg/dx = (g[i]-g[i-1])*N\n", " # because dx = i/N - (i-1)/N = 1/N\n", " wgh[i] = weight # total weight is (df/dx)*(df/dy)*(df/dx).../N_{samples}\n", " # Here we evaluate function f on all randomly generated x points above\n", " fx = integrant(xr) # n function evaluations required in single call\n", " neval += n # We just added so many fuction evaluations\n", " \n", " # Now we compute the integral as weighted average, namely, f(g(x))*dg/dx\n", " wfun = wgh * fx # weight * function ~ f_i*w_i, here w_i has 1/N in its weight, hence actually we are \n", " # evaluating 1/N * sum_i f_i*w_i\n", " cum.sum += sum(wfun) # 1/N sum_i f_i*w_i = \n", " wfun *= wfun # carefull : we need 1/N (f_i w_i)^2, while this gives (f_i w_i/N)^2\n", " cum.sqsum += sum(wfun) # sum_i (f_i*w_i/N)^2 = /all_nsamples\n", " # \n", " w0 = sqrt(cum.sqsum*all_nsamples) # w0 = sqrt()\n", " w1 = (w0 + cum.sum)*(w0 - cum.sum) # w1 = (w0^2 - ^2) = (-^2)\n", " w = (all_nsamples-1)/w1 # w ~ 1/sigma_i^2 = (N-1)/(-^2)\n", " # Note that variance of the MC sampling is Var(monte-f) = (-^2)/N == 1/sigma_i^2\n", " cum.weightsum += w # weightsum ~ \\sum_i 1/sigma_i^2\n", " cum.avgsum += w*cum.sum # avgsum ~ \\sum_i _i / sigma_i^2\n", " \n", " cum.avg = cum.avgsum/cum.weightsum # I_best = (\\sum_i _i/sigma_i^2 )/(\\sum_i 1/sigma_i^2)\n", " cum.err = sqrt(1/cum.weightsum) # err ~ sqrt(best sigma^2) = sqrt(1/(\\sum_i 1/sigma_i^2))\n", " \n", " cum.avg *= unit**ndim\n", " cum.err *= unit**ndim" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vegas parameters:\n", " ndim = 3\n", " unit = 3.141592653589793\n", " maxeval = 200000\n", " nstart = 10000\n", " nincrease = 5000\n", " nbins = 128\n", " nbaths = 1000\n", "\n", "1.3258378290394897 +- 0.02037303730823348 exact= 1.3932\n" ] } ], "source": [ "from scipy import *\n", "from numpy import *\n", "\n", "unit=pi\n", "ndim=3\n", "maxeval=200000\n", "exact = 1.3932 # exact value of the integral\n", " \n", "cum = Cumulants()\n", " \n", "nbins=128\n", "nstart =10000\n", "nincrease=5000\n", "grid = Grid(ndim,nbins)\n", "random.seed(0)\n", "\n", "#SimpleMC(my_integrant2, ndim, pi, maxeval, cum)\n", "Vegas_step1(my_integrant2, pi, maxeval, nstart, nincrease, grid, cum)\n", "print (cum.avg, '+-', cum.err, 'exact=', exact)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we are going to insert the sampling of the projection of the function $f(x)$ to all axis, $f_1(x), f_2(y)...$, from which we will calculate new grids $g_1(x), g_2(y)...$." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "def Vegas_step2(integrant, unit, maxeval, nstart, nincrease, grid, cum):\n", " ndim, nbins = grid.ndim,grid.nbins # dimension of the integral, size of the grid for binning in each direction\n", " unit_dim = unit**ndim # converts from unit cube integration to generalized cube with unit length\n", " nbatch=1000 # function will be evaluated in bacthes of 1000 evaluations at one time (for efficiency and storage issues)\n", " neval=0\n", " print (\"\"\"Vegas parameters:\n", " ndim = \"\"\"+str(ndim)+\"\"\"\n", " unit = \"\"\"+str(unit)+\"\"\"\n", " maxeval = \"\"\"+str(maxeval)+\"\"\"\n", " nstart = \"\"\"+str(nstart)+\"\"\"\n", " nincrease = \"\"\"+str(nincrease)+\"\"\"\n", " nbins = \"\"\"+str(nbins)+\"\"\"\n", " nbaths = \"\"\"+str(nbatch)+\"\\n\")\n", "\n", " bins = zeros((nbatch,ndim),dtype=int) # in which sampled bin does this point fall?\n", " \n", " all_nsamples = nstart\n", " fxbin = zeros((ndim,nbins)) #new2: after each iteration we reset the average function being binned\n", " for nsamples in range(all_nsamples,0,-nbatch): # loop over all_nsample evaluations in batches of nbatch\n", " n = min(nbatch,nsamples) # How many evaluations in this pass?\n", " # We are integrating f(g_1(x),g_2(y),g_3(z))*dg_1/dx*dg_2/dy*dg_3/dz dx*dy*dz\n", " # This is represented as 1/all_nsamples \\sum_{x_i,y_i,z_i} f(g_1(x_i),g_2(y_i),g_3(z_i))*dg_1/dx*dg_2/dy*dg_3/dz\n", " # where dg_1/dx = diff*NBINS\n", " wgh = zeros(nbatch) # weights for each random point in the batch\n", " xr = random.random((n,ndim)) # generates 2-d array of random numbers in the interval [0,1)\n", " for i in range(n):\n", " weight = 1.0/all_nsamples\n", " for dim in range(ndim):\n", " # We want to evaluate the function f at point g(x), i.e, f(g_1(x),g_2(y),...)\n", " # Here we transform the points x,y,z -> g_1(x), g_2(y), g_3(z)\n", " # We hence want to evaluate g(x) ~ g(x[i]), where x is the random number and g is the grid function\n", " # The discretized g(t) is defined on the grid :\n", " # t[-1]=0, t[0]=1/N, t[1]=2/N, t[2]=3/N ... t[N-1]=1.\n", " # We know that g(0)=0 and g(1)=1, so that g[-1]=0.0 and g[N-1]=1.0\n", " # To interpolate g at x, we first compute i=int(x*N) and then we use linear interpolation\n", " # g(x) = g[i-1] + (g[i]-g[i-1])*(x*N-i) ; if i>0\n", " # g(x) = 0 + (g[0]-0)*(x*N-0) ; if i=0\n", " #\n", " pos = xr[i,dim]*nbins # which grid would it fit ? (x*N)\n", " ipos = int(pos) # the grid position is ipos : int(x*N)==i\n", " diff = grid.g[dim,ipos] - grid.g[dim,ipos-1] # g[i]-g[-1]\n", " # linear interpolation for g(x) : \n", " xr[i,dim] = (grid.g[dim,ipos-1] + (pos-ipos)*diff)*unit # g(xr) ~ ( g[i-1]+(g[i]-g[i-1])*(x*N-i) )*[units]\n", " bins[i,dim]=ipos # remember in which bin this random number falls.\n", " weight *= diff*nbins # weight for this dimension is dg/dx = (g[i]-g[i-1])*N\n", " # because dx = i/N - (i-1)/N = 1/N\n", " wgh[i] = weight # total weight is (df/dx)*(df/dy)*(df/dx).../N_{samples}\n", " # Here we evaluate function f on all randomly generated x points above\n", " fx = integrant(xr) # n function evaluations required in single call\n", " neval += n # We just added so many fuction evaluations\n", "\n", " # Now we compute the integral as weighted average, namely, f(g(x))*dg/dx\n", " wfun = wgh * fx # weight * function ~ f_i*w_i\n", " cum.sum += sum(wfun) # sum_i f_i*w_i = \n", " wfun *= wfun # carefull : this is like (f_i * w_i/N)^2 hence 1/N (1/N (f_i*w_i)^2)\n", " cum.sqsum += sum(wfun) # sum_i (f_i*w_i)^2 = /all_nsamples\n", " # \n", " for dim in range(ndim): #new2\n", " # projection of the sampled function^2 to each dimension, which will be used to improve the grid.\n", " for i in range(n): #new2\n", " fxbin[dim, bins[i,dim] ] += wfun[i] #new2: just bin the function f. We saved the bin position before.\n", " \n", " w0 = sqrt(cum.sqsum*all_nsamples) # w0 = sqrt()\n", " w1 = (w0 + cum.sum)*(w0 - cum.sum) # w1 = (w0^2 - ^2) = (-^2)\n", " w = (all_nsamples-1)/w1 # w ~ 1/sigma_i^2 = (N-1)/(-^2)\n", " # Note that variance of the MC sampling is Var(monte-f) = (-^2)/N == 1/sigma_i^2\n", " cum.weightsum += w # weightsum ~ \\sum_i 1/sigma_i^2\n", " cum.avgsum += w*cum.sum # avgsum ~ \\sum_i _i / sigma_i^2\n", " \n", " cum.avg = cum.avgsum/cum.weightsum # I_best = (\\sum_i _i/sigma_i^2 )/(\\sum_i 1/sigma_i^2)\n", " cum.err = sqrt(1/cum.weightsum) # err ~ sqrt(best sigma^2) = sqrt(1/(\\sum_i 1/sigma_i^2))\n", " \n", " cum.avg *= unit**ndim\n", " cum.err *= unit**ndim\n", " \n", " return fxbin" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vegas parameters:\n", " ndim = 3\n", " unit = 3.141592653589793\n", " maxeval = 200000\n", " nstart = 10000\n", " nincrease = 5000\n", " nbins = 128\n", " nbaths = 1000\n", "\n", "1.3805573702326992 +- 0.03849036529933611 exact= 1.3932\n" ] } ], "source": [ "from scipy import *\n", "from numpy import *\n", "\n", "unit=pi\n", "ndim=3\n", "maxeval=200000\n", "exact = 1.3932 # exact value of the integral\n", " \n", "cum = Cumulants()\n", " \n", "nbins=128\n", "nstart =10000\n", "nincrease=5000\n", "grid = Grid(ndim,nbins)\n", "\n", "#SimpleMC(my_integrant2, ndim, pi, maxeval, cum)\n", "fxbin = Vegas_step2(my_integrant2, pi, maxeval, nstart, nincrease, grid, cum)\n", "print(cum.avg, '+-', cum.err, 'exact=', exact)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAEDCAYAAAAlRP8qAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAAAsTAAALEwEAmpwYAABG80lEQVR4nO2deZxkZXX3v+feW0vv0z0zzA4M+ya7gOKGaILGiIkoisYlKiFRYsybVzFqYmJiYvSNW9xwiUuMmkRNABFQMSgisigCA8wwzAxMzz7TPb1Md9dy73n/uEvdqq6eroGZ6brt+X4+2FW3bt16bgunT/3O75xHVBXDMAwj+zhzvQDDMAzj4GAB3TAMY55gAd0wDGOeYAHdMAxjnmAB3TAMY55gAd0wDGOeMKcBXUS+JCI7ReTBg3Cti0TkvtQ/UyLysoOwTMMwjEwgc+lDF5HnAOPAV1X1tIN43QFgPbBSVScO1nUNwzDamTnN0FX1J8BQ+piIHCsiN4nIvSLyUxE56Ulc+jLg+xbMDcP4TaIdNfRrgatV9RzgL4BPP4lrvAr4xkFdlWEYRpvjzfUC0ohIN/BM4D9FJD5ciF77feBvm7xti6r+duoay4CnATcf2tUahmG0F20V0Am/MexV1TMbX1DV7wDfaeEarwS+q6qVg7w2wzCMtqatJBdVHQU2isgrACTkjAO8zKsxucUwjN9AZg3os1kLo6D7CRFZLyL3i8jZrX64iHwD+DlwoogMisibgNcAbxKRXwNrgEsP4HpHA6uA21p9j2EYxnxhVtvibNZCEXkxcDXwYuB84OOqev4hWKthGIaxH2bN0JtZCxu4lDDYq6reCSyICpOGYRjGYeRgFEVXAJtTzwejY9saTxSRK4ErAZyO3nNOPXIh+dHHwzd1nMh4yeekpT3hyVN7YWgjLD4Jch3hsZHNMDUCSw5aD5JhGMbhZ+/jUBpjNwE7PJfjSwFVr5vOI1azeXgCKY2yMtjGpo5+9vkljltwPAUvzL/vvffe3aq6uNllD0ZAlybHmuo4qnotoc+cwrLj9YZr/5ojb30rAO885Wv8bMMIP7vm+eHJa/4b/vP18Mf/CUtOCY/d8A54+Hr4v/cchGUbhmHMEd9+Czzxcz4nI/xL/wJu3DDOjkXP5Jyrv87bv/krOjb+gH8s/T1vOu13uXP4Mb576fc47ogw2RWRx2e67MFwuQwSFiJjVgJbW3mjaFBbiPrU6fnxa5Jaoji144ZhGFlFA3Bc4mjmpHJg1VqW7ACI0uqEloMR0K8DXhe5XS4ARlR1mtzSnFRApyFQJwE99QVAHAj8p7RYwzCMOUd9cDw0Ct3p/1VIElnBAbS55NGEWSWXyFr4PGCRiAwCfw3kAFT1s8CNhA6X9cAE8MYWPxtJBWdnpsy7LkN3aflPlWEYRruiATgegQ+iYYYeRzZNpeiOCNB6hj5rQFfVV8/yugJvbe3jGt9cn6Frs9dMcjEMY76hAYhDkFIg4qCdDt4OEkouLeboczsPnVSGToOU0ixwi1hANwwj+6iGCao4SFpqIRRY4mNxhh60GPbmNqDr/jT06PamZeimoRuGkXECH0QIIpVcqM/Q47w9DOxZydDrXC5BvU7UTHJxXMvQDcPIPhqAuASOJNl4kJZcIilGRJAD0NDndjhXUB/Q65jJ5WIB3TCMrBNp6LG4IumiKJqEPQGQ1mPeHGvojUXRuhQ9OsmKooZhzDNSRdE4ZY0z9EBJ7IxOFKIzkaGLpouiM2XoTQK6WRcNw8gy6tdl6JAqimootUCqKNpizJtbyUVbcbmkJRc3es0CumEYGSbqFFWRWuEzCWuaKooS2RZbo42Kon5DUXQGyQVMdjEMI9tEtsVABElJLfFLMY5EnaLZyNBbaf1PB3SZ9j7DMIzMEWvoSVEUYtElNLnEwwBi22JrtLGGHmfoDS4XMC+6YRjZJog0dJEkCAca2xc1iXtJp2g2iqJB3eP6NTeRXJxYQ7cM3TCMDNOs9T/+mZ62GBVFZ5hIPo0MSC7NMnQL6IZhZJiUDz3sFK3p5OG0xVSGjib6+my0TYY+Y6coTQK6jdA1DCPLaE1ykURqiZT0VCAUBBElaDGit5GG3mhbbOZyMcnFMIx5QLLBRbpTtBa0nbhTNPoZtBjz2siH3mJjEZgP3TCMbJNo6KQ6RVNF0Sg0O4n/JQMZejowh/JLsy3o0pKL2RYNw5gHRD70WEOHWtCe7kMHP3uSS2OQ3l9jkWnohmFkmGh8roqANhmfm+xYFJ3eYsxrn4DeuOCZxuemXzMMw8gi8fjctA89filsLQJqkktGZrk0TFts1eViAd0wjCyTdIpSK4o2y9CTgJ6Bomj9jkWtuFwsoBuGMQ9Iz0OPYt1MG1wABNMk6ea0j8ulsVN0fwHdfOiGYWSZyIeellxm3lMUghY3FZ3bDD040E5R09ANw5gHxONzo6d1naI1CT3Z4MLPguRCeseiVregA/OhG4aRbWLbYpPhXKl4ni0NPS2diPoNM3+1Xm4B86EbhjE/0AAk3IRTEttinKFrbXxuYlvMgMslLIrG9pwmGfq0gG4+dMMw5gGBP6NtsX5P0Thrz0KGTgBuLlpIM8lF6o+ZD90wjPlA4nIJ9fP0FnR1G1wkRdEsZOiBD24+fKz+dJfLjBm6BXTDMDJMascip2ELOrS2p6ibJQ1dtJahuwciuZht0TCMLJOMz00dSv2stf6HD7LhctF0ht6kU1QaJBfL0A3DmA+kbItOpJgHSaZeaxWVzLX+O7GG3iTrnpahxxq62RYNw8gwkaScllzqt6BraCzKQoaellycxnm/+3W5WIZuGEaGmWWWS0zcWJQNl0tKcnEafejNXC6JD900dMMwMkwyPreWzDbdUzT2oWei9V+DOpdLHemRYzFmWzQMYz4Qj88lbCyC+j1Fa52icet/VjT0/fnQTXIxDGM+kpq26BBKLkGSqTfZ4KJZjbEJc7/BRdrlkn7RXC6GYcxXpjUWpWe51PYUjRuLWvWBtBTQReQSEVkrIutF5Jomr/eJyPUi8msRWSMib2zp0wM/laE3/gXaT2OR+dANw8gyyfhcogw9JAj00G5wISIu8CngRcApwKtF5JSG094KPKSqZwDPA/6fiORn//gg0sUlnLY4zYc+k23RMnTDMDJKnG47oYbupIqhvmpDUfTg2xbPA9ar6gZVLQPfBC5tXCLQI+H3g25gCKjOdmEJoqDtuEgrs1xsfK5hGFkntV9yTVwJ8QONpi2Gzw/FnqIrgM2p54PRsTT/ApwMbAUeAN6uOv1PiohcKSL3iMg9QPS1wwVxm8xDt1kuhmHMQ1J7PcQaek1HjySX6FQ3dmofxKKoNDnW+Ofit4H7gOXAmcC/iEjvtDepXquq56rquRDZFh0XHBeHVoZzmQ/dMIyME9cAG2yLioQZOiSx71C0/g8Cq1LPVxJm4mneCHxHQ9YDG4GTZr1yrJOLW7dhdO0186EbhjHPaJBc3HSGHjT40KPAfjAbi+4GjheR1VGh81XAdQ3nPAFcDCAiS4ATgQ2zXjmq9OI4033oNGksMsnFMIyskwroSaUw+p9pRdE4Q58mijTHm/WzVasi8jbgZsAFvqSqa0Tkquj1zwIfAL4sIg9ES3uXqu6e7doS+GHWLe70LeisscgwjPlILBlHtkU3tYuoHzRq6Afmcpk1oAOo6o3AjQ3HPpt6vBX4rZY+sY6w/RXHa23HIvOhG4aRdeLg7LgEWhvOBaFWHqQkF5Lu0QzMciFlW3SmzXIxH7phGPOQWImIbYtRAFdqGXosubixht6i5DL3rf9OzbbY+hZ05kM3DCOjNGjoTrSnKIQBPXoRSG0SnZnhXOKC4yCNPsumGbrZFg3DyDiJbVEI0KT1X5HIh67JDJdMbXCRti06qS3o/u6Gh7hv85C5XAzDmH8kGXpYDnVT2XfsQ2/cUzQTW9CFkkukoaeKout2jjM2WZmeoZsP3TCMrNNEckmGczUURV3NVIZea/1PNxZV/SA00ptt0TCM+UZDY1EcvMOiKHVFUXFiH3omAnpj63/4taIaKBr4mG3RMIx5R9qHjkY+9FpRtE5yifcUzUKGnkxbbMjQ/UAJgmadoia5GIaRcVI+9HDaYjw+V5LhXHFojgN0RlwufuJycRokF9UANcnFMIz5RsqHHqC4WpvlEtoWdfoWdFnI0BPJRVwEP7nPaqA4BASNf5TMh24YRtaZVhSt4auSFifixiLNRmNRNFHRqZ+H7gdhlTeYpqGbD90wjIwT1DR0jbLzxIcebXAR1w9r43MzkaGnXC6p5taKH4QZeuPyzLZoGEbWabJjUWzbbiyKuodgHvqhI5626Hh1s1zCDF3xZ5RcLKAbhpE9tu/bzr9v+n74JD0+l9SeogoSb3ARG/uykaGnWv9TAb0aBfRArVPUMIz5w00bb+IfHvkyYyJJUdRJJa5BUJ+Nu3XhfnbmVkNHqaAERBtcxEVRX3FQ/JkCuvnQDcPIIFP+FACVqHY4bZNo1XBvn+h5hma5hNH7Fdtv4ssyWt8pGiiONJNcTEM3DCO7lP0yANVUhi5pH3rDnqKZCejxX6Ct1X1sxcchraEHoYY+U6eo2RYNw8ggJb8EQEWY1voP8Tz01CyXA9yCbm41dKCqAVUJLYxJ678fF0VnCugmuRiGkT3igF5FQARVTQXh2p6ijdMW2771P/6aUSWgCvWdokGkoac6i/537U4uv/bO8IlJLoZhZJCa5AKI26QoGk1blAYfehaGc/mESnpVqOsUrdkWaxn6PZuG+cWm4XAcgAV0wzAySJKhRxp6KLmk5qEns1ziLejC462qzHOqoVejxTZm6JUgwEGppgL62FQleqMFdMMwskmcoVeIA3pNclEg0MguEoU+yc60RQ11JMKAHrtcgmiTVCHAT93D2FQ1fCCO2RYNw8gktQydlMulRhDEtsU4Qw9/nrztOzC+c9brz3GGngro+Chhdp68nvqaMRoHdCxDNwwjmyQZesqHLlGcU5Wo9T81bTF63xHjD0Jlctbrz6mGHokoVKUmucSFUIegqeSijgV0wzCySc3lwjTJBaZPW3Si+bmKgJub9fpz6nKpZeiazHKpJgFdqTaTXHDMh24YRiap+dAlEVucVFG0Nm0xaiyKXgoA3Pys15/TDD1dFBUCVJWqnwroqbg9XgoDeuhyMQ3dMIzsUQlCpaEqQpBYE0O0iQ891tADAMeb9fpzm6HTLEOP0/LGDN1cLoZhZJu05BJHsUYfuqZmucQBXYX2llygoSiqQbTr9XTJRVUTycV86IZhZJVGHzo0jM+NmymT1+IMXcBp44Be70NXJPp7lZZcKlHcnqoEibau5nIxDCOjpF0ucRRL2xbjOBdLLrWATrtn6DNJLuENuUIS0BO5BVAR86EbhpFJ6iQXJyp8pqYtxhm6JAXTkECcWpTfD+1RFNUglFw0nLQI4DpKJQhPqHnQQcW1DN0wjEySHp8bS+dpDb2aSC7xj/CBL62F6jmVXCop26JE43MrkeTiRfPQ/UDrM3TEbIuGYWSOalDFj5UIiXRxpo/PTR+LbOj4LYbqOZZcQkLJpb6xyI1ueLLipzzopqEbhpFN4uwcwlkuQZKFhyhCNZp34iRyTJyhuy19Rnu0/mu8a4emNHQlQJgoV+sDuoj50A3DyByxfg6x5BIH7RrVoF59OCSSi4hcIiJrRWS9iFwzwznPE5H7RGSNiNzWynVrtsVINydI/kKFYyOFybLfILmYhm4YRvZIB/SKRN5yauNz622LTYqiLTBr65GIuMCngBcCg8DdInKdqj6UOmcB8GngElV9QkSOmPW6ackl0sRdgkRDd1ACFfaV/CYZugV0wzCyRVpyqSKJhh4XRR0RStNcLlGGfhA19POA9aq6QVXLwDeBSxvOuQL4jqo+AaCqs855rJ+2GGfofq2xSJQAh8lKtS5DD7DxuYZhZI/6DL3mQ4+DsCOpomicvcdF0YMouawANqeeD0bH0pwA9IvI/4rIvSLyumYXEpErReQeEbkH6m2LEGXosW0x2mF0ouwzVkoXRS1DNwwje5SDVIYukdpAyuUiQiWSnNOWc9HWA/rs017qXTUxjb5BDzgHuBjoAH4uIneq6rq6N6leC1wLMLBspVaTrxNh8HYIkk5RiVwuE+VQcsm7DmU/CDN0C+iGYWSMRsmlFtBrVsXGxqLk+EGUXAaBVannK4GtTc65SVX3qepu4CfAGfu7aNqHDmHnVLooGk8Kjoui/V1h22tgPnTDMDJIvcuFaRq6OE6qsai2majQelG0lbPuBo4XkdUikgdeBVzXcM7/AM8WEU9EOoHzgYf3d9F0URRCPd1N2RbDzZlIMvT+znAWcOhDNw3dMIxsUedDF0lcLnEQlpSGnuagSi6qWhWRtwE3Ay7wJVVdIyJXRa9/VlUfFpGbgPsJ58h8QVUfnO3a1YYM3SFIxueGkovDVORDjwN6YBq6YRgZpNGH3jicy0FSw7lqsdGhdcmlFQ0dVb0RuLHh2Gcbnn8Y+HBLnxpRlfRjqbctapDS0CusGugAoq8eFtANw8gYcUB3kPp56PEJUusUTQd0oSbPzEZbbHABYXB3JUgVBRRHnERyWZBk6BbQDcPIHrHk0ul4dcO54keOpMbnpt7nAH4Lkxbjc+eMeslFIpdLbccix3WYjCSXnqKH5wiB2vhcwzCyR5yhd0k+0tCjTSySyO6kfOipoqhqNqYt7k9yQQNc12XvZIWyH9BbzOG5YpKLYRiZJM7QuxwvlFwaiqLpDD2dojtkQHKhQXKpSENRVBXXcdgxOgVAT9Ej5zhhhm62RcMwMkaSoTu5+nno0U+BJhq6HlBRdI7nodeeVwkz9Nq0McV1XXaOhr+EnqIXZujmcjEMI4OU/BKCUMSlIrWiqEQJqjgplwtpl4sSZE5Dl7ixqCa5eK5by9ALOTzXiQK6aeiGYWSLsl+m4BbIiUTDuUJqGbpMm+USHge/3SWXxsYiH8HFrxVFNcB1HfaVw+AdSi6Cr6ahG4aRPcp+mbybx8MJi6LR8ThUi0hKoYhCsyqORu6+Fmi/DD2oz9BjeorpDN0CumEY2aLklyi4BTwk0tDrLYoikuypLHVF0QxILoI2BPSahu46EhZF6wJ6qKH7mG3RMIzskWToEnWKajy3KkSE1HDCxqJomwd0oE5yqUQ+9Iof4DlhFp5za8vrLeZSLhfL0A3DyBZxhp6LJReNu+JrhdBpjUWqWcnQm0kuih9oGNBRPLc2mWC0upOp4s8jDd1si4ZhZIu4KOoRJrNxhp5ILo6ktqCLDqofaehtHtBpMm3RkbCxKE7MXS+UXDrzLjduvIGhzn9jyAksQzcMI3OU/FJSFA2HczUEdKTWhxMf9SsI2v6SSzwPvegWgPp56IVoVXFRtKfoMVmdBOAJt2q2RcMwMketKBrGu0RyiV4XAb9RQ/crUadoa8y5y6XoFpPHcVHUi1aV8+KAnku6rAa9imXohmFkjrJfJufmyCGRbTEK3qlNoqeNz/XLoeTS/hp6KLkUvTCg+1Hrf8UPyLvh4nNNMvTNFtANw8ggpaBEwSmQI9qxSGu7s0FsW2xoLIrmv2RAQ48z9FhyCTN0P1ByseSSytCn/LBjdGvOArphGNmjVhSVuqJoTXJp0vofVCPbYmu0tMHFoaIqUPTCjSsqqWmLuWmSi8dUNQzo27wyQaBz+5fIMAzjAEmKoqr4KR96fWNRw56ifjkrtsVw2mIsuaS3oMtF/URxQO8tekmGXnaULa3dm2EYRtuQzHKJQng8TjfZgk5IXC4JfpnQxN32Ab0+Q6+K4OFHPvTwnNiH3lPMMVWdwiHctWi9Y5KLYRjZojbLJXoehAHdSZJySTpFHSfO0Ks42rrkMvcaepyhp4qiuehe8lGG3l0IJZde52gA1rvWWGQYRrZIz3IBqPgVoL4oWm1SFHWAViPenDYWVUTocKMMPZ6H7itRHKeQC/+WLegMM/SC9LGgmuNRd6ZrGoZhtB+BBlSCShjQI/95nKHXNPTa+bWiaIYai6oIBS9yuYjgSuhDz0er6i7m+djlZ/LSM5Yz5U+RcwocUc7zqGciumEY2SHWy9OSS9xbU5NcUuE4q41FOSeHK04kuSjVIMCTWqX3ZWetYEFnnqnqFJ4UWFQussmV5OuKYRhGuxMH74JbIBeFtziGpYuiMcnDqLGo7SWXcHwueI6HJ16d5JKLGotI/cWKM/SFpQJVETaNbpqbhRuGYRwg9Rl6GJ4rQRzQp287l2TrkcslGxk6gud4uI6bFEXTrf9pUalULZFz8gyUwyLq+r3r52DFhmEYB06coYc+9PBYHOTjMCxOOqBHD/xKGNBbVJnbMEMPyMWSS1wNDipUtUreKdJTKuCq8ujwo3O1dMMwjAMiDt6hDz0kDvLNJJcEv4KDtr8PHcJmIk88PMdLtqCr+PE8dBLJJe4SzTsFRD2W+QGDY4NztGrDMIwDI52hxxp67HJBoww9JTEnj4MKohC0qKLPaYYeREXRMKBL0ilak1zqA3rBLRIgdASa/IIMwzDanXRRNLYtJkXRSF+RpkXRrLhcohV7jkfOaSiKOvXzDOK2/7xbQBEKGlAKLKAbhpEN0pJLEtCD2KkXB/RUhh4/TBqLWpNc5nA4V3hTnuPhOblEcqkGiifNJZeCW8THIa+aKigYhmG0N7G8knfz+FHsq2noYZyrty3WhnMJ2v6SS0wY0L1ogwufqh/gJRl6fUAvRpJLQU1yMQwjOzTzodeS0jB4O800l2iWS9v70OMFJhk64EpAJW1bpF5yKbpFFIdCEFCuWoZuGEY2qPOhR2NzE8kl1ldSAb0+Q8+Chp6SXEIfelgU9QOt2RYbJRevSKBhhh4HecMwjHanrigaxb5kfG6yBV3tfKduHjrJdnWzMfeSS2RbjDe48APFbbQtRsG7wws19IIqZZNcDMPICPVF0fpjcTFUpC6ihz+jHYvaXnKJ/ywljUUiuNGyp7lcqrWAHiDkVSlZUdQwjIwQZ+g5J0euYdoiSVF0BslF9eBm6CJyiYisFZH1InLNfs57uoj4InJZS59OdINOjiqh5ALUDeeC+gxdcSgolqEbhpEZ6iSXaFeimg89ytDTs1ziB34lenaQArqIuMCngBcBpwCvFpFTZjjvQ8DNLX1yROxyiSWX8Fh80XoNvcPrsAzdMIzM0awomsxD18iHXjfLpTY+N2zDPHgZ+nnAelXdoKpl4JvApU3Ouxr4NrCzlQ/WOh96rVM0PNbch96RS2noQRlV27nIMIz2p+SXyDk5HHESySWxXst026JI2uXSuoreSkBfAWxOPR+MjqU/fAXwe8Bn93chEblSRO4RkXviY/U+9DCguw3Duab8KRxx6PDiTtFGDcowDKN9iTeIBsjpDJJLXUCPHkTWxoOZoTfrOW28+seAd6nqfvcyVdVrVfVcVT03PhYHdJ+U5JLsyVTL0AtugZzrJI1F8XHDMIx2p+SXyLvhJvfTJJdEQ2+OHMA0l1Za/weBVannK4GtDeecC3wz+guzCHixiFRV9b9nvmwkuYiHK7V56NBcQ+/wOvBcJ5FcAGv/NwwjE6QzdK8hQ4+nLTp1Gno6125dQ28loN8NHC8iq4EtwKuAK9InqOrq2kLky8AN+w/m1A3n8lLDuaC5y6XoFsm5QhDNcgGs/d8wjEyQDuiOhtJIMsslmbbYRHIJn9Gqhj5rQFfVqoi8jdC94gJfUtU1InJV9Pp+dfMZrxv9TGyLAq6Eio3bJEMvekU8x6nX0C1DNwwjA6QlFwKfHDJdcklF8fpBXc5BzdBR1RuBGxuONQ3kqvqGlj55msuFJhl6rVM01NAlsS2CZeiGYWSDUlBKMnQ0wEMoBVWgFtDrh3PVSy6tauhz3/rfRHJxk/uqdYp2eB24jtRp6BbQDcPIAmW/XMvQo4AeI007RWvoAWTo7TFtUbwZiqK1gF70iuTcesnFArphGFmg5JfIO6mAnt7MIt4kOh3Fm40BaIE2ytBJZrm4TSSXolvEc4VALUM3DCNbpIuiaKihxyQaerNOUYADsC3O/fhciX3ozTT0WoZe8Ap4Tr0P3YqihmFkgbqiqAZ4qdDbbJaLU5eUZ0FyabAths8jl0uTLeg6vA5yriRb0IFl6IZhZIP6DD21zSbgSBMfejo0y0EcznWoiQM6ABIVRRu3oEskF7MtGoaRPaZn6GlHiwuAw0w+9IM7y+WQknNyeBIGdG2UXKgvinpO1FgUWIZuGEZ2KPkp22Lgk0sXRePGorpoXK+ht7/kEv1smqGnZrn4gU85KEedoqGGXjTJxTCMDFEvuQTkmmjoTt2x9LuzVBRNB3SnYdqiOEnQLnpFXEcIxFwuhmFkB1Wd7kOPgriqIJHkIo2yefLEpe0lF40+3BEnCehB4/hckWS3oqJXBMARF4+wImwB3TCMdqcaVFG0zrZY86ELOFFAT8swdTYXqe0kPQtzuKcoSWFguuRSc7nEI3KLbjE6FJYOCk7OiqKGYbQ9cVKaztBz6YDepPVfsqihx17MOKBrPJwrnaFX6zN0nPA9eSdnGbphGG3PeHkcgO5cd3hAteZDV1IBvfYemTbXpc0DOpB4MZMMvcmORYnkEmXoTvT1pOB4lqEbhtH2jJZHAegt9IYH6lr/axm6zDjLJSMaepKhx7bFKJDHIwDqJJdYQ48y9IKTtwzdMIy2Jwno+SigBz5eVAidUXKpC+5ZCegNGXoS0FO2xcaAHleEC45nAd0wjLZntBQG9J58T3ggraFrKkOfYZaLZkVyyTVq6JHk4jg1DX3SnwRSRVE3DOh5C+iGYWSAaRm6BvUZutNkHnodGQjoYYZeH9CDKEP3UpJLqVrzoUNaQ7eiqGEY7c/sGnrU+l9XB02b0l0QRXX2oD7HRdFGDT3K0NOSS1QU7fA6okORhi5WFDUMo/0ZLY8iSMrlUq+h17agq4Xj+mmL4bmtWBfndNpio20xoKEoijBZDSWX2JTvOia5GIaRHUZLo/Tke8KpilGWnYsCumoLPvTo9UBnb/9vC8kl5+QACCLt3JGZXS6xhl60DN0wjAwwWh6t08+B+gw91tDrWv9TRdE4Q8+M5JIUReOAHp2QmuUSZ+iO1DL0ONgbhmG0K6Pl0Tr9HJih9X+GomgU84IWBnTNcYYeLtSNv34kPvRo4VGnaNEt1obAu7GG7lqGbhhG2zNWHqtZFoOwGz4XBXHqJJfpI3VDMpChN3O5+NIouYQaesErJO9z0rbFwDR0wzDam2aSS07i7vh0UbT2Hmda63+ba+jQTHIJ8JxUOSCSXGIPOqRsi5ahG4aRAUZLs2joiW2x+Y5FKvWS9P6Y0ww9rvTWMnRwHUluOi6KxpZFqLX+58Wl5Jda+hpiGIYxF6jqDBp6k8aiGTpFEw29nTN0ldpNpRuLcq5TC+iEnaLJpEVqtsWiuAQaUNXqYV23YRhGq0z5U1SCSipDDzX0ZCCh1lwu9UG89lAzEdBpYltEowy93raYDIanpqEXopuMO0kNwzDajXiOSy2gRz50p5nkkiqKksmiaPhXKi255Nx6yaXkl+oydInOzUfvteYiwzDalWZzXKAW+9K2xZnnodfv6LY/5jCgC54zXXKp19BD22KHW9PQvcS2GP60wqhhGO3KWHkMqB+dCySxD5WkLsiMAT0zkku9D92XeKRuTXKZrNZr6LEPPR8FdMvQDcNoV5oN5oLU/KqUbbFecqmhkgHJBaYH9CpCwdU6Db3kl+o19CibTzR0C+iGYbQpM0kuOSctuczmcokUjLbP0FMtry5CVSDnaJ3LZao6Ve9yiYuimORiGEZ7M70o2mBbVEnqgjPtWER2fOhe8tzDoSpC3kln6OGeomkfuuvVB/SpXQ/XzjcMw2gj4gy9O18bnQvgubnoDEmCdzqgO3U7FmVAclFJFQYAF4cqcUAP/4ppND43LbnE74k19PL1V8Pg3Ydx5YZhGK0xWh6lK9eV8p03tv6DJEpF6o2H0uUiIpeIyFoRWS8i1zR5/TUicn/0zx0icsZs10zbFiEK6EJdQC9rBaChKBq+JxeVDUoiMLK5ldswDMM4rIyVx2pyC6R86KlZLqnGolhGrw/uB1FDl9D1/ingRcApwKtF5JSG0zYCz1XV04EPANfO+smkuqUAV0LJJecExC6XKT8M6HWSS+RyyQVRhi4CE0OtfJxhGMZhpW6OC9Q09CRjd5IMHaLRJ9S7XJbmTsPf+hYWdSya9fO8Wc+A84D1qroBQES+CVwKPJSsUfWO1Pl3AitbuG5qnkGYoVeAgpDc9Gh1HwBdua7ae6IM3Y3kpJIITOxp5eMMwzAOK3VzXCDlQ09n6LWuUSeybaf3FO3wFqETUpfYzkQrkssKIK1pDEbHZuJNwPebvSAiV4rIPSJyDzRk6Dj4InUul6GpYQAGigO18+IMXVOSi2XohmG0IXWjc2F6ho7U+c/jDD3dNRo4uZYcLtBaht5sG42mVxeRiwgD+rOava6q1xLJMR2rOzQd0B1xqEIouUQ3PVwaAeoDuuPlooWHyypbhm4YRpsyk+QSz69CJdlWE8CVWHKpBXkVr2UjXysBfRBYlXq+EtjaeJKInA58AXiRqrYUYb34poiLonGGHq5+uDw9oHvx+NzoBqcsoBuG0abMnKHXYl/cKYpI0lyUFEXFQR23xfy8NcnlbuB4EVktInngVcB16RNE5EjgO8AfqOq6Fj+7wbbohgFdSAL6nkhy6S/2187zIg09lKLCDH3SJBfDMNqLsl9myp+qbT8H03zoiiSb9kBNcklwcqGu3mJEnzWgq2oVeBtwM/Aw8B+qukZErhKRq6LT/gpYCHxaRO6LNfLZqMvQY8lF0pLLXjq8jrpiQC76eiKVSXKqlATT0A3DmFNufWQHj+0arzs2bY4LMFkKnXux3Cwp22KtKAoSB3Y3NGgHLWourUguqOqNwI0Nxz6bevxm4M0tfWL6w+tsi25Ncon+HA2XhuvkFgA3crk4+3ZQUKWcK8KwSS6GYcwNQaDc/O+fYOHqM3jnG1+ZHJ82xwX43gNbuAyoVOIg7iTTFAEiz0etU9TxOIAEfY6Hc9W5XFwqUl8UHZoapr/QX/eeuPXfGd9OXpVSRz9UJqAyefgWbhiGEbF1x07+Tj7DWVu/UXd82hwXYNOucJzueDSCSpBkE2hIF0XjDD2PIC1vtTnHAb0muTjiUUXopBQFdGFoaqhOPwfCLeoAb992ioFS6ugLXzDZxTCMOWD4oVvJiU++NETVr3VzNpNcBveEvTVjk3GATgX0uqJoSnLJToaeqvS6RXyBvmAkLIqK01Ry8VyXQIXcvm1hhh4PvTGni2EYc4C74VYA+hlh056J5Hij5FKq+mwfCV8fmwwDf5ih1wqh0zpFHQ8Radm22DYBHbdIFaHH3wsaoOIwNDk0PaA7go+DV9pLAaWUj+a8mNPFMIw54IhdYaP8Ihnh0R1jyfFYcoldLut3jidy8t6pgHBoeG0LOpCa5NJQFIU2n7YI6QE1IG4HVYHeYC9owITjUA7K0yQXz3UIolssiEc5/rpiGbphGIeboY0sKg8yLl0sZJS120eTl+Lt5/ryoSy8bscYTjQxcWjCx8ENPegpDT2RXNIaevSwlSx9bjN0N588diRPGYfu6jCgDEX2xOmSi6DRzeadHKVIXfra4I94523vPDwLNwzDAHgslFvW9F9MQaps3rYjeWm0PEqH10Eu8pw/sn0snCYLDE1Wahl6Q1FUhJoM43hJcG9FdWkbl4sjHiVx6akOgwYMRQ1E04qijoMfLbvgFSlHX2F+uHctP3j8B1SCymFavWEYv+mU1/2IQV3E5NLzANizYzB5bbQ8WtdUtHb7GCv6Qol4z0SVcJCt1GyLUVG0rrUoKopCBiSXdIbuOi4VEbr9YVBlODLbN8vQg1RALwVltNDHY+VhqlplcGwQwzCMQ45fxdn0E37qP40FR4TzCif3bqdcDZPMB7dtpVKuNUWu3T7Gkf1hQB+eqOIQFjzrMnSnYfs5J6Wht7CktimKuuJRQeishAF9Jskll5JcCl4nJb/Enq5+RqLNMDaMbDhMqzcM4zeaLffgVcb4afA0li4Lx10t0BE27t5Hqeqzfu8Gdg31snlogpGJCttGpli1INx9bfe+aiS5pDX0sCjqpCUXN5fo6u2voTupDB2PqsQBPUgC+rSiqFMriubz3ZT8Eus7az7PjSMbD8PKDcP4jWfjT1GEe93TOWJpuAXEIhll3Y4xvv/gIOrtwS8v5t/veoJ1O8MC6cooQ99XUVSna+ih5JLK0N1a0ttK+39Lrf+HCs9LF0VdfIGOyjAEVYYdmTbHBULJJdHQ8z2USzt4rJCHINzZyAK6YRiHheGNDLsLWdi/FKd7MQCLI+vizwfXIK5yyqLj+I+7N7OoO8zMV/aFPxUh8KMM3akvitaJ6E6ufju6WZhj22K6U9TFh9DWMznEkOtMk1sg7BRNMvRiHyW/xKOu0Bcopy863QK6YRiHh5FBtgYDHHdEN7gedAxwdMcEt63bxa+2rwXgFaefw559ZT7/kw30FD36O0PlIcBBhl5K5+QLp3WKTiuKkhnJJaWhOx6BRCse38mwI9PmuITvETTO0AthQH+MMsdWqqzuW83GkY0tzz0wDMN4sgQjg2yq9ocBHaBrMavy+/j14AhOfieC8LJTz+TohZ1sH53ixCU9SOTK83EY2rOaYnBUc9ticiDlcmmhLDq3Ad2r19CRaMnjOxhynGn6OTQ0FnUMUA2qrK+Oc3xpitXdqxivjLNrctdhugPDMH4jUYWRLWzThXUBfYkbNhYdsXCE5d3L6cp38przjwLgxKU9SadoQNjO7zop2yKC69RG6IJE89BrHzkbc5yhF5LHTnRTVYgCuswguYQaesnroZAPN48e1wrHliscU1wIWGHUMIxDzOQwjj9VH9C7F7MgCHdZ6+jcw+q+1QC84tyVLO8r8qzjFiVROd7cx5FmRdEUKcmllaLoHPvQa5KLJ2F9tiKCTo0w7Ey3LELoclGEfflFFNzaH4TjKhVWe+Ev1qyLhmE8GVSVD9zwEHdvmmU21EjY77KdhRy1sDM81rWYruow//zKpzFc2cIxfccAsKAzzx3vvpgXPW0ZBOGORX1dodslzNBrGrorKR+6SDIPHbLgQ3fTGXoc0B0mRCiLNJVccq4QqDCeW0g+1Zh0bLnCEX5AV64rydA3jGzg/Xe8n+37tvPwtlHW7xybdj3DMIyYXWMlvnj7Rv7j7s37P3F0CwBe/yoK0R4NdC1GpvZy3jE+Jb+UBPQ6IsllQeR6cRxpaCxqzNBrMa4VyWVObYtuXVE0/KVMFBZQrUzfHDpGRNhDHxSPSjL0gXwvA0EAk8Os7l2dZOgfvvvD3L7ldn70xI8ob3s1/XIaN/3Zcw71bRmGkVHWbA018LU79p/86cggAixavrp2sGsRABt2/hogkVzq3xgG9IE4QxfqbItOnW1RoqJo6yn6nGXoAkh6c9QoQ5/IDzAUbWLRLEMHuDK4hh+uujrJ0I+Nf3ETexKny5rda7h9y+1cfuLldHsD7Ov/LI9N/TDcMeT+/4B1N4dfm8wRYxhGxJqtYTK5dvsYflCLDQ/seoAHdz+YPB/f+TgVdVl9dDqgHwHAxj0PA+w3Qx+IMvQ6ySXaU9Spa/33akXRFiL6nGXoojQY6sOlTBUXMFwO9almGTrApNvLFAUKUVH1uIGTgOthYohjFh7D9Ruu55/v/Wd6872845x34O9ey+O7/pr8oltZ++MVHP1QbSrjnu4TWPh/7uKA3PuGYcxLHtoWZuilasCmPfs4dnFYl/urO/6KicoE33/593HEYWznJkbo57SVqaSzK2wu2rD3MQaKAywoLpj+ARpq6APdnUB5WlHUdVK2xZ6l0LcSqYZPg3bO0BcEQd3mqA7h41JhQZKhzxTQPVeo+gEFLwro/SdAoQ8mh1jdG/7FvGv7XfzBKX9Ap9fJLQ/u5diOi3ByI7DxWuhfjb7hRq4rvISF4+u4/96fHcpbNQwjI6zZOsqRA2GRc+32UHYZKY2wfu96tu7byn077wPAHx5kmy7k5GXh2JE7t93JY0G4r/GG8S3N5RZIMvSFPc2LonUul7fdDU9/cyK5tPW0xWXVamqnjlqGXir0zTjHJcZzHCqBsqpnFT25Hs5Zcg50DoSSy4LwF9mT6+GKk6/gvs172bJ3kstO/i0E2FDYychZf8yPJo7jAyMvAuC+H/+nNSMZxm84o1MVHt8zwe+esQRHlEeibD0O4gA3bLgBgMLENsYLSynmXCYqE7z1h2/ltXdcw/2FPBumdjWXWyAJ6IvqAno6DqZcLvkucNzsuFzSXzXybniD33OG2e65dCjT5rjE5KIMfVXPKu644g6OXXAsdC6EiT2s6lnFQHGAN572Rnrzvdz4wDZyrvCy00/kVC3yo45urpfn8slbH6U4sJyhnpM4YewX3PLQjqafZRjGbwYPbx1FvFG+u+cqlqz6BQ9HGfqvdv4KT1wuXnURN2+6mXJlin5/F9IXjsy9e/vdlIMygsOblx7BaNDE4fLoD2Fse1KzW9gdxrZZfejUaqRt31iU/st0Yu+5VPaew/+UH+VbvT0M7GfxnisM7SvXH+xcCBND5Jwct1x2C29+2ptRVW58YDvPPn4xfaOP8vzh7awtenz0p2v49eAIf/K841jwtEs411nHp276Vd2O3Y3sK1Wf6t0ahtHGrNk6QnHZtxmrDBN03ZVILr/a+UtOCRwu27Ke0fIo1z343+Tw6VwcdoD+dMtP6fA6+NZLvsUiDcNvXUAf2ghffzlcexFsvx+ARb1hQG8sioat/w0hPZZc2r31Py25eE6OqW2v4H1Lr2BptcpxwcxLu/ikJfzw4Z388y1ra1JJ/9Gw7dfw7bdQ2DuIiHD3pmG27J3kd047An789zy3HJ476tzP8r4iLz97Jc4JL8TDZ+meX/DlOzY1/bz/uW8LZ/7tLXz+J9awZBjzlVs2X4fXvZbTFp3GBFsZHN/I0MQED+56gDNH93DBxl8wUOjn+vXXA7B4xTGoKrdvuZ3zl57Pqt5V/Gu1nz+SAc5Zek7twptuD39WJ+GXXwVgoLsY9g1FzUMAiFDIOeTd+oDuJCn67PfQNpJLvOYzFp7PTZu38tHJfPP3AO97ySlcfu4qPnHrev7xpkfCoP7898CFb4eHr4d/eTp7vvVWrvnarazogpeuvQYeuYHjn/EOFhWX4HU/zJ9cdBx5z4GV56H5Hl49sI6/+97DfPjmRwhS5eR/u/Nx/uxb9yEifOyH69g5NnWofhuGYcwRW8a38FDp3+jWk/j4RR9HELze+/nB+nspa5XTSz5eUOWSvpO4f2INo46w4qjj2DS6iS3jW3jWimcBsKRrGW+b1Loudh7/WaggXHU7HHEqiIuXK7CwK4/rAMvOgOe/D466kD96zrF89PIz69ZWa/2f/T7msLFImloFtWsxLuCm5JhGXEf4h99/GjlP+NxtG1jSU+QPn7UaXvg3cMGfsO2Gv2PxQ//GdfIdcguPIvfoI3DJh5ALruIFd07x3fJ3efk5oWcUL48c81yet+3XvOrcd/GpHz/Gg1tGWTXQwfaRKX748E5+68QBPrjo+7z+zuX8v5vX8aHLTj9EvxPDMA43gQa89/b3EQTwgiVXc0TnEZy28CzuKz3AfevCOHT7+CU8gxs4buMeql0+/97bw1UDR3L7498H4Fkrw4BO12LY8WD9B2z6GRz1TOhbCW+6BXavg3wnFx63iGMWRaN3n/MXAKwagFWRyyYmG9MWG2J5MRf+4gp9S6LX9780xxE+cOlpvODkJfzD9x/m15v3AvCDzfDcNS/mj7o/ibf6GRRGNsErvgwXXAXA81Y9j1JQ4jvrv1O72HEXoyOb+eBzCrznxSdz18Yhvnf/Njbu3sfrn3EUnzn5fhbd+3G+1flP/OzeX/LglpGD8AswDOOwUxqHOz8DP/807A3b+7/xyDe4Z8fdlHa8hPNXHQfA7x57CW5hJ/eN3MrKis/N8lKe6DuPC3f8kuPH+vjcgj7WTu3m9i23s7pvNSu6wwIpXYtg365aBXPvEzDyBBwVBfxCN6w4G4CPv+os3v6C42dd8oEURec2Q0/xnBMW8/U3n8/q5Ysg19lSo4+I8JFXnM7vfOJ23vrvv+TK5xzD31z/EKet6OMjb7iYYtdroVqG1Jje85edz4XLL+RDd32I3nwvLznmJdxUzPHBI1fwijs/yJ++9Ku8+dmra4WJqVHGPnkpf7/qWC7dO8xXKh/mA/+zgi9e9YKwoNHA9zZ8jw0jG7j6rKuf2q/HMIyDh1+Bu78IP/1IGHABbn43m1aezceKYxzX/XR+NXIupy7vA+CFR7+QD/7igwx6VY4ZWcqVF5/GqZ0vR66/jffs7uDPO12uuf3dPDH6BJefdHntc7oWg1+GqRHoWACP3xEeP/rCJ7307NgWU7iOcOFx4SwEuha13Lm5oDPPJ684i+0jU/zV/6zhgmMG+Pqbz6e/KwriXr0W7zkeH7voY5y39Dze+7P38uZb3sw77/0nphyXfxv6JSPj2+uqzHr7R3lfF3zPq3D1Ef3s6hjij7e/l3/89k+nedcfGXqE9/7svVx7/7X8etevn/wvwzCMAyPwYcu9sPMRmBians7+8P1w07tg8Unwph8wdtVPue/CP+Y9up18tUzP6OV05T2OiuSORVvv5+xS6KTbw3P4g2cchRz3AgDOYQvvdxazfu96ykE50c8B6I6k3PiPxqbbobgg1M6fJJloLJqmuaTpWjyr5JLm7CP7+afLTucNzzyaL73h6XQX9v/Fo+gV+cTzP8FZR5zFL3f+kref/Xa+es5fMinCf976rtqJI1v42oP/yo+6OnnL097Cyp4j+dPly9jRuwXd+iae99Vn8/Zb386eyT1MVae45ifX0F/op6/Qx+fv/3zL6zcMowVUYd9ueOJOeOxWmAobf/SJXzD56efC558Pnz4f/mk1fOm3oRJ2brLnMfjF5wjOfA1rfucfueL+j/HMm1/DH2z9Hg/kPd63axfHrL+BP734+HD64UPXwb9fzkXVTlC48hkvCScq9q1IAvNFfSfw+8f/PgsKCzh3ybm1NS45FRC489Ph88cj/dx58qE2G5LLwAytsRD+UvbtPqDL/f7ZK/n9s1e2fH5nrpPP/9bnGSmNsKgj/GbwzF99gq/vvofXjQySz3Vy33+/kY8u6OaipRdw9VlXc8XJV/CGm97Ae4IKrsK5kzv4yRM/5pLBe1lSOJHHpx7jWP8dOMXN3Db4Xzy852FOXnhy8pmqysaRjeScHKt6Vx3Q/RnGbyLrhtcxWZ3kjCAHX38FjA4mrz2Ry/G5gWV0Vsc4YcLj5/7r6cgPcMUxU5zy6Gf4xXVv4b+PWElx0885uqeHT26apDxyBT1eP6878SqOW3A8G7f2klt/DX+Z/xa5ZS+Bb/4VPHIDrDiXV77ymxQ3Ps7lZ6QsiMe/AHaugd4V/PUz3sOfn/PndWO8WXIqPPNquOMTsOxMGNoA5/7hU/od1DL0Fs6dq5b3c889V++5557mL/pRE497eP/e3PHwf/FHd/0NfytLKYxu5f1dsLDQz7cuu5HefDizYffkbu7cdifPOOLprPvaXzMw9F+87YiVbM/7uKMX8nvl49k+spOfrb6V85ddwOcv+SSbxzZzw2PXc9Omm5PRvquChZy/p8xzZClnnnQ6/UeeBqufC9Hu4TGqyrX3X8u2fdv4o9P/iGXdyw7r78QwnhKqofzQ0Q/RhjZ+4LN+73qO6TuGXHRMVdm2bxuLi4vIbfhfePQWNp7+cq746Z8zXhnn7Iryxokq/ae9kr1dA9y292G+s/3nOIEi4lCWsCnQCxYxOb6EFR0b2JmbZIHk0OoUI64LKrj7nsneLS+EoJgs8ZUnunxox5XI1Ajke0L78zPeCvnOabfDxp/AV34XXvIxOPeNze+5WgqbiHY+BCi85cdJIfTJsG7HGP+7dieXP/1I+jpyiMi9qnpus3PbM6DPEarKZV+/kC2VEfY5Dmf2Hc9HXvgZlnQtmflN93yJiRv/gtsWruTi0b3kS6ED5iMLFvOV/g6OKXexIb8PUeXMUpVnTbo4wRjf6+lgfT5PZ6BcNjrGsyYneaSQ5+f5AXL+clYWLqW65GzuGv4Em5z7ERVcx+O1p7yWV55wGasmx6nuWsf6yR5u2y30LVzFy846JnELzcZUxcdzBM9tmzKKkUHK1RJbh9cRTI5AaZScV6AwcCKP7lYqa69nYO0XyU8+TiGAQkc/P+5ZwJe9Cttdn4LmOav/eZy6/Dh+PHgTG0Y3cKLm+OjgJhb4AVesWM5osZvXlYRvMMYOr372U2no6ZzXfzmff+2zeWjPQ9yz4x4e2fMI92x7kL374LXDu7h6Yj27goV884KvcsWzjmFJ1zLu2jjE4PAEFV/Jew4vOX0ZxSduC/XuC/4kmWvelCCAX34ZTns5FPtmPm/7g/D5i8AtwLs2HdTk1AL6AXDTo9/l/97xV7z2hMv58/PfRS61CceMrLsFbv0ALD0dTn0ZuHm23/FpLis/QGcAF071cnz1JPpLVToqw/g9yznhBW9keHEXn3/gK9w2+COUaAqbL+xxlQW+z1GVKr8uFnjr8F4uHdvHJ/oX8L3uLlRgZaXCsZUq63M5tuQ8XFWOLSvHBJ34rsO4o3hSYLF3EmW5gHzpPsaqd7LFGccNOhkvL2SSVZxx7Fm88JSTeWLwAR597Kf4U3tZVDiZZUteSO/yEykU9xHIONt27kY3/oxydZQ9i1dR7snRX+xjsdvLKnKc3r2EBW5ArqMH7VnOHi9Hd7GPolec8de2e3I3D+15CEE4uecoFg0/AV4HdC2E7qWQa3ivX4HyvlAbLXRDoafpdcvVAEVrO8mkUFVK1YCC50xvsU6dM9NrM7JvN+S7IVec/n5VKI2F62123fI+GN8B3UvZJ8pUdYqCW8CTPMVcfVF/suwzVfFRDWDvZgbHNvHI6DqqrrB66ems6D0SUYdH1z/E0O6tLF6+mqXLl7Fh9zg3PLCFuzbuZtVAgdNWdHFSl8vi4b0Uhh5lQXee4YWwNhiinxydk5Ab2UNu7yaKk9t5vLOHx3t72eH4jE+OUqlOsNP12eI5+Af4uzp2Cn5v3wQPFpRbOzspO8KZUyWeOTnJ13p7mSKPlhejxW18YfsOzp4q89kVf8uP8h0s6u7ghEVL+M87J8hJDze87dn0dU7/b7TiB1z/s/s47ra3svNpV/GCl73+gNZ4UHjgv2ByGM57y0G97FMO6CJyCfBxwAW+oKr/2PC6RK+/GJgA3qCqv9zfNds1oAMMTw3POOnxQJgc30Gh2I/jzdz1CrB1fCsbRjZw8sDJLOxYyANb7uRTd3+YO0ce5S9XvZhXnnkllYkRNvzkm+x84kfc1tXNPZ0FhnMVji0s4tzOXvaM7uTXE9sYdKfIK3T7MOkG7PZqGXhnoCwvd6DOJMNukEy1jHFUEWjpP9BcoFRSts1iEHBGqUwAPJLPMxZl/sUAOgPBI8AlwFXFASbEqVsbwOJqlX4/oEsDen2lP+hAK/1UKVPxRhj3KgTRhi6KMEUH+5wuSo5Qdnyq+LhBQMEPA3rZEXwR+v2AZdUyXVphl+sx5Lr0+sLKqkuf5hnMC4/nfKbw6fV9FvgVpsRjn5ujLB6KA+pSkYCSVKlKQGe1E7fcywK/ynJ3OzkZZ5vn8Xguz4gjdKjQqS6OBlSkSknAVcFRFzfwWBg4HBH4eDrJlFNlyHXY7nrJ7y1macVndSWgJ3DY6OXYkgNfAvIa4AtMPIViG0CPH3BqucS6fH7avw+NeKosq/pI4AJ5urWD3lI3zlQP+4Ii+7RIzilzXO84i4sTFBefRM+Rz6bs5/j5hm38anAniwtH83cv+h3OWdVHMHgvG+7+D/bseQKneCy78kfyYM8x3DjyL+ypbOJYeS0XDo6wu1rgrs7nUvAcHt8zwWTFJ+86fPuPn8nTVu4nS56nPKWALiIusA54ITAI3A28WlUfSp3zYuBqwoB+PvBxVT1/f9dt54DeLkxVp/ab4TajXA3YV6oyUfEhCJgauoP7N97EikWnctZpryGXi1qShzZS3nIP96+9k8e2rqNj0ek8/dmvY+HSo3how83c/dgP8PduZfHoThZPjjC19CwKJ7+Qrp6ldG24n55Nv2Dc6+LxzsWs9xzWVLazvrIFUWV5tYvlZcHTMSqMMoHPJHnGNYdPGJELqpxQqXBOaYQp6eCOjuWszecZDyap6iTqTjCRm6LkhP9+Lghc+ugiUBdfBUcrFHWSok7SGfh0B0pOYdLJM+XmcUQo+D6u+ux28+z0HMoC/eToU4dhLTHolqkILKjC6rLSETiM5PJMeC65wKfLL1MMKqgEBAR0qNIdBOQUtnoum3Ie445DQV2EIguCAiv9gCXVSaa0yj7xqUiOivZQkW56ZYxOHWaKCju8PLtcByFHUTrpcLvpKwuLSmU6NIBcDt9z2MIET8gEE1JhpS8cUy1TlCJjhQHKuX6Weks40ltOoVRiz+ijjJe34Rd76BhYRU/vQiaGd+KP7KDbVZb3d1PIFXCcPBV12ewrj+TKrCvvoD+3jMWTx5Hfu5Ce/g46B5Tu/k76uwt05FxcfzE79vQyOqk898TFnLikp+5byFTFZ3iiTGfeo6+jhW+1+2GyOsnaobWcsfiMad+UgkDZPDxBoLB6UddT+pys8lQD+jOA96vqb0fP3w2gqv+QOudzwP+q6jei52uB56nqtpmuawHdmIlS1adcDegueAyXhim6RTpzTQpUTxE/8BmvjNNX6Es8vjNKLfF/JyKhjjq1NxyHWuwL7WyGcZjYX0BvRalfAaS3wB4kzMJnO2cFUBfQReRK4MroaUlEGoYeZJ5FwIH5Ldsbu5/2Zr7dD8y/ezoU93PUTC+0EtCbpSyNaX0r56Cq1wLXAojIPTP9lckq8+2e7H7am/l2PzD/7ulw308rFZVBIN0FsxLY+iTOMQzDMA4hrQT0u4HjRWS1iOSBVwHXNZxzHfA6CbkAGNmffm4YhmEcfGaVXFS1KiJvA24mtC1+SVXXiMhV0eufBW4kdLisJ7QtztBCVce1T3rV7ct8uye7n/Zmvt0PzL97Oqz3M2eNRYZhGMbBxfq+DcMw5gkW0A3DMOYJcxLQReQSEVkrIutF5Jq5WMNTQURWiciPReRhEVkjIm+Pjg+IyA9E5NHo51OfH3AYERFXRH4lIjdEz7N+PwtE5L9E5JHo/6tnZPmeROQd0b9vD4rIN0SkmKX7EZEvicjOdP/J/tYvIu+OYsRaEfntuVn1/pnhnj4c/Tt3v4h8V0QWpF47pPd02AN6NErgU8CLgFOAV4vIKYd7HU+RKvB/VPVk4ALgrdE9XAP8SFWPB34UPc8SbwceTj3P+v18HLhJVU8CziC8t0zek4isAP4UOFdVTyM0KLyKbN3Pl4FLGo41XX/039OrgFOj93w6ih3txpeZfk8/AE5T1dMJx6a8Gw7PPc1Fhn4esF5VN6hqGfgmcOkcrONJo6rb4uFjqjpGGChWEN7HV6LTvgK8bE4W+CQQkZXA7wBfSB3O8v30As8BvgigqmVV3UuG74nQldYhIh7QSdjrkZn7UdWfAEMNh2da/6XAN1W1pKobCR105x2OdR4Ize5JVW9R1WhTB+4k7MuBw3BPcxHQZxoTkElE5GjgLOAXwJLYfx/9PGIOl3agfAx4J0RzfEOyfD/HALuAf41kpC+ISBcZvSdV3QJ8BHiCcKTGiKreQkbvJ8VM658vceIPge9Hjw/5Pc1FQG9pTEAWEJFu4NvAn6nq6Fyv58kiIi8BdqrqvXO9loOIB5wNfEZVzwL20d5yxH6JtOVLgdXAcqBLRF47t6s6pGQ+TojIewjl2a/Hh5qcdlDvaS4C+rwYEyAiOcJg/nVV/U50eIeILIteXwbsnKv1HSAXAi8VkU2EEtjzReTfyO79QPjv2aCq/iJ6/l+EAT6r9/QCYKOq7lLVCvAd4Jlk935iZlp/puOEiLweeAnwGq01+xzye5qLgN7KKIG2RsIZq18EHlbVf069dB0Qb43yeuB/Dvfangyq+m5VXamqRxP+/3Grqr6WjN4PgKpuBzaLyInRoYuBh8juPT0BXCAindG/fxcT1m6yej8xM63/OuBVIlIQkdXA8cBdc7C+A0bCDYHeBbxUVSdSLx36e1LVw/4P4ZiAdcBjwHvmYg1Pcf3PIvyqdD9wX/TPi4GFhJX6R6OfA3O91idxb88DbogeZ/p+gDOBe6L/n/4b6M/yPQF/AzwCPAh8DShk6X6AbxDq/xXCbPVN+1s/8J4oRqwFXjTX6z+Ae1pPqJXHseGzh+uerPXfMAxjnmCdooZhGPMEC+iGYRjzBAvohmEY8wQL6IZhGPMEC+iGYRjzBAvohmEY8wQL6IZhGPOE/w/DIYqnpSOGqwAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "from pylab import *\n", "%matplotlib inline\n", "\n", "plot(fxbin[0])\n", "plot(fxbin[1])\n", "plot(fxbin[2])\n", "xlim([0,128])\n", "ylim([0,1e-7])\n", "show()" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "def smfun(x):\n", " if (x>0):\n", " return ((x-1.)/log(x))**(1.5)\n", " else:\n", " return 0.\n", "vsmfun = vectorize(smfun)\n", "\n", "def Smoothen(fxbin):\n", " (ndim,nbins) = shape(fxbin)\n", " final = zeros(shape(fxbin))\n", " for idim in range(ndim):\n", " fxb = copy(fxbin[idim,:])\n", " #**** smooth the f^2 value stored for each bin ****\n", " # f[i] <- (f[i+1]+f[i]+f[i-1])/3.\n", " fxb[:nbins-1] += fxbin[idim,1:nbins]\n", " fxb[1:nbins] += fxbin[idim,:nbins-1]\n", " fxb[1:nbins-1] *= 1/3.\n", " fxb[0] *= 1/2.\n", " fxb[nbins-1] *= 1/2.\n", " norm = sum(fxb)\n", " if( norm == 0 ):\n", " print ('ERROR can not refine the grid with zero grid function')\n", " return # can not refine the grid if the function is zero.\n", " fxb *= 1.0/norm # we normalize the function.\n", " # Note that normalization is such that the sum is 1.\n", " final[idim,:] = vsmfun(fxb)\n", " return final" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "from pylab import *\n", "%matplotlib inline\n", "\n", "imp = Smoothen(fxbin)\n", "\n", "plot(imp[0])\n", "plot(imp[1])\n", "plot(imp[2])\n", "xlim([0,128])\n", "show()" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "class Grid:\n", " \"\"\"Contains the grid points g_n(x) with x=[0...1], and g=[0...1]\n", " for Vegas integration. There are n-dim g_n functions.\n", " Constraints : g(0)=0 and g(1)=1.\n", " \"\"\"\n", " def __init__(self, ndim, nbins):\n", " self.g = zeros((ndim,nbins+1)) \n", " # a bit dirty trick: We will later use also g[-1] in interpolation, which should be set to zero, hence\n", " # we allocate dimension nbins+1, rather than nbinx\n", " self.ndim=ndim\n", " self.nbins=nbins\n", " # At the beginning we set g(x)=x\n", " # The grid-points are x_0 = 1/N, x_1 = 2/N, ... x_{N-1}=1.0. \n", " # Note that g(0)=0, and we skip this point on the mesh.\n", " for idim in range(ndim):\n", " self.g[idim,:nbins] = arange(1,nbins+1)/float(nbins)\n", " \n", " def RefineGrid(self, imp):\n", " (ndim,nbins) = shape(imp)\n", " gnew = zeros((ndim,nbins+1))\n", " for idim in range(ndim):\n", " avgperbin = sum(imp[idim,:])/nbins\n", " #**** redefine the size of each bin ****\n", " newgrid = zeros(nbins)\n", " cur=0.0\n", " newcur=0.0\n", " thisbin = 0.0\n", " ibin = -1\n", " # we are trying to determine\n", " # Int[ f(g) dg, {g, g_{i-1},g_i}] == I/N_g\n", " # where I == avgperbin\n", " for newbin in range(nbins-1): # all but the last bin, which is 1.0\n", " while (thisbin < avgperbin) :\n", " ibin+=1\n", " thisbin += imp[idim,ibin]\n", " prev = cur\n", " cur = self.g[idim,ibin]\n", " # Explanation is in order : \n", " # prev -- g^{old}_{l-1}\n", " # cur -- g^{old}_l\n", " # thisbin -- Sm = f_{l-k}+.... +f_{l-2}+f_{l-1}+f_l\n", " # we know that Sm is just a bit more than we need, i.e., I/N_g, hence we need to compute how much more\n", " # using linear interpolation :\n", " # g^{new} = g_l - (g_l-g_{l-1}) * (f_{l-k}+....+f_{l-2}+f_{l-1}+f_l - I/N_g)/f_l\n", " # clearly\n", " # if I/N_g == f_{l-k}+....+f_{l-2}+f_{l-1}+f_l\n", " # we will get g^{new} = g_l\n", " # and if I/N_g == f_{l-k}+....+f_{l-2}+f_{l-1}\n", " # we will get g^{new} = g_{l-1}\n", " # and if I/N_g is between the two possibilities, we will get linear interpolation between\n", " # g_{l-1} and g_l\n", " # \n", " thisbin -= avgperbin # thisbin <- (f_{l-k}+....+f_{l-2}+f_{l-1}+f_l - I/N_g)\n", " delta = (cur - prev)*thisbin # delta <- (g_l-g_{l-1})*(f_{l-k}+....+f_{l-2}+f_{l-1}+f_l - I/N_g)\n", " # cur is the closest point from the old mesh, while delta/imp is the correction using linear interpolation.\n", " newgrid[newbin] = cur - delta/imp[idim,ibin] \n", "\n", " newgrid[nbins-1]=1.0\n", " gnew[idim,:nbins]= newgrid\n", " self.g = gnew\n", " return gnew" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Update the class Grid, so that it can refine the grid" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vegas parameters:\n", " ndim = 3\n", " unit = 3.141592653589793\n", " maxeval = 200000\n", " nstart = 10000\n", " nincrease = 5000\n", " nbins = 128\n", " nbaths = 1000\n", "\n", "1.4824486908802832 +- 0.068853203999754 exact= 1.3932\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAD4CAYAAAD8Zh1EAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAAAsTAAALEwEAmpwYAABBOElEQVR4nO3dd3yN5//H8deVKZKQRMwEsfeKGLVLlbZ0V43aqqjVSatLv1VUtVZLtbW3DqW09lYjsXczSIIsiUyZ5/r9cae/KjmRQ8j6PB+PPOScc51zXRfxdrvuayitNUIIIQo+q7xugBBCiNwhgS6EEIWEBLoQQhQSEuhCCFFISKALIUQhYZNXFbu7u2svL6+8ql4IIQokPz+/KK116axey7NA9/LywtfXN6+qF0KIAkkpddncazLkIoQQhYQEuhBCFBIS6EIIUUhIoAshRCEhgS6EEIXEXQNdKbVAKRWhlDpt5nWllJqllPJXSp1USnnnfjOFEELcTU6u0BcBXbN5/QmgRubXUGDu/TdLCCGEpe46D11rvUcp5ZVNkWeAJdrYh/egUspFKVVea30ttxophBCFmUmbiE+NJz41nrjUOOJS44hPjSc6KZpAf19uhJ9ifK/luDqWyvZzcmNhkQcQcsvj0Mzn7gh0pdRQjKt4KlWqlAtVCyFE/qC15mb6TWJSYriRfIMbKcbX/4d0ShzxafHEpfwb2P+Ed0JqAhrzZ1NY22ievvAXrb27ZduG3Ah0lcVzWbZMaz0fmA/g4+MjJ2sIIfIlrTVJ6UnEJMcQmxJLTErMf76/NbBjUmKITTaeTzOlmf3MYtbFKGHnjLONAyWULa4mK8qm2VMstSTFU+xxTknCNTWBiukxuOp0bEx2RDs2wbH20zRq8zIOjiXu2u7cCPRQoOItjz2Bq7nwuUIIkauS05O5lniNawnXuJp4lbDEMGKSY4xQvi2szYWzlbKipF1JXIq54GLvgqeTJw1K1aeklS2uJoWLKQOXtBRckhMpnngDuxtROMaH45QUTvH0i3d8Xoq2JQJXbtiUIrlYVTLcqlKy0RNUb9IRK1s7i/qXG4G+HhiplFoFtABiZfxcCJEXtNbEpsQSHB9McHwwIfEhhMSFGL/Gh3A9+fp/ylspK1zsXShpXxJXe1cqOlWkgXsDXOxdcLV3NZ5XNrikp+OSdhPX5EScE2OwSgiD+DCICMYUdwiVGIHSpv98dgaKSO1CuHbFX7sSTmWSi5UB5/LYu3lQonQl3CtUpmJ5Dyq4OlDR+v5nkd810JVSK4EOgLtSKhT4GLDN/M2bB2wCngT8gSRg4H23SgghciAyKRK/CD+Ohh/lZORJguOCiU+L/0+Zco7lqORcifYV21PBsQIVnCpQ3rE8HnYulE7PwCYxAuKvZX6FwfXLEHfw38cZKXfUm2hdkijlSmi6C6HptQmnJRHalXDcMDmWw6GUJ65lKlDZvQRV3B2p5u5Ie9fi2Nk82KU/Kq8Oifbx8dGy26IQwhKxKbHsu7KPA1cPcDT8KKEJoQA42DjQwL0BVUpWoZJzJSqVqEQl2xJ4RIdgH3ftlsDODOm4a5Aaf8fnazsnkuzLcMPajXDtSkh6SfxvOhOQ7Ex4ZmBH6pK4lHDGq5QjVdyNL6/MXyu5FaeYrfUD/T1QSvlprX2yei3Pts8VQoi70VoTGBvI7tDd7A7ZzfHI45i0CRd7F7zLeNOzdk+alm1KLbda2KbehMsH4NJeCJoPYaf5//kZ1nbgXA6cy0OZOlCt0/8/TnYozaEoezYEwR8X4kmMywCglKOdEdZejtRzd+SpUo54uRfHq5Qjjvb5MzrzZ6uEEEVaWGIYvwf+zm/+v3Ep7hIAddzq8GqDV2nv2Z567vWwUlbGlfb532Hj+3BpH+gMsLaHis3h0Qng1Qbca0JxN1D/TsjTWnM4KJqF+y+x62IEyWk3cXO0o3ujCnStXw7vyq6UKGabR72/dxLoQoh8ITk9mR3BO/gt4Df+uvoXGo13GW/61u1LO892lHMsZxS8HgAHZsO5DRB6xHjOvSa0Hg3VOoJnc7AtlmUdWmt2Xojgm50B+F2Owc3Rjh4+FelavxzNvdywyYUbk3lJAl0IkWe01pyIPME6/3VsvrSZhLQEKjhW4LVGr/F01aepWCJzRnTU33BkkRHi4ZnbSpVvDB0/hDrdoXStbOtJzzCx8dQ15u4K4HxYPB4uDkx8uh49fCriYPdgx7wfJgl0IcRDF5YYxoaADfwW8BuX4y7jYONA58qdeabaM/iU8zGGU2KvGFfip9bCtROAgkqPQJfJUPspcK1813pS0jP42e8K3+0J4PL1JKqVduTLlxrxTOMK2Bbwq/GsSKALIR6Km+k32R68nd/8f+PQtUNoND5lfRjSYAidK3fG0dYR0m7CyTVwbJkxJo6GCt7Q5XOo9zyUKJ+juhJT0llxKJgf9gUSHpdCQ8+SzHulKY/XLYuVVVaL2wsHCXQhxAOVkJrAqgurWHxmMTdSbuDh5MGwRsPoXq07FZ3/GVLxB7+FcHw53IwBt2rQ4T1o8CKUqpbjupJS01mwL4jv9wYRezONR6qW4suXGtGmujtKFd4g/4cEuhDigUgzpbHy3Eq+O/kdcalxtPVoy4B6A/4dUtEazm+CQ3MhaA9Y2Rjj4T6DwKvtf2al3E16hok1vqHM2HaRiPgUOtUuw+sdq+NdyfUB9jD/kUAXQuS6w9cO8/mhzwmIDaB1hdaMajKKeu71jBdNJjj7K+z50rjBWbKicXOzSV9wLmtRPVprtpwN54s/zxMQmUjTyq5828cbHy+3B9Cr/E8CXQiRa6JuRvGl75dsDNyIh5MHszvOpr1ne2O4w5QBp3+BvV9C5HkoVR2enQcNXgJry6PI91I0k/84j9/lGKqWduS7vsYYeVEYWjFHAl0Icd9M2sTPf//M135fczP9Jq81fI0hDYZQzKaYMbRycTNs+QCiLkLpOvDCj1DvObCyfMpgUFQikzedY8vZcEo72/P5cw3o4eNZ4OeQ5wYJdCHEfbkQfYH/HfwfJyJP0KxcMz5o+QFVS1Y1Xgw/A5snQOBO40bnS4uhztNgZXn43kzN4Jud/szfE4itteKtzjUZ3LYKxe0kxv4hvxNCiHuSlJbEvBPzWHJ2CSXsSjCpzSS6V+1uDHkkRMDOSXB0CdiXgK5TwGcw2Fi2vzf8O07+6YazXLlxk+eaePDeE7UpUyLr1aBFmQS6EMJiu0J28fmhz7mWeI0XarzAWO+xuBRzMYZXji6Fze9DWhI0fw3av2vspXIPLl9P5JP1Z9h5IZKaZZ1YPbQlLapmf65mUSaBLoTIsbDEMKYcnsL24O1Ud6nO4q6L8S7rbbwYdw02jIa/t0DlNtB9BrjXuKd6ktMy+HZXAPN2B2BrpfjgqTr0b+VVKFd35iYJdCHEXaWb0ll5fiVzjs3BpE2M9R5Lv7r9sLW2Na7KT66GP96F9FToOhWaD72ncXKAbWfD+WTDGUJjbvJ0owpMeKoOZWV4JUck0IUQ2ToVeYr/Hfwf56LP0dajLe+3eB9PZ0/jxYRI2DAGLmyEii3g2bkWrey8VfD1JCZuOMP28xHUKOPEyldb8kg1GV6xhAS6ECJL8anxzDo6i9UXVlPaoTTT20+nc+XO/87z9t8Ovw6D5Fh4/DNoOeKepiGmppuYvyeAWTv8sbVSTHiyDgNay/DKvZBAF0LcYculLUw+PJno5Gh61+nNyMYjcbJzMl5MT4XtE+GvOcac8n7roGy9e6rnUOB1Jqw7jX9EAk81KM+H3epSrqQMr9wrCXQhxP+LSY5h0qFJbL60mTpudZjTaQ71St0S1lH+8PMgYztbn8HQZRLYOlhcT3RiKpM3nWOtXyierg4sHNCMR2uXycWeFE0S6EIIAHYE72DiXxOJS41jdJPRDKw/EBurzIjQ2tjS9o9xxlzyl5dDnW73VM8fp64xYd1p4m6mMbxDNUZ3rFGoDpnISxLoQhRxsSmxTD08lQ2BG6jtVpv5nedTy+2WE4ASo4wbn+d/N3ZBfO47KOlhcT3xyWlM3HCWn/xCaehZkmmvtqRWOedc7ImQQBeiCNsbupdPDnzC9eTrDGs0jKENhhpTEf9xcTP89nrmjc9JmTc+Lb9Z6XspmjfWHOdKzE1Gd6zOqE415KbnAyCBLkQRlJCawJe+X/Lz3z9TrWQ1ZnWc9e/2tgCpicYeLH4LoUw96PfbPd34TMswMWv733yz0x8PVwfWDnuEppWL5ta2D4MEuhBFjF+4HxP2TeBa4jUG1h/I641fx97a/t8CV4/Dz4PhegC0GmXsVW5jb/bzzAmMTOCN1cc5ERrLS009+ah7XZyL2d79jeKeSaALUUSkZaTxzfFvWHB6AR5OHizuupjGZRr/W8BkMk4P2voxOJaG/uuhSjuL69Fas+JwMJ/9fg57Wyu+7ePNkw1ydhaouD8S6EIUAf4x/ry37z3OR5/nhRov8E6zd4xDmf+REAnrhoP/Vqj1FDwz55421IpKSGHcTyfZfj6CtjXcmfZiI5lX/hBJoAtRiJm0iRXnVvC139c42Tkx89GZdKzU8b+Fbl3x+eSX0GyIRed5/mPn+Qje+ekEccnpfNStLgNaeWFlVXRPD8oLEuhCFFJhiWF8uP9DDl47SHvP9nzS6hPcHdz/LWAyGcfB7fwcSte+5xWfKekZfPHnBX7cF0Ttcs4sHyLTEfOKBLoQhdDWy1v5+MDHpJvS+eiRj3ixxov/PWszOda4Kr+wCRq+DN1mgF1xi+sJikpk1MqjnL4Sx4BWXox/ojbFbGWRUF6RQBeiEEnJSOHLI1+y6sIq6peqz5R2U6hcovJ/C0Wch9V9IOYSPPGFsdXtPQyx/HoslA9+PY2NtRXz+zbl8XrlcqcT4p7lKNCVUl2BmYA18IPWesptr5cElgGVMj/zS631wlxuqxAiG5fjLvPO7nc4F32O/nX7M8Z7zH8XCQGcWQfrRoCdI/TfAJVbWVxPYko6H/12hp+PhtLMy5WZPZtQwcXy/VxE7rtroCulrIFvgM5AKHBEKbVea332lmKvA2e11t2VUqWBC0qp5Vrr1AfSaiHEf/wR9AcT/5qIjZUNszvOpkPFDv8tYMqA7Z/C/hng2Qx6LIESFSyu58zVWEatOEbQ9URGd6rB6I7VsZEVn/lGTq7QmwP+WutAAKXUKuAZ4NZA14CzMgbpnIBoID2X2yqEuE1qRipTD09lzcU1NC7dmC/afUF5p9vmfCdeN3ZIDNwFPoOMA5vvYaHQikPBfLL+DK6OtqwYIodP5Ec5CXQPIOSWx6FAi9vKzAHWA1cBZ+BlrbXp9g9SSg0FhgJUqlTpXtorhMgUlhjGGzvf4PT10wysP5BRTUZha3XbEMvV47C6LySEw9NzwLuvxfWkppuYuOEMyw8F075mab5+uTFujna50wmRq3IS6FndLdG3Pe4CHAc6AtWArUqpvVrruP+8Sev5wHwAHx+f2z9DCJFDB68d5N3d75JqSmVGhxl0qtzpzkLHV8LvY6G4Owz6AzyaWlzP9YQUhi8/yuGgaF5rX5V3u9TGWuaW51s5CfRQoOItjz0xrsRvNRCYorXWgL9SKgioDRzOlVYKIQBjWf2C0wuYdWwWVUpU4etHv6ZKySr/LZSeCpvfhyPfG9vdvrQIHN2z/LzsnLkay9AlfkQlpDDj5cY828TyLXPFw5WTQD8C1FBKVQGuAD2B3reVCQY6AXuVUmWBWkBgbjZUiKIuITWBD/Z/wPbg7XTx6sKnrT6luO1tc8fjw2BNfwg5aGys1ekTsLZ8dvLGk9d4e+0JXIrbsnbYIzT0dMmVPogH665/0lrrdKXUSGAzxrTFBVrrM0qpYZmvzwP+ByxSSp3CGKIZp7WOeoDtFqJICbgRwNidYwmJD+Edn3foW7fvfxcKAVw5Cit7QUocvLgA6r9gcT0mk+brbReZvcOfppVdmfuKN2WcZS+WgiJH/3RrrTcBm257bt4t318FHs/dpgkhAP689Ccf7f8IBxsHvn/8e5qVa3ZnoTPrjJWfTqWh77Z7WsKfkJLOG6uPs/VsOC/7VOTTZ+thbyOrPgsSWSkqRD6Vbkrna7+vWXJ2CY1KN2J6++mUdSz730Jaw76vjDnmns2h5woj1C10+Xoiry7xJSAykU+616V/K687/wcg8j0JdCHyoejkaN7a9Ra+4b70qt2Ld3zeuXPVZ3qKcdbniZXQ4CVjWqKt5cMj+/2jGLH8KErBkkHNaV3d8huoIn+QQBcin/k75m9G7RhF1M0oPm/zOd2rdb+zUOJ1Yz+W4L+gw/vQ/l2L92PRWrPowCU+23iOaqUd+b6fD5VLOd79jSLfkkAXIh/ZE7qHd3Ybh08s6rqI+u717ywUeQFW9IC4a/DCj9DgRYvrSUnP4MN1p1njG0rnumX5+uXGONlLHBR08icoRD6gtWbJ2SVM951ObbfazO44+87xcoCAHbBmANjYwYCNUDGLG6R3ERGfzPBlR/G7HMOojtV547GachBFISGBLkQeS8tI49ODn7LOfx2dK3dmUptJONhksXvhkR9h0zvGYRS9V4GL5dtnnAy9wWtL/biRlMY3vb15qqGc9VmYSKALkYdikmMYu3MsRyOO8lrD1xjReARW6rbdC00ZsOUDOPgt1HjcGGYpVsLiutafuMo7a0/g7mTPT8MfoV6FkrnUC5FfSKALkUf8Y/wZuWMkkUmRTG07lSerPnlnoZQE+HkwXPwTWo6Axz8DK8vmht+6WKiZlytzX2mKu5Pluy2K/E8CXYg8sCd0D+/ueRcHGwcWdl1Iw9IN7ywUd824+Rl+2ji8ufmrFteTmJLOm2uOs/mMsVjof8/Wx85G9i8vrCTQhXiItNYsPbuU6X7Tqelak9kdZ1POMYuj28JOwYqXjbM/e62GmpYvxA6NSWLIYl8uhsfzUbe6DGwti4UKOwl0IR6StIw0Jh2axM9//8xjlR5jUptJd26uBfD3NljbH+xLwKA/oVwDi+vyvRTNa0v9SM0wsXBgc9rXtHz1qCh4JNCFeAhikmN4c9eb+Ib78mqDVxnZZOSdNz/h35ksZetC7zX3dEzcGt8QJvx6Cg8XB37o34zqZZxyoQeiIJBAF+IBC7gRwMjtI4lIimBy28l0q9rtzkImE2z9EP6aAzW6GLsl2lsWxBkmzeRN5/hhXxCtq5fim97euBSXk4WKEgl0IR6gfVf28c7ud7C3tmdB1wU0Kt3ozkKpSfDrUDi3AZq9apz5aeEe5jdTMxi7+hibz4TT75HKfNitLrZyeHORI4EuxAOgtWb5ueVM851GDZcazO44+87DmwESImBlT2Mv865ToMUwi/dkiUpIYchiX06E3uCjbnUZ1KbK3d8kCiUJdCFyWZopjc8Pfc5PF3+iY8WOTG47OeubnxHnYflLkBQFPZdD7acsriswMoEBC48QHpfM3D5N6Vo/ixkzosiQQBciF8WmxPLGrjc4EnaEIQ2GMKrJqKxvfl7aByt7G9vdDtgIHt4W1+V7KZohS3yxUoqVQ1viXck1F3ogCjIJdCFySUh8CCO2jeBKwhXz294CnPkVfhkKrlXglZ/uaU+WjSev8caa43i4OLBoYDPZ9lYAEuhC5IpTkacYuWMk6aZ0vn/8e5qWbZp1wUPfwR/joGIL6LUSirtZVI/Wmh/2BjFp0zmaVnbl+34+uDnKTBZhkEAX4j7tCN7BuD3jKOVQirmPzaVKySxuSppMsH0i7J8BtbvBCz+AbRY7KmYjw6T5dMMZFv91mScblOOrHo0pZitnfop/SaALcR9WnFvBlMNTqFeqHrM7zcbdIYvj29JTYf1IOLkafAbDk9Ms3mArKTWd0SuPs+1cOEPbVWV819qyh7m4gwS6EPfApE185fsVi88upkPFDkxtOzXrmSwp8bCmn3EwRccPoO3bFk9LjIxPYcjiI5y6EsvEp+vRv5VX7nRCFDoS6EJYKDk9mff3vc/Wy1vpVbsX45qNwzqrK+74cFjxEoSdNg5w9u5rcV0BkQkMWHiYyPgUvuvrQ+e6WZxiJEQmCXQhLBCTHMPoHaM5Hnmct33epl/dflnvYHg9AJY+B4mRxs3Pml0srutwUDSvLvHF1lqxeugjNKrocv8dEIWaBLoQORQSF8Lw7cO5lnCN6e2n87iXmS1tQ/2MK3OA/r+Dp5kZL9nYcOIqb605gaebA4sHNqeiWxbDOULcRgJdiBw4EXmCUdtHodH80OUHmpRpknXBi5th7QBwLA19f4VS1SyqR2vNvN2BTP3zPM293Jjfr6lssCVyTAJdiLvYfnk74/aOo7RDaeY+Nhevkl5ZF/RbDL+/AeXqQ++14GzZeHeGSfPx+tMsOxhM90YVmPZiQ5mWKCwigS5ENpafW87Uw1Np4N6A2Z1m41Ysi4VAWsOuKbB7ClTrBD0Wg72zRfUkp2UwdtVx/jwTxmvtqzKui0xLFJaTQBciCyZt4kvfL1l6dimdKnVictvJONhksRAoIx1+HwvHlkKj3vD0LLC2taiu2JtpvLrEl8NB0XzYrS6DZbdEcY8k0IW4TXJ6Mu/tfY9twdvoU6cP7/i8k/W0xNREY7z87y3Q7h14dILFc8zD45Lpv+AwAZEJzOrVhKcbWX5CkRD/yFGgK6W6AjMBa+AHrfWULMp0AGYAtkCU1rp9rrVSiIckOjma0TtGczLyJO82e5e+dc3MHU+IhBU94Npx6PY1+AyyuK6AyAT6/XiYG0mpLBzQnDY1slhlKoQF7hroSilr4BugMxAKHFFKrddan72ljAvwLdBVax2slCrzgNorxAMTHBfM8G3DCU8KZ3qH6XSu3DnrgtcDYNkLEB8GLy+H2k9aXNex4BgGLTqCtZVi1dBHaOBZ8j5bL0TOrtCbA/5a60AApdQq4Bng7C1legO/aK2DAbTWEbndUCEepOMRxxm1YxQAPzz+A43LNM664D9zzLWG/hugYjOL69p5IYIRy45S2tmepYOby9a3Itfk5NBBDyDklsehmc/dqibgqpTapZTyU0r1y+qDlFJDlVK+SinfyMjIe2uxELls6+WtDNkyhBJ2JVj25DLzYX7hT1jcDeycYPDWewrzn/1CGbLYl6qlHfl5eCsJc5GrcnKFntVdHp3F5zQFOgEOwF9KqYNa64v/eZPW84H5AD4+Prd/hhAP3dKzS5l2ZBoNSjdgdkcz0xIB/BZlzjFvCH3WgpNlo4paa77bE8iUP87Tunop5r3SFOdils2GEeJuchLooUDFWx57AlezKBOltU4EEpVSe4BGwEWEyIcyTBlM853G8nPLeazSY0xuO5liNsXuLKg17JoMu6dC9c7w0iKwd7KoLpNJ89nGcyzYH0S3huWZ3qMR9jayYEjkvpwE+hGghlKqCnAF6IkxZn6r34A5SikbwA5oAXydmw0VIrfcTL/J+D3j2RGyg751+/JW07eynpaYkZY5x3wZNH4Fus+weI55arqJt9eeYP2Jqwxs7cWHT9WVBUPigblroGut05VSI4HNGNMWF2itzyilhmW+Pk9rfU4p9SdwEjBhTG08/SAbLsS9iE6OZtT2UZyKOsX45uPpU6dP1gVTEow55v5bod278Oj7Fs8xT0hJZ9hSP/b5RzGua22Gta+a9c6MQuQSpXXeDGX7+PhoX1/fPKlbFE0h8SEM3zacsMQwpradSqfKnbIumBABy1+CsJPw1FfgM9DiuiLjUxi06Ahnr8Ux5fkGvORT8e5vEiIHlFJ+WmufrF6TlaKiSDhz/Qwjto0gQ2dkPy3xegAse944nKLnSqjV1eK6Ll9PpN+Cw4THJfN9v6Z0rC2HUoiHQwJdFHr7r+znjV1v4GrvytzOc6lasmrWBUN9jdWfAAN+B88sL4KydfpKLAMWHibdpFnxaku8K7neR8uFsExO5qELUWCtD1jPyO0jqeRciaVPLjUf5hf+hEXdjF0SB2+9pzDf7x9Fz/kHsbex5qdhj0iYi4dOrtBFoaS15sfTPzLz6ExalG/BjA4zcLIzM93QdyFsfBPKN4LeayyeYw7GCUNvrjlOVXcnFg9qTrmSWUyBFOIBk0AXhU6GKYPJhyez+sJqnqr6FP9r9T9ss5puqDXs/Bz2fAE1HocXF1o8xxxg4f4gPv39LM0qu/F9Px9KFpcFQyJvSKCLQiU5PZnxe8ezPXg7A+sPZKz3WKxUFiOLGWmwYSwcXwZN+kK3GWBt2V8HrTVfbL7A3F0BPF63LLN6NZEThkSekkAXhUZsSiwjt4/kROSJHMwx7w/+26D9eOgw3uI55mkZJt775RQ/+YXSq3klPnu2PtayYEjkMQl0UShcTbjKsG3DCI0PZVr7aXTx6pJ1wYRIWP4ihJ2C7rOgaX+L67qZmsHrK46y43wEYzrVYOxjNWTBkMgXJNBFgXch+gLDtw0nOT2Z7zp/R7NyZnZBjLkES5+DuGvQayXUNBP62YhJTGXQ4iOcCLnBZ8/W55WWle+v8ULkIgl0UaAdunaIMTvH4GTrxOInFlPDtUbWBcNOGwuG0lOg/3qo2Nziuq7cuEm/Hw8REnOTb/t407V++ftsvRC5SwJdFFibAjcxYf8EvEp4MfexuZRzLJd1wcsHYEVPsHOEQX9CmToW13UhLJ5+Cw6RlJrB0kHNaVG11H22XojcJ4EuChytNYvPLGa633R8yvows+NMStiVyLrw+U3w00BwqQSv/AIulu+pcjgomiGLj1DM1pq1wx6hdjkzdQmRxyTQRYFi0iamHZnGsnPLeLzy43ze9nPsre2zLnx0KWwYDRWaQO+14Gj5VfXmM2GMWnkMT1cHlgxqjqdr8fvsgRAPjgS6KDBSMlKYsG8Cmy9t5pU6r/BOs3eynmOuNez7GrZPhGqdoMeSe1owtOJQMB+sO0VDTxcWDGiGm6NdLvRCiAdHAl0UCHGpcYzZMQbfcF/e9nmb/vXMTDc0mWDLBDj4LdR/EZ6dCzaWBbHWmlnb/fl620U61CrNt328KW4nf1VE/ic/pSLfC0sMY/i24VyKu8TUtlN5suqTWRfMSIN1I+DUGmgxHLp8DlaW7T+XYdJ89Ntplh8K5gVvT6a80ABba9nDThQMEugiX/s75m+GbxtOQloC8x6bR4vyLbIumJoIa/oZqz87fQRt3rR49WdyWgZjVx3nzzNhDGtfjXFda8mCIVGgSKCLfMs3zJfRO0dTzLoYi7suppZbrawLJkUbJwxdPXrPqz9jb6bx6hJfDgdF82G3ugxuU+U+Wy/EwyeBLvKlLZe2MH7veDydPZn32DwqOFXIumBsKCx93lgF2mMp1OlmcV3hccn0X3CYgMgEZvZszDONPe6v8ULkEQl0ke8sP7ecqYen0rhMY2Z3nE1J+5JZF4w4b6z+TImHvr+AVxuL6wqITKDfj4e5kZTKggHNaFuj9H22Xoi8I4Eu8g2TNjHDbwYLzyykU6VOTGk7hWI2Zg6KCDlsHBdnbQcDN0G5BhbXdyw4hkGLjmBtpVg19BEaeJr5h0OIAkICXeQLaRlpfHjgQzYGbuTlWi/zXvP3sLYys7f4xS3GDdAS5Y3Vn26Wj3fvvBDBiGVHKe1sz5JBzfFyd7zPHgiR9yTQRZ5LSE1g7K6xxkZb3mMYXH+w+dklJ1YZUxPL1Yc+P4OT5UMkP/mFMu7nk9Qu58yigc0p7WxmpakQBYwEushTkUmRDN82nIAbAUxqM4mnqz1tvvCB2bDlA6jSDl5eDsUs21NFa813ewKZ8sd5WlcvxbxXmuJcTI6LE4WHBLrIM4GxgQzfOpyYlBjmdJpDa4/WWRfUGrZ+BAdmQd1n4fn5YGPZVbXJpPls4zkW7A+iW8PyTO/RCHsbOS5OFC4S6CJPHI84zsgdI7FW1izsupB6peplXTAjDdaPhhMroNkQeOILMDe2bkZquom3155g/YmrDGjlxUfd6mIlx8WJQkgCXTx024O3M27POMo5lmPuY3Op6GxmS9vUJFg7AP7eDB3eh/bvWrz6MyElnWFL/djnH8W7XWsxvH01Wf0pCi0JdPFQrbmwhkmHJlG/VH3mdJqDazHXrAsmRcPKnsb0xKe+gmaDLa4rMj6FQYuOcPZaHNNebMhLPpbvhS5EQSKBLh4KrTWzj83m+1Pf096zPdPaT8PBxiHrwrFXYNkLEB0APRZD3Wcsri8oKpH+Cw4TEZ/M/L5N6VSn7H32QIj8TwJdPHBppjQmHpjIbwG/8UKNF/ig5QfYWJn50Yu8aKz+vHkDXvnZmNFioeMhNxi06Ahaa1a+2pImlcz8L0CIQkYCXTxQSWlJvLn7TfZf2c+IxiMY1nCY+THsUF9jky0rGxi4Eco3sri+necjGLH8KO7Odiwe2JyqpS0/2EKIgipHGz0rpboqpS4opfyVUuOzKddMKZWhlHox95ooCqqom1EM3DyQg1cPMrHVRIY3Gm4+zP23weLuxtzywZvvKczXHAlhyBJfqpVx5OfhrSTMRZFz1yt0pZQ18A3QGQgFjiil1mutz2ZRbiqw+UE0VBQsl+MuM2zrMK4nX2dWx1m088xm6OTkGlg3HMrUMVZ/Ols23q21Zs4Of6ZvvUjbGu7MfaUpTvbyn09R9OTkp7454K+1DgRQSq0CngHO3lZuFPAz0CxXWygKnJORJxm5fSQAPz7+Iw1KZ7Nx1l/fwub3wKst9FwOxSzbIOvWE4aea+LB1BcaYmcjJwyJoiknP/keQMgtj0Mzn/t/SikP4DlgXnYfpJQaqpTyVUr5RkZGWtpWUQDsCN7B4M2DcbR1ZOmTS82Hudaw7RMjzOt0hz4/WRzmyWkZDFvmx/JDwQzvUI2vejSSMBdFWk6u0LMa9NS3PZ4BjNNaZ2S3aENrPR+YD+Dj43P7Z4gCbsW5FUw5PIUG7g2Y1XEWpRxKZV0wIx1+HwPHlkHTgfDUdItXf8YkpjJkiS9Hg2OY+HQ9+rfyuv8OCFHA5STQQ4FbV2R4AldvK+MDrMoMc3fgSaVUutZ6XW40UuRvJm3iK9+vWHx2MY9WfJSp7aaan2OemghrBxqrP9uPgw7vWbz6MzQmif4LDhMSc5NvenvzZIPyudALIQq+nAT6EaCGUqoKcAXoCfS+tYDW+v83pFZKLQJ+lzAvGlIyUnh/7/tsubyFXrV7Ma7ZOPP7mCdEGIdSXDtxz6s/T1+JZeCiI6SkZbB0UHNaVDXzvwAhiqC7BrrWOl0pNRJj9oo1sEBrfUYpNSzz9WzHzUXhdSP5BqN3juZYxDHe9nmbfnX7mZ+WGOVvLBhKjISeK6DWExbXt+diJMOX+VHSwZblw1tRs6zzffZAiMIlR3O7tNabgE23PZdlkGutB9x/s0R+FxIfwohtI7iacJUv239JF68u5gsHHzL2ZVFW0P938GxqcX1rfUN475dT1CjrzKKBzShbwszRdEIUYTJZV1jsdNRpXt/+Ohk6g+8f/x7vst7mC59dD7+8CiU84JWfwK2qRXVprZm9w5+vtl6kTXV35r7iLYdSCGGGBLqwyK6QXby7513cirkx97G5VCmZzXmeB+fBn+PB0wd6rQZHy8a70zJMfLjuNKuOhPC8twdTnpc55kJkRwJd5Niq86uYfHgyddzqMKfTHNwd3LMuaDLB1g/hrzlQuxs8/z3YFbeorsSUdF5fcZRdFyIZ1bE6b3auKfuYC3EXEujirkzaxIyjM1h4eiHtPdvzRbsvKG5rJqDTkmHdMDjzKzQfCl2nWDzHPCI+2djH/Gocnz/XgN4tKuVCL4Qo/CTQRbZSMlL4YN8H/HnpT16u9TLjm483v/VtUjSs6gPBB6Dz/6DVKIvnmAdEJtB/wWGuJ6TyfT8f2cdcCAtIoAuzYlNiGbNzDH7hfrzR9A0G1htoftgj5jIsfxFiLsGLC6D+CxbX53spmiFLfLFWilVDW9Koost9tV+IokYCXWTpSsIVhm8bTmh8KFPbTuXJqk+aL3z1uLFgKD0Z+q4Dr9YW17fhxFXeWnsCDxcHFg1sRuVSjvfcdiGKKgl0cYeTkScZvWM0qaZUvuv8Hc3KZbOB5t/bYE0/KO4G/dZDmdoW1aW1ZtZ2f77edpFmXq5819cHN0e7++yBEEWTBLr4jz8v/ckH+z7A3cGdBZ0WUNUlm3njR5fChjFQti70XgslLNtTJTktg3E/n+S341d53tuDyc83wN7GshuoQoh/SaALwLhSnn9yPnOOz6FJmSbMeHQGbsXczBWGXVNg9xSo1hF6LAF7y5bhRyWkMHSJL0eDb/BOl1qM6FBNpiUKcZ8k0AWpGal8cuATNgRuoFvVbkxsNRE7azPDHhlpsGEsHF8GjV+B7jPA2rKVmxfC4hm8+AhRCSl820d2SxQit0igF3ExyTGM3TmWoxFHGdl4JEMbDjV/pZwSD2v6Q8B2aD8eOoy3eFrirgsRjFxxDAc7a1YPfURmsgiRiyTQi7DAG4G8vv11Im9GMq39NLp6dTVfOD4Mlr8E4Wfg6dng3c/i+hYfuMTEDWeoXa4EP/T3oYKLmT3ThRD3RAK9iPrr6l+8testbK1tWdBlAQ1LNzRfOPICLHvBWDjUezXU6GxRXekZJj79/SxL/rrMY3XKMrNnYxzlEGchcp38rSqC1lxYw+eHPqdKySp80+kbKjhVMF/40n5Y1QtsisHATVChsUV1xSWnMXLFMfZcjGRou6qM61obayu5+SnEgyCBXoRkmDL4yu8rlpxdQhuPNkxrNw0nOyfzbzj9C/z6Grh6GYc4u1a2qL5LUYkMWeLLpahEpjzfgJ7NZU8WIR4kCfQiIjYllvF7x7Pvyj761OnD2z5vm9+TRWtjp8QtH0ClVtBzubFwyAIHAqIYsfwoAEsGN6dVNTM7Mwohco0EehHgH+PPmJ1juJp4lQ9bfkiPWj3MF05PhU1vw9HFUPdZeO47sLXsdKClBy8zcf0Zqrg78kN/H1nGL8RDIoFeyG2/vJ33971PcdviLOiygCZlmpgvnBRtLOO/tBfavg2PTgCrnB8okZZh4tMNZ1l68DIda5dhZs/GcrqQEA+RBHohZdImvj3+Ld+d/I4G7g34usPXlHXMZivaqL+NDbZiQ+G5+dDoZYvqu5GUyojlRzkQcJ3X2lXlXbn5KcRDJ4FeCMWnxvPe3vfYHbqb56o/x4SWE7C3tjf/hoCdsLY/WNkahzhXamFRff4R8Qxe7Mu1G8lMf6kRLzT1vM8eCCHuhQR6IRMYG8iYHWMIjQ/l/Rbv07NWz+z3SDnyI2x6B0rXgl6rLJ7JsvNCBKNXHMPe1pqVQ1vStLLrffZACHGvJNALkV0huxi/dzz21vZ8//j3+JTzMV84Ix22TIBD86BGF3jhByhWIsd1aa35YW8Qk/84R+1yJfi+vw8esvJTiDwlgV4ImLSJ+Sfn883xb6hbqi4zH51JOcdy5t9w8wb8PBj8t0HL1+Hx/1l07mdKegYTfj3NT36hPFG/HNN7NKK4nfwoCZHX5G9hAZeYlsj7e99nR8gOulftzkePfEQxm2ymGUb9DSt7GkfGdZ8JTQdYVF9kfArDlvnhdzmGMZ1qMKZTDazk5qcQ+YIEegF2Oe4yY3aM4VLcJcY1G0efOn2yHy//exv8NMjY7rb/eqjcyqL6zlyNZegSP64npvBNb2+eaijb3gqRn0igF1B7Q/cybs84rK2s+a7zd7Qon83MlH9Wfm79CMrUg14rwMWyZfi/HgvlvV9O4eJgx0/DWlHfo+R99kAIkdsk0AsYrTU/nv6RWUdnUcutFjMenYGHk4f5N6Qlw+9j4cRKqPsMPDsX7HK+cjM13cRnG42dEltUcWNOb29KO2czBVIIkWck0AuQpLQkPtj/AVsvb+WJKk8wsdVEHGyymVkSHwar+sAVX2PVZ7t3LDqQIjwumRHLj+J3OYYhbaow/ona2FjnfOWoEOLhkkAvIELiQxizcwwBNwJ4q+lb9K/XP/vx8it+Rpgnx8HLy6BOd4vqOxR4nddXHCMpNZ3ZvZrQvVE2W+wKIfKFHF1uKaW6KqUuKKX8lVLjs3i9j1LqZObXAaVUo9xvatF14OoBev7ek/DEcOZ2msuA+gPMh7nW4LsQFnQ1bn4O3mJRmGutWbAviN4/HKJEMRvWvd5awlyIAuKuV+hKKWvgG6AzEAocUUqt11qfvaVYENBeax2jlHoCmA9Ytn5c3EFrzeIzi/n66NdUc6nGzA4zqViiovk3pN2EjW/B8eVQrZOxWMiCbW+TUtN575dT/Hb8Kp3rlmV6j0aUkM21hCgwcjLk0hzw11oHAiilVgHPAP8f6FrrA7eUPwjIZh73KSktiU/++oQ/gv6gc+XOfNb6M4rbFjf/huggWNMXwk5B+3HGlwWLhS5fT+S1pX5cCI/n7cdrMqJDdZlfLkQBk5NA9wBCbnkcSvZX34OBP+6nUUVd4I1A3tr9FgE3AhjjPYbB9QdnP15+cQv8MsT4vvcaqNnFovp2no9gzKpjKKVYNLA57WuWvo/WCyHySk4CPask0VkWVOpRjEBvY+b1ocBQgEqV5DiyrGwM3MjEv4zZK/M6z6NVhWwW/5gyYPdU46tcA+ixFNyq5LiuDJNmxraLzNnpT51yJfiub1MqumXzvwAhRL6Wk0APBW4duPUErt5eSCnVEPgBeEJrfT2rD9Jaz8cYX8fHxyfLfxSKqpSMFL44/AVrLq7Bu4w3X7T7Ivv9y5Oi4ZdXjf1YGveBp6aDbc43x4qIS2b0qmMcDIymh48nE5+uj4NdzodohBD5T04C/QhQQylVBbgC9AR631pAKVUJ+AXoq7W+mOutLORC4kN4a9dbnIs+x8D6AxnVZBS2VtncjLx6DFb3g4Qw6DbD2I/FgvnlB/yjGL3qOAkpaXz5UiNelP3LhSgU7hroWut0pdRIYDNgDSzQWp9RSg3LfH0e8BFQCvg2c6w3XWudzd6t4h/bL2/nw/0fgoJZj87i0UqPZv+Go0tg49vgWBoG/QkeTXNcV4ZJM2eHPzO2X6RaaSdWvNqCmmWd77MHQoj8QmmdNyMfPj4+2tfXN0/qzg/STGnM8JvBkrNLqFeqHtM7TM9+CX9qojEl8cRKqPoovPAjOJbKcX1RCSmMXXWcff5RPN/Eg/89Wx9He1lXJkRBo5TyM3fBLH+j80BYYhhv736bE5En6FW7F2/7vI2dtZ35N4SfhbUDIOoidHjPWMJvwZTEQ4HXGbXyGLE305jyfANeblYx+1kzQogCSQL9Idsbupf3971PakYq09pNo2uVruYLa20sEtr4Ntg7Q791ULVDjutKzzAxa/vfzNnpT+VSjiwe1Jw65XN+KpEQomCRQH9IUjJSmOE3g2XnllHDtQZftf8Kr5Je2bwhATa9bQyxVGkHz/8AztnMerlN8PUkxqw+xrHgG7zg7cnEZ+rhJEMsQhRq8jf8IQi4EcC7e97lYsxFetXuxZtN38z+VKGQw/DLUIi5dE9DLL8eC+XDdWdQCtlYS4giRAL9AdJas/rCar70/RJHW0e+6fQN7TzbmX9DRhrsmWZ8lfCEARvBq3WO64tLTuPDdaf57fhVmnm58vXLjfF0lYVCQhQVEugPSERSBJ/+9Sm7Q3fT2qM1n7X+DHcHd/NvuB5gLBS64geNesETU6FYzk8F8rsczZhVx7kWm8ybnWsyokM12btciCJGAj2Xaa1Z57+OaUemkWpKZVyzcfSu0xsrZSZcTSbwWwBbPgRrO3hpEdR7Lsf1pWeYmL3Dn9k7/sbD1YE1rz1C08quudMZIUSBIoGei64mXGXiXxM5cPUA3mW8+bT1p1QuUdn8G6KDYP0ouLTXmFv+7LdQIufj3SHRSYxdfRy/yzE838SDic/Uw1m2uxWiyJJAzwUmbWL1hdXM8JuBRjOhxQR61OqR/VX54fmwfSJY2UD3WeDdL8fL97XW/HrsCh//dgaAmT0b80zjbBYlCSGKBAn0+3Q66jSTDk7i9PXTPFL+ET5u9XH2Kz6j/OG31yHkINR43NiLpWTOwzgqIYUJv55i85lwfCobNz5lh0QhBEig37MbyTeYdWwWP138iVIOpfi8zed0q9rN/ArM9FQ4MBN2TwPbYvDsPGjU06JNtf48HcaEX08Rn5zOe0/UZkjbqljLIRRCiEwS6BYyaRO//P0LM47OICE1gT51+jCi8Qic7bLZ5CrkCGwYDRFnoe6zxgwW53I5rjM2KY1PNpzh12NXqO9RgpU9GsumWkKIO0igW+BM1BkmHZrEqahTeJfxZkLLCdR0rWn+DclxsP1TOPKDcbOz1yqo9USO69Na89vxq3y28RwxSamM6VSDkR2rYyvTEYUQWZBAz4Hbh1cmt53MU1WeMj+8YjLBqTWw7ROID4MWr0HHD4z9WHLIPyKeD9ad5mBgNI08S7JoYDPqe+R8XroQouiRQM/GvQ2vHIY/xxsLhCo0gZeXgWfOt4ZPSk1n1nZ/ftgbiKO9DZOeq0/PZpVkrFwIcVcS6GZYPLwSG2pckZ9aC07l4Nm50LAnWOVseORmagarjgQzb3cA4XEpvNTUk/FP1KaUk33udEgIUehJoN/m1uEVt2Jud5+9kpoI+2fC/lmANjbSaj0W7J1yVF9iSjrLDl7m+72BRCWk0ryKG3N6e9PMyy3X+iSEKBok0DP9M7wy8+hM4lPj7z68YjLB6Z9g68cQfxXqPQ+dJ4JLpRzVF5ecxuL9l/hxfxA3ktJoW8OdkY9Wp0XVnJ9CJIQQtyryga615q9rfzHr6CzOXD+Ts+GVkCOZ4+S+UL4xvLgAKj+So/pib6axcH8QC/YFEZecTqfaZRjZsTpNKsn+K0KI+1NkA11rjW+4L3NPzOVI2BHKOZa7+/BK2CnY/QWcW2/xOHlsUhoL9gexYH8Q8cnpPF63LKM71ZCZK0KIXFPkAt2kTewI3sHC0ws5GXUSt2JujG8+npdqvmT+XM9rJ4wgP/872JeA9uOg1egcjZMnp2WwYH8Qc3cGEJ+STpd6RpDXqyBBLoTIXUUm0FMzUtkQsIFFZxZxKe4SHk4eTGgxgWerP2v+9KCrx4wgv7AJ7EtC+/HQchg43H14RGvNH6fD+HzTOUJjbvJYnbK89XhNOdNTCPHAFPpAj0yKZO3Ftay5sIbrydep41aHae2m8Vjlx7CxMtP9K36wayr8vdk4ZKLD+8biIAeXHNV5+kosn/5+lsNB0dQu58yKIS1oVT2bwy2EECIXFNpAPxV5iuXnl7P50mbSTem082zHK3VeoWX5lubHyEN9YdcU8N9qXIV3/ACavwbFcnZVHRGfzJebL7DWLxS34nZ8/lwDXm5WURYFCSEeikIV6GkZaWy9vJXl55ZzMuokjraO9KzVk561e2Z/0MS1E8aeK/7bwMENOn0EzYfmeKl+Umo6iw5c4psd/qRmmHi1bVVGdqxOCTlsQgjxEBWKQA+MDeT3gN9Z57+OyJuReJXw4r3m7/FM9WdwtHU0/8boINjxmTGfvJgLdPoYmr+a4yCPTUpj6cFLLNh/iejEVDrXLcuEJ+vg5Z5NnUII8YAUyEDXWhMYG8iO4B1svbyVc9HnsFJWtKrQik/rfEqrCq3MnxYEkBAJe74A34XGiUFt3oTWY3I0Rh4Wm8zWc+FsPRvOXwFRpGVoOtYuw+uPVqNpZVndKYTIOwUm0DNMGZyIPMHOkJ3sCN5BcHwwAA3cG/Bus3d5osoTuDtkc+MxLdkYUjnzC1z4A9JTwLuvMXOlRHmzb0tJz+BkaCwHA66z7Vw4J0JjAfAqVZwBrbx4rokndSvIzBUhRN7L14GenJ7MwWsH2RG8g92hu4lOjsbGyoYW5VvQv15/OlTsQJniZcx/QFoyBO0xQvz8RkiJM8bIG/aAR0aCe4073pKUms6x4BscCormcNB1jgXfICXdBEDjii6806UWj9ctS/UyTuZvrgohRB7Id4F+I/kGu0N3szNkJweuHuBm+k2cbZ1p49mGjpU60qZCG5zszCzo0RrCT0PATgjcCZf/gvSbxtTDOk9D/eegSnuw/vdmZVxyGn6XYjgYdJ3DQdGcCo0l3aSxUlCvQkn6tqxM8ypuNPNyw9XRzMIjIYTIB/JFoMemxLLl8hb+CPqDo+FHydAZlClehmeqPcOjlR6lWdlm2N4SwphMxoZY1wPguj9EBxq/XjkKiRFGmdK10U37k+DZjituLYhM0kTEphC5L5iw2GQuX08kKCqR4OgkTBpsrRWNPF0Y2q4qzau40bSyK84yS0UIUYDkKNCVUl2BmYA18IPWesptr6vM158EkoABWuuj2X2mRrM7ZDfrA9azK2QXqaZUqpasyuAGg+lYqSN1naui4kIh5jIcXWz8GnMJU5Q/xARilZ78/5+VZlWMaHtPQu0acbRUY/ab6nMhzpmofSmkZWjg0H/qdrSzpnIpR+p5lOS5Jp40q+JKk4quONhZ5+S3Qwgh8iWltc6+gFLWwEWgMxAKHAF6aa3P3lLmSWAURqC3AGZqrVtk97nOVZ2118deuNo40cmxOp0yXKgWF4NtXAgOiVdwTI38T/lUbAjVZQg0lSVIl8/8KkeQqRzhuGJnY4O7kz1ujna4OdpR2tmeMs72mb8W+89jR/t88R8TIYSwmFLKT2ud5TFoOUm25oC/1jow88NWAc8AZ28p8wywRBv/OhxUSrkopcprra+Z+9DiGanMCYug1c1gbDlLhlZcoxSXTGUI0XW5qspww74CiQ4VSHWuhHWJcrg5FcPNyQ53R3s6OtpRysmOUo72lHKyo7idtdykFEIUaTkJdA8g5JbHoRhX4Xcr4wH8J9CVUkOBoQBVy7sSV+YNNpWshJVbZYqVqoRbCSfKO9pR38kOJ3sbCWghhLBATgI9q1S9fZwmJ2XQWs8H5gP4+Pjo7gPH56B6IYQQOZGTE4xDgYq3PPYErt5DGSGEEA9QTgL9CFBDKVVFKWUH9ATW31ZmPdBPGVoCsdmNnwshhMh9dx1y0VqnK6VGApsxpi0u0FqfUUoNy3x9HrAJY4aLP8a0xYEPrslCCCGykqP5e1rrTRihfetz8275XgOv527ThBBCWCInQy5CCCEKAAl0IYQoJCTQhRCikJBAF0KIQuKue7k8sIqVigcu5EnlD447EJXXjchF0p/8rbD1Bwpfnx5EfyprrUtn9UJe7lJ1wdwGMwWVUsq3MPVJ+pO/Fbb+QOHr08Pujwy5CCFEISGBLoQQhUReBvr8PKz7QSlsfZL+5G+FrT9Q+Pr0UPuTZzdFhRBC5C4ZchFCiEJCAl0IIQqJPAl0pVRXpdQFpZS/UqrAnXKhlKqolNqplDqnlDqjlBqT+bybUmqrUurvzF9d87qtllBKWSuljimlfs98XND746KU+kkpdT7zz+qRgtwnpdQbmT9vp5VSK5VSxQpSf5RSC5RSEUqp07c8Z7b9Sqn3MjPiglKqS960Ontm+jQt82fupFLqV6WUyy2vPdA+PfRAzzx0+hvgCaAu0EspVfdht+M+pQNvaa3rAC2B1zP7MB7YrrWuAWzPfFyQjAHO3fK4oPdnJvCn1ro20AijbwWyT0opD2A04KO1ro+xlXVPClZ/FgFdb3suy/Zn/n3qCdTLfM+3mdmR3yzizj5tBeprrRsCF4H34OH0KS+u0P//0GmtdSrwz6HTBYbW+prW+mjm9/EYQeGB0Y/FmcUWA8/mSQPvgVLKE3gK+OGWpwtyf0oA7YAfAbTWqVrrGxTgPmEsBHRQStkAxTFOBSsw/dFa7wGib3vaXPufAVZprVO01kEYZy00fxjttERWfdJab9Fap2c+PIhxghs8hD7lRaCbO1C6QFJKeQFNgENA2X9Oasr8tUweNs1SM4B3AdMtzxXk/lQFIoGFmcNIPyilHCmgfdJaXwG+BIIxDl+P1VpvoYD25xbm2l9YcmIQ8Efm9w+8T3kR6Dk6ULogUEo5AT8DY7XWcXndnnullOoGRGit/fK6LbnIBvAG5mqtmwCJ5O/hiGxlji0/A1QBKgCOSqlX8rZVD1SBzwml1ASM4dnl/zyVRbFc7VNeBHqhOFBaKWWLEebLtda/ZD4drpQqn/l6eSAir9pnodbA00qpSxhDYB2VUssouP0B4+csVGt9KPPxTxgBX1D79BgQpLWO1FqnAb8ArSi4/fmHufYX6JxQSvUHugF99L+LfR54n/Ii0HNy6HS+ppRSGGOz57TWX93y0nqgf+b3/YHfHnbb7oXW+j2ttafW2gvjz2OH1voVCmh/ALTWYUCIUqpW5lOdgLMU3D4FAy2VUsUzf/46Ydy7Kaj9+Ye59q8Heiql7JVSVYAawOE8aJ/FlFJdgXHA01rrpFteevB90lo/9C+MA6UvAgHAhLxow322vw3Gf5VOAsczv54ESmHcqf8781e3vG7rPfStA/B75vcFuj9AY8A3889pHeBakPsETATOA6eBpYB9QeoPsBJj/D8N42p1cHbtByZkZsQF4Im8br8FffLHGCv/JxvmPaw+ydJ/IYQoJGSlqBBCFBIS6EIIUUhIoAshRCEhgS6EEIWEBLoQQhQSEuhCCFFISKALIUQh8X8wuggE05dxgAAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "from scipy import *\n", "from numpy import *\n", "\n", "unit=pi\n", "ndim=3\n", "maxeval=200000\n", "exact = 1.3932 # exact value of the integral\n", " \n", "cum = Cumulants()\n", " \n", "nbins=128\n", "nstart =10000\n", "nincrease=5000\n", "\n", "grid = Grid(ndim,nbins)\n", "\n", "fxbin = Vegas_step2(my_integrant2, pi, maxeval, nstart, nincrease, grid, cum)\n", "imp = Smoothen(fxbin)\n", "grid.RefineGrid(imp)\n", "print(cum.avg, '+-', cum.err, 'exact=', exact)\n", "\n", "plot(grid.g[0,:nbins])\n", "plot(grid.g[1,:nbins])\n", "plot(grid.g[2,:nbins])\n", "xlim([0,128])\n", "show()" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "def Vegas_step3(integrant, unit, maxeval, nstart, nincrease, grid, cum):\n", " ndim, nbins = grid.ndim,grid.nbins # dimension of the integral, size of the grid for binning in each direction\n", " unit_dim = unit**ndim # converts from unit cube integration to generalized cube with unit length\n", " nbatch=1000 # function will be evaluated in bacthes of 1000 evaluations at one time (for efficiency and storage issues)\n", " neval=0\n", " print (\"\"\"Vegas parameters:\n", " ndim = \"\"\"+str(ndim)+\"\"\"\n", " unit = \"\"\"+str(unit)+\"\"\"\n", " maxeval = \"\"\"+str(maxeval)+\"\"\"\n", " nstart = \"\"\"+str(nstart)+\"\"\"\n", " nincrease = \"\"\"+str(nincrease)+\"\"\"\n", " nbins = \"\"\"+str(nbins)+\"\"\"\n", " nbaths = \"\"\"+str(nbatch)+\"\\n\")\n", "\n", " bins = zeros((nbatch,ndim),dtype=int) # in which sampled bin does this point fall?\n", " \n", " \n", " all_nsamples = nstart\n", " for iter in range(1000): # NEW in step 3\n", " wgh = zeros(nbatch) # weights for each random point in the batch\n", " fxbin = zeros((ndim,nbins)) # after each iteration we reset the average function being binned\n", " for nsamples in range(all_nsamples,0,-nbatch): # loop over all_nsample evaluations in batches of nbatch\n", " n = min(nbatch,nsamples) # How many evaluations in this pass?\n", " # We are integrating f(g_1(x),g_2(y),g_3(z))*dg_1/dx*dg_2/dy*dg_3/dz dx*dy*dz\n", " # This is represented as 1/all_nsamples \\sum_{x_i,y_i,z_i} f(g_1(x_i),g_2(y_i),g_3(z_i))*dg_1/dx*dg_2/dy*dg_3/dz\n", " # where dg_1/dx = diff*NBINS\n", " xr = random.random((n,ndim)) # generates 2-d array of random numbers in the interval [0,1)\n", " for i in range(n):\n", " weight = 1.0/all_nsamples\n", " for dim in range(ndim):\n", " # We want to evaluate the function f at point g(x), i.e, f(g_1(x),g_2(y),...)\n", " # Here we transform the points x,y,z -> g_1(x), g_2(y), g_3(z)\n", " # We hence want to evaluate g(x) ~ g(x[i]), where x is the random number and g is the grid function\n", " # The discretized g(t) is defined on the grid :\n", " # t[-1]=0, t[0]=1/N, t[1]=2/N, t[2]=3/N ... t[N-1]=1.\n", " # We know that g(0)=0 and g(1)=1, so that g[-1]=0.0 and g[N-1]=1.0\n", " # To interpolate g at x, we first compute i=int(x*N) and then we use linear interpolation\n", " # g(x) = g[i-1] + (g[i]-g[i-1])*(x*N-i) ; if i>0\n", " # g(x) = 0 + (g[0]-0)*(x*N-0) ; if i=0\n", " #\n", " pos = xr[i,dim]*nbins # which grid would it fit ? (x*N)\n", " ipos = int(pos) # the grid position is ipos : int(x*N)==i\n", " diff = grid.g[dim,ipos] - grid.g[dim,ipos-1] # g[i]-g[i-1]\n", " # linear interpolation for g(x) : \n", " xr[i,dim] = (grid.g[dim,ipos-1] + (pos-ipos)*diff)*unit # g(xr) ~ ( g[i-1]+(g[i]-g[i-1])*(x*N-i) )*[units]\n", " bins[i,dim]=ipos # remember in which bin this random number falls.\n", " weight *= diff*nbins # weight for this dimension is dg/dx = (g[i]-g[i-1])*N\n", " # because dx = i/N - (i-1)/N = 1/N\n", " wgh[i] = weight # total weight is (df/dx)*(df/dy)*(df/dx).../N_{samples}\n", " \n", " # Here we evaluate function f on all randomly generated x points above\n", " fx = integrant(xr) # n function evaluations required in single call\n", " neval += n # We just added so many fuction evaluations\n", " \n", " # Now we compute the integral as weighted average, namely, f(g(x))*dg/dx\n", " wfun = wgh * fx # weight * function ~ f_i*w_i \n", " cum.sum += sum(wfun) # sum_i f_i*w_i = \n", " wfun *= wfun # carefull : this is like (f_i * w_i/N)^2 hence 1/N (1/N (f_i*w_i)^2)\n", " cum.sqsum += sum(wfun) # sum_i (f_i*w_i)^2 = /all_nsamples\n", " # \n", " for dim in range(ndim): #new2\n", " # Here we make a better approximation for the function, which we are integrating.\n", " for i in range(n): #new2\n", " fxbin[dim, bins[i,dim] ] += wfun[i] #new2: just bin the function f. We saved the bin position before.\n", " \n", " w0 = sqrt(cum.sqsum*all_nsamples) # w0 = sqrt()\n", " w1 = (w0 + cum.sum)*(w0 - cum.sum) # w1 = (w0^2 - ^2) = (-^2)\n", " w = (all_nsamples-1)/w1 # w ~ 1/sigma_i^2 = (N-1)/(-^2)\n", " # Note that variance of the MC sampling is Var(monte-f) = (-^2)/N == 1/sigma_i^2\n", " cum.weightsum += w # weightsum ~ \\sum_i 1/sigma_i^2\n", " cum.avgsum += w*cum.sum # avgsum ~ \\sum_i _i / sigma_i^2\n", " cum.avg2sum += w*cum.sum**2 # avg2cum ~ \\sum_i _i^2/sigma_i^2\n", " \n", " cum.avg = cum.avgsum/cum.weightsum # I_best = (\\sum_i _i/sigma_i^2 )/(\\sum_i 1/sigma_i^2)\n", " cum.err = sqrt(1/cum.weightsum) # err ~ sqrt(best sigma^2) = sqrt(1/(\\sum_i 1/sigma_i^2))\n", " \n", " # NEW in this step3\n", " if iter>0:\n", " cum.chisq = (cum.avg2sum - 2*cum.avgsum*cum.avg + cum.weightsum*cum.avg**2)/iter\n", " \n", " print (\"Iteration {:3d}: I= {:10.8f} +- {:10.8f} chisq= {:10.8f} number of evaluations = {:7d} \".format(iter+1, cum.avg*unit_dim, cum.err*unit_dim, cum.chisq, neval))\n", " imp = Smoothen(fxbin)\n", " grid.RefineGrid(imp)\n", " \n", " cum.sum=0 # clear the partial sum for the next step\n", " cum.sqsum=0\n", " all_nsamples += nincrease # for the next time, increase the number of steps a bit\n", " if (neval>=maxeval): break\n", " \n", " cum.avg *= unit**ndim\n", " cum.err *= unit**ndim" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vegas parameters:\n", " ndim = 3\n", " unit = 3.141592653589793\n", " maxeval = 2000000\n", " nstart = 100000\n", " nincrease = 5000\n", " nbins = 128\n", " nbaths = 1000\n", "\n", "Iteration 1: I= 1.36762346 +- 0.01023309 chisq= 0.00000000 number of evaluations = 100000 \n", "Iteration 2: I= 1.38308994 +- 0.00488295 chisq= 2.95787653 number of evaluations = 205000 \n", "Iteration 3: I= 1.38903765 +- 0.00341085 chisq= 2.92764168 number of evaluations = 315000 \n", "Iteration 4: I= 1.39085420 +- 0.00271957 chisq= 2.21131183 number of evaluations = 430000 \n", "Iteration 5: I= 1.39235286 +- 0.00238578 chisq= 1.98798517 number of evaluations = 550000 \n", "Iteration 6: I= 1.39215278 +- 0.00209328 chisq= 1.59649946 number of evaluations = 675000 \n", "Iteration 7: I= 1.39187814 +- 0.00186075 chisq= 1.34408861 number of evaluations = 805000 \n", "Iteration 8: I= 1.39040546 +- 0.00167503 chisq= 1.62389166 number of evaluations = 940000 \n", "Iteration 9: I= 1.39098400 +- 0.00155755 chisq= 1.53107506 number of evaluations = 1080000 \n", "Iteration 10: I= 1.39152488 +- 0.00144974 chisq= 1.46121875 number of evaluations = 1225000 \n", "Iteration 11: I= 1.39101550 +- 0.00135470 chisq= 1.41244571 number of evaluations = 1375000 \n", "Iteration 12: I= 1.39111487 +- 0.00127230 chisq= 1.28818899 number of evaluations = 1530000 \n", "Iteration 13: I= 1.39172957 +- 0.00120599 chisq= 1.37245777 number of evaluations = 1690000 \n", "Iteration 14: I= 1.39195626 +- 0.00114625 chisq= 1.29501238 number of evaluations = 1855000 \n", "Iteration 15: I= 1.39272504 +- 0.00110407 chisq= 1.64730521 number of evaluations = 2025000 \n", "1.3927250368308894 +- 0.0011040731205297308 exact= 1.3932 real error= 0.00034091528072821835\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "from scipy import *\n", "from numpy import *\n", "\n", "unit=pi\n", "ndim=3\n", "maxeval=2000000\n", "exact = 1.3932 # exact value of the integral\n", " \n", "cum = Cumulants()\n", " \n", "nbins=128\n", "nstart =100000\n", "nincrease=5000\n", "\n", "grid = Grid(ndim,nbins)\n", "\n", "random.seed(0)\n", "\n", "Vegas_step3(my_integrant2, pi, maxeval, nstart, nincrease, grid, cum)\n", "\n", "print (cum.avg, '+-', cum.err, 'exact=', exact, 'real error=', abs(cum.avg-exact)/exact)\n", "\n", "plot(grid.g[0,:nbins])\n", "plot(grid.g[1,:nbins])\n", "plot(grid.g[2,:nbins])\n", "show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we are going to speed up the code by using vectorized numpy capability, and `numba` capability.\n", "\n", "Here `numba` will be used to set `fxbin` array, using `wfun` array, which contains projection of the function integrated to all axis.\n", "\n", "To interpolate grid at the random points `xr`, we will use numpy vectorized functionality and `fancy indexing` to remove the loop over batches. All loops over batch size `n` is gone in the final version of the code." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "from numba import jit\n", "\n", "@jit(nopython=True)\n", "def SetFxbin(fxbin,bins,wfun):\n", " (n,ndim) = bins.shape\n", " for dim in range(ndim):\n", " # Here we make a better approximation for the function, which we are integrating.\n", " for i in range(n):\n", " fxbin[dim, bins[i,dim] ] += abs(wfun[i]) # just bin the function f. We saved the bin position before. \n", "\n", "\n", "def Vegas_step3b(integrant, unit, maxeval, nstart, nincrease, grid, cum):\n", " ndim, nbins = grid.ndim,grid.nbins # dimension of the integral, size of the grid for binning in each direction\n", " unit_dim = unit**ndim # converts from unit cube integration to generalized cube with unit length\n", " nbatch=1000 # function will be evaluated in bacthes of 1000 evaluations at one time (for efficiency and storage issues)\n", " neval=0\n", " print (\"\"\"Vegas parameters:\n", " ndim = \"\"\"+str(ndim)+\"\"\"\n", " unit = \"\"\"+str(unit)+\"\"\"\n", " maxeval = \"\"\"+str(maxeval)+\"\"\"\n", " nstart = \"\"\"+str(nstart)+\"\"\"\n", " nincrease = \"\"\"+str(nincrease)+\"\"\"\n", " nbins = \"\"\"+str(nbins)+\"\"\"\n", " nbaths = \"\"\"+str(nbatch)+\"\\n\")\n", "\n", " bins = zeros((nbatch,ndim),dtype=int) # in which sampled bin does this point fall?\n", " \n", " \n", " all_nsamples = nstart\n", " for iter in range(1000): # NEW in step 3\n", " wgh = zeros(nbatch) # weights for each random point in the batch\n", " fxbin = zeros((ndim,nbins)) # after each iteration we reset the average function being binned\n", " for nsamples in range(all_nsamples,0,-nbatch): # loop over all_nsample evaluations in batches of nbatch\n", " n = min(nbatch,nsamples) # How many evaluations in this pass?\n", " # We are integrating f(g_1(x),g_2(y),g_3(z))*dg_1/dx*dg_2/dy*dg_3/dz dx*dy*dz\n", " # This is represented as 1/all_nsamples \\sum_{x_i,y_i,z_i} f(g_1(x_i),g_2(y_i),g_3(z_i))*dg_1/dx*dg_2/dy*dg_3/dz\n", " # where dg_1/dx = diff*NBINS\n", " xr = random.random((n,ndim)) # generates 2-d array of random numbers in the interval [0,1)\n", " pos = xr*nbins # (x*N)\n", " bins = array(pos,dtype=int) # which grid would it fit ? (x*N)\n", " wgh = ones(nbatch)/all_nsamples\n", " for dim in range(ndim): \n", " # We want to evaluate the function f at point g(x), i.e, f(g_1(x),g_2(y),...)\n", " # Here we transform the points x,y,z -> g_1(x), g_2(y), g_3(z)\n", " # We hence want to evaluate g(x) ~ g(x[i]), where x is the random number and g is the grid function\n", " # The discretized g(t) is defined on the grid :\n", " # t[-1]=0, t[0]=1/N, t[1]=2/N, t[2]=3/N ... t[N-1]=1.\n", " # We know that g(0)=0 and g(1)=1, so that g[-1]=0.0 and g[N-1]=1.0\n", " # To interpolate g at x, we first compute i=int(x*N) and then we use linear interpolation\n", " # g(x) = g[i-1] + (g[i]-g[i-1])*(x*N-int(x*N))\n", " gi = grid.g[dim,bins[:,dim]] # g[i]\n", " gm = grid.g[dim,bins[:,dim]-1] # g[i-1]\n", " diff = gi - gm # g[i]-g[i-1]\n", " gx = gm + (pos[:,dim]-bins[:,dim])*diff # linear interpolation g(xr)\n", " xr[:,dim] = gx*unit # xr <- g(xr)\n", " wgh *= diff*nbins # wgh = prod_{dim} dg/dx\n", " \n", " # Here we evaluate function f on all randomly generated x points above\n", " fx = integrant(xr) # n function evaluations required in single call\n", " neval += n # We just added so many fuction evaluations\n", " \n", " # Now we compute the integral as weighted average, namely, f(g(x))*dg/dx\n", " wfun = wgh * fx # weight * function ~ f_i*w_i \n", " cum.sum += sum(wfun) # sum_i f_i*w_i = \n", " wfun *= wfun # carefull : this is like (f_i * w_i/N)^2 hence 1/N (1/N (f_i*w_i)^2)\n", " cum.sqsum += sum(wfun) # sum_i (f_i*w_i)^2 = /all_nsamples\n", " # \n", " SetFxbin(fxbin,bins,wfun)\n", " #for dim in range(ndim): #new2\n", " # # Here we make a better approximation for the function, which we are integrating.\n", " # for i in range(n): #new2\n", " # fxbin[dim, bins[i,dim] ] += wfun[i] #new2: just bin the function f. We saved the bin position before.\n", " \n", " w0 = sqrt(cum.sqsum*all_nsamples) # w0 = sqrt()\n", " w1 = (w0 + cum.sum)*(w0 - cum.sum) # w1 = (w0^2 - ^2) = (-^2)\n", " w = (all_nsamples-1)/w1 # w ~ 1/sigma_i^2 = (N-1)/(-^2)\n", " # Note that variance of the MC sampling is Var(monte-f) = (-^2)/N == 1/sigma_i^2\n", " cum.weightsum += w # weightsum ~ \\sum_i 1/sigma_i^2\n", " cum.avgsum += w*cum.sum # avgsum ~ \\sum_i _i / sigma_i^2\n", " cum.avg2sum += w*cum.sum**2 # avg2cum ~ \\sum_i _i^2/sigma_i^2\n", " \n", " cum.avg = cum.avgsum/cum.weightsum # I_best = (\\sum_i _i/sigma_i^2 )/(\\sum_i 1/sigma_i^2)\n", " cum.err = sqrt(1/cum.weightsum) # err ~ sqrt(best sigma^2) = sqrt(1/(\\sum_i 1/sigma_i^2))\n", " \n", " # NEW in this step3\n", " if iter>0:\n", " cum.chisq = (cum.avg2sum - 2*cum.avgsum*cum.avg + cum.weightsum*cum.avg**2)/iter\n", " \n", " print (\"Iteration {:3d}: I= {:10.8f} +- {:10.8f} chisq= {:10.8f} number of evaluations = {:7d} \".format(iter+1, cum.avg*unit_dim, cum.err*unit_dim, cum.chisq, neval))\n", " imp = Smoothen(fxbin)\n", " grid.RefineGrid(imp)\n", " \n", " cum.sum=0 # clear the partial sum for the next step\n", " cum.sqsum=0\n", " all_nsamples += nincrease # for the next time, increase the number of steps a bit\n", " if (neval>=maxeval): break\n", " \n", " cum.avg *= unit**ndim\n", " cum.err *= unit**ndim" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vegas parameters:\n", " ndim = 3\n", " unit = 3.141592653589793\n", " maxeval = 2000000\n", " nstart = 100000\n", " nincrease = 5000\n", " nbins = 128\n", " nbaths = 1000\n", "\n", "Iteration 1: I= 1.36762346 +- 0.01023309 chisq= 0.00000000 number of evaluations = 100000 \n", "Iteration 2: I= 1.38308994 +- 0.00488295 chisq= 2.95787653 number of evaluations = 205000 \n", "Iteration 3: I= 1.38903765 +- 0.00341085 chisq= 2.92764168 number of evaluations = 315000 \n", "Iteration 4: I= 1.39085420 +- 0.00271957 chisq= 2.21131183 number of evaluations = 430000 \n", "Iteration 5: I= 1.39235286 +- 0.00238578 chisq= 1.98798517 number of evaluations = 550000 \n", "Iteration 6: I= 1.39215278 +- 0.00209328 chisq= 1.59649946 number of evaluations = 675000 \n", "Iteration 7: I= 1.39187814 +- 0.00186075 chisq= 1.34408861 number of evaluations = 805000 \n", "Iteration 8: I= 1.39040546 +- 0.00167503 chisq= 1.62389166 number of evaluations = 940000 \n", "Iteration 9: I= 1.39098400 +- 0.00155755 chisq= 1.53107506 number of evaluations = 1080000 \n", "Iteration 10: I= 1.39152488 +- 0.00144974 chisq= 1.46121875 number of evaluations = 1225000 \n", "Iteration 11: I= 1.39101550 +- 0.00135470 chisq= 1.41244571 number of evaluations = 1375000 \n", "Iteration 12: I= 1.39111487 +- 0.00127230 chisq= 1.28818899 number of evaluations = 1530000 \n", "Iteration 13: I= 1.39172957 +- 0.00120599 chisq= 1.37245777 number of evaluations = 1690000 \n", "Iteration 14: I= 1.39195626 +- 0.00114625 chisq= 1.29501238 number of evaluations = 1855000 \n", "Iteration 15: I= 1.39272504 +- 0.00110407 chisq= 1.64730521 number of evaluations = 2025000 \n", "1.3927250368308894 +- 0.0011040731205297308 exact= 1.3932 real error= 0.00034091528072821835\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "from scipy import *\n", "from numpy import *\n", "\n", "unit=pi\n", "ndim=3\n", "maxeval=2000000\n", "exact = 1.3932 # exact value of the integral\n", " \n", "cum = Cumulants()\n", " \n", "nbins=128\n", "nstart =100000\n", "nincrease=5000\n", "\n", "grid = Grid(ndim,nbins)\n", "\n", "random.seed(0)\n", "\n", "Vegas_step3b(my_integrant2, pi, maxeval, nstart, nincrease, grid, cum)\n", "\n", "print (cum.avg, '+-', cum.err, 'exact=', exact, 'real error=', abs(cum.avg-exact)/exact)\n", "\n", "plot(grid.g[0,:nbins])\n", "plot(grid.g[1,:nbins])\n", "plot(grid.g[2,:nbins])\n", "show()" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "## Homework\n", "\n", "* generalize Vegas algorithm so that the integration limits are given by arbitrary numbers [a,b]. You can still assume supercube in which all dimensions have the same limit [a,b].\n", "* Test Vegas on the same example $f=1/(1-\\cos(k_x)\\cos(k_y)\\cos(k_z))/\\pi^3$ but use limits $[-\\pi,\\pi]$ instead of $[0,\\pi]$.\n", "* Speed up the part of the code that Redefines the grid `RefineGrid`\n", "* generalize Vegas so that it works for complex functions.\n", "* Using Vegas, evaluate the following Linhardt function:\n", "\n", "\\begin{eqnarray}\n", "P(\\Omega,\\vec{q}) = -2 \\int \\frac{d^3k}{(2\\pi)^3} \\frac{f(\\varepsilon_{\\vec{k}+\\vec{q}})-f(\\varepsilon_{\\vec{k}})}{\\Omega-\\varepsilon_{\\vec{k}+\\vec{q}}+\\varepsilon_\\vec{k}+i\\delta}\n", "\\end{eqnarray}\n", "\n", "Here $\\varepsilon_\\vec{k}=k^2-k_F^2$.\n", "\n", "We will use $k_F=\\frac{(\\frac{9\\pi}{4})^{1/3}}{rs}$ with $r_s=2$, $f(x) = 1/(\\exp(x/T)+1)$, $T=0.02 k_F^2$, $\\delta = 0.002 k_F^2$, $\\Omega=0$, $q=0.1 k_F$, integration limits can be set to $[-3 k_F,3 k_F]$.\n", "\n", "The result for $P(\\Omega=0,q<< k_F)$ should be close to $-n_F$, where $n_F = \\frac{k_F}{2\\pi^2}$.\n", "\n", "* Optional: Change the Vegas algorithm so that it computes $P(\\Omega,\\vec{q})$ at once for an array of $\\Omega$ points, such as `linspace(0,0.5*kF*kF,200)`. Use $P(\\Omega=0)$ to redefine the grid, so that we have most efficient integration at $\\Omega=0$ (where the function is hardest to integrate)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.5" } }, "nbformat": 4, "nbformat_minor": 2 }