diff options
Diffstat (limited to 'src/divonne')
-rw-r--r-- | src/divonne/Divonne.c | 157 | ||||
-rw-r--r-- | src/divonne/Divonne.tm | 429 | ||||
-rw-r--r-- | src/divonne/Explore.c | 160 | ||||
-rw-r--r-- | src/divonne/FindMinimum.c | 689 | ||||
-rw-r--r-- | src/divonne/Integrate.c | 452 | ||||
-rw-r--r-- | src/divonne/Iterate.c | 138 | ||||
-rw-r--r-- | src/divonne/KorobovCoeff.c | 881 | ||||
-rw-r--r-- | src/divonne/Rule.c | 685 | ||||
-rw-r--r-- | src/divonne/Sample.c | 261 | ||||
-rw-r--r-- | src/divonne/Split.c | 311 | ||||
-rw-r--r-- | src/divonne/common.c | 34 | ||||
-rw-r--r-- | src/divonne/decl.h | 127 |
12 files changed, 4324 insertions, 0 deletions
diff --git a/src/divonne/Divonne.c b/src/divonne/Divonne.c new file mode 100644 index 0000000..5fcaada --- /dev/null +++ b/src/divonne/Divonne.c @@ -0,0 +1,157 @@ +/* + Divonne.c + Multidimensional integration by partitioning + originally by J.H. Friedman and M.H. Wright + (CERNLIB subroutine D151) + this version by Thomas Hahn + last modified 15 Nov 11 th +*/ + +#include "decl.h" + +#define Print(s) puts(s); fflush(stdout) + +/*********************************************************************/ + +#define DIVONNE +static void DoSample(This *t, number n, creal *x, real *f, ccount ldx); +static int ExploreParent(This *t, cint iregion); + +/*********************************************************************/ + +static inline count SampleExtra(This *t, cBounds *b) +{ + number n = t->nextra; + t->peakfinder(&t->ndim, b, &n, t->xextra); + DoSample(t, n, t->xextra, t->fextra, t->ldxgiven); + return n; +} + +/*********************************************************************/ + +static inline void AllocGiven(This *t, creal *xgiven) +{ + if( t->ngiven | t->nextra ) { + cnumber nxgiven = t->ngiven*(t->ldxgiven = IMax(t->ldxgiven, t->ndim)); + cnumber nxextra = t->nextra*t->ldxgiven; + cnumber nfgiven = t->ngiven*t->ncomp; + cnumber nfextra = t->nextra*t->ncomp; + + Alloc(t->xgiven, nxgiven + nxextra + nfgiven + nfextra); + t->xextra = t->xgiven + nxgiven; + t->fgiven = t->xextra + nxextra; + t->fextra = t->fgiven + nfgiven; + + if( nxgiven ) { + t->phase = 0; + Copy(t->xgiven, xgiven, nxgiven); + DoSample(t, t->ngiven, t->xgiven, t->fgiven, t->ldxgiven); + } + } +} + +/*********************************************************************/ + +#include "common.c" +#include "DoSample.c" + +Extern void EXPORT(Divonne)(ccount ndim, ccount ncomp, + Integrand integrand, void *userdata, + creal epsrel, creal epsabs, + cint flags, cint seed, + cnumber mineval, cnumber maxeval, + cint key1, cint key2, cint key3, ccount maxpass, + creal border, creal maxchisq, creal mindeviation, + cnumber ngiven, ccount ldxgiven, creal *xgiven, + cnumber nextra, PeakFinder peakfinder, + int *pnregions, number *pneval, int *pfail, + real *integral, real *error, real *prob) +{ + This t; + t.ndim = ndim; + t.ncomp = ncomp; + t.integrand = integrand; + t.userdata = userdata; + t.epsrel = epsrel; + t.epsabs = epsabs; + t.flags = flags; + t.seed = seed; + t.mineval = mineval; + t.maxeval = maxeval; + t.key1 = key1; + t.key2 = key2; + t.key3 = key3; + t.maxpass = maxpass; + t.border.upper = 1 - (t.border.lower = border); + t.maxchisq = maxchisq; + t.mindeviation = mindeviation; + t.ngiven = ngiven; + t.xgiven = NULL; + t.ldxgiven = ldxgiven; + t.nextra = nextra; + t.peakfinder = peakfinder; + t.nregions = 0; + t.neval = 0; + + ForkCores(&t); + AllocGiven(&t, xgiven); + + *pfail = Integrate(&t, integral, error, prob); + *pnregions = t.nregions; + *pneval = t.neval; + + free(t.xgiven); + WaitCores(&t); +} + +/*********************************************************************/ + +Extern void EXPORT(divonne)(ccount *pndim, ccount *pncomp, + Integrand integrand, void *userdata, + creal *pepsrel, creal *pepsabs, + cint *pflags, cint *pseed, + cnumber *pmineval, cnumber *pmaxeval, + cint *pkey1, cint *pkey2, cint *pkey3, ccount *pmaxpass, + creal *pborder, creal *pmaxchisq, creal *pmindeviation, + cnumber *pngiven, ccount *pldxgiven, creal *xgiven, + cnumber *pnextra, PeakFinder peakfinder, + int *pnregions, number *pneval, int *pfail, + real *integral, real *error, real *prob) +{ + This t; + t.ndim = *pndim; + t.ncomp = *pncomp; + t.integrand = integrand; + t.userdata = userdata; + t.epsrel = *pepsrel; + t.epsabs = *pepsabs; + t.flags = *pflags; + t.seed = *pseed; + t.mineval = *pmineval; + t.maxeval = *pmaxeval; + t.key1 = *pkey1; + t.key2 = *pkey2; + t.key3 = *pkey3; + t.maxpass = *pmaxpass; + t.border.upper = 1 - (t.border.lower = *pborder); + t.maxchisq = *pmaxchisq; + t.mindeviation = *pmindeviation; + t.ngiven = *pngiven; + t.xgiven = NULL; + t.ldxgiven = *pldxgiven; + t.nextra = *pnextra; + t.peakfinder = peakfinder; + t.nregions = 0; + t.neval = 0; + + ForkCores(&t); + AllocGiven(&t, xgiven); + + *pfail = Integrate(&t, integral, error, prob); + *pnregions = t.nregions; + *pneval = t.neval; + + free(t.xgiven); + WaitCores(&t); +} + diff --git a/src/divonne/Divonne.tm b/src/divonne/Divonne.tm new file mode 100644 index 0000000..bcb8b88 --- /dev/null +++ b/src/divonne/Divonne.tm @@ -0,0 +1,429 @@ +:Evaluate: BeginPackage["Cuba`"] + +:Evaluate: Divonne::usage = + "Divonne[f, {x, xmin, xmax}..] computes a numerical approximation to the integral of the real scalar or vector function f. + The output is a list with entries of the form {integral, error, chi-square probability} for each component of the integrand." + +:Evaluate: Key1::usage = "Key1 is an option of Divonne. + It determines sampling in the partitioning phase.\n + Special cases:\n + Key1 = 7: use a degree-7 cubature rule,\n + Key1 = 9: use a degree-9 cubature rule,\n + Key1 = 11: use a degree-11 cubature rule (available only in 3 dimensions),\n + Key1 = 13: use a degree-13 cubature rule (available only in 2 dimensions),\n + otherwise a random sample of n1 = Abs[Key1] points is used, where the sign of Key1 determines the type of sample:\n + Key1 > 0: use a Korobov quasi-random sample,\n + Key1 < 0: use a \"standard\" sample." + +:Evaluate: Key2::usage = "Key2 is an option of Divonne. + It determines sampling in the main integration phase.\n + Special cases:\n + Key2 = 7: use a degree-7 cubature rule,\n + Key2 = 9: use a degree-9 cubature rule,\n + Key2 = 11: use a degree-11 cubature rule (available only in 3 dimensions),\n + Key2 = 13: use a degree-13 cubature rule (available only in 2 dimensions),\n + otherwise a random sample is used, where the sign of Key2 determines the type of sample:\n + Key2 > 0: use a Korobov quasi-random sample,\n + Key2 < 0: use a \"standard\" sample,\n + and n2 = Abs[Key2] determines the number of points:\n + n2 >= 40: sample n2 points,\n + n2 < 40: sample n2*nneed points, where nneed is the number of points needed to reach the prescribed accuracy, as estimated by Divonne from the results of the partitioning phase." + +:Evaluate: Key3::usage = "Key3 is an option of Divonne. + It sets the strategy for the refinement phase:\n + Key3 = 0: do not further treat the subregion,\n + Key3 = 1: split the subregion up once more,\n + for other values the region is sampled a third time:\n + Key3 = 7: use a degree-7 cubature rule,\n + Key3 = 9: use a degree-9 cubature rule,\n + Key3 = 11: use a degree-11 cubature rule (available only in 3 dimensions),\n + Key3 = 13: use a degree-13 cubature rule (available only in 2 dimensions),\n + otherwise a random sample is used, where the sign of Key3 determines the type of sample:\n + Key3 > 0: use a Korobov quasi-random sample,\n + Key3 < 0: use a \"standard\" sample,\n + and n3 = Abs[Key3] determines the number of points:\n + n3 >= 40: sample n3 points,\n + n3 < 40: sample n3*nneed points, where nneed is the number of points needed to reach the prescribed accuracy, as estimated by Divonne from the results of the partitioning phase." + +:Evaluate: MaxPass::usage = "MaxPass is an option of Divonne. + It controls the partitioning termination. + The partitioning phase is terminated when the estimated total number of integrand evaluations (partitioning plus main integration) does not decrease for MaxPass successive iterations." + +:Evaluate: Border::usage = "Border is an option of Divonne. + It specifies the width of the border of the integration region. + Points falling into this border region are not sampled directly, but are extrapolated from two samples from the interior. + The border width always refers to the unit hypercube, i.e. it is not rescaled if the integration region is not the unit hypercube." + +:Evaluate: MaxChisq::usage = "MaxChisq is an option of Divonne. + It specifies the maximum chi-square value a single subregion is allowed to have in the main integration phase. + Regions which fail this chi-square test and whose sample averages differ by more than MinDeviation move on to the refinement phase." + +:Evaluate: MinDeviation::usage = "MinDeviation is an option of Divonne. + Regions which fail the chi-square test are not treated further if their sample averages differ by less than MinDeviation. + MinDeviation is specified as the fraction of the requested error of the entire integral." + +:Evaluate: Given::usage = "Given is an option of Divonne. + It provides a list of points where the integrand might have peaks. + Divonne will consider these points when partitioning the integration region." + +:Evaluate: NExtra::usage = "NExtra is an option of Divonne. + It specifies the maximum number of points that will be considered in the output of the PeakFinder function." + +:Evaluate: PeakFinder::usage = "PeakFinder is an option of Divonne. + It specifies the peak-finder function. + This function is called whenever a region is up for subdivision and is supposed to point out possible peaks lying in the region, thus acting as the dynamic counterpart of the static list of points supplied with Given. + It is invoked with two arguments, the multidimensional equivalents of the lower left and upper right corners of the region being investigated, and must return a (possibly empty) list of points." + +:Evaluate: MinPoints::usage = "MinPoints is an option of Divonne. + It specifies the minimum number of points to sample." + +:Evaluate: Final::usage = "Final is an option of Divonne. + It can take the values Last or All which determine whether only the last (largest) or all sets of samples collected on a subregion over the integration phases contribute to the final result." + +:Evaluate: PseudoRandom::usage = "PseudoRandom is an option of Divonne. + It can take the following values: + False for Sobol quasi-random numbers (default), + True or 0 for Mersenne Twister pseudo-random numbers, + any other integer value n for Ranlux pseudo-random numbers of luxury level n." + +:Evaluate: PseudoRandomSeed::usage = "PseudoRandomSeed is an option of Divonne. + It specifies the seed for the pseudo-random number generator." + +:Evaluate: Regions::usage = "Regions is an option of Divonne. + It specifies whether the regions into which the integration region has been cut are returned together with the integration results." + +:Evaluate: Region::usage = "Region[ll, ur, res, df] describes a subregion: + ll and ur are multidimensional equivalents of the region's lower left and upper right corner. + res gives the integration results for the region in a list with entries of the form {integral, error, chi-square} for each component of the integrand. + df is the number of degrees of freedom corresponding to the chi-square values in res." + +:Evaluate: $Phase::usage = "$Phase is a global variable set by Divonne during the evaluation of the integrand to the integration phase:\n + 0 = sampling of the points in xgiven,\n + 1 = partitioning phase,\n + 2 = main integration phase,\n + 3 = refinement phase." + +:Evaluate: MapSample::usage = "MapSample is a function used to map the integrand over the points to be sampled." + + +:Evaluate: Begin["`Divonne`"] + +:Begin: +:Function: Divonne +:Pattern: MLDivonne[ndim_, ncomp_, + epsrel_, epsabs_, flags_, seed_, + mineval_, maxeval_, + key1_, key2_, key3_, maxpass_, + border_, maxchisq_, mindeviation_, + xgiven_, fgiven_, nextra_] +:Arguments: {ndim, ncomp, + epsrel, epsabs, flags, seed, + mineval, maxeval, + key1, key2, key3, maxpass, + border, maxchisq, mindeviation, + xgiven, fgiven, nextra} +:ArgumentTypes: {Integer, Integer, + Real, Real, Integer, Integer, + Integer, Integer, + Integer, Integer, Integer, Integer, + Real, Real, Real, + RealList, RealList, Integer} +:ReturnType: Manual +:End: + +:Evaluate: Attributes[Divonne] = {HoldFirst} + +:Evaluate: Options[Divonne] = {PrecisionGoal -> 3, AccuracyGoal -> 12, + MinPoints -> 0, MaxPoints -> 50000, + Key1 -> 47, Key2 -> 1, Key3 -> 1, MaxPass -> 5, + Border -> 0, MaxChisq -> 10, MinDeviation -> .25, + Given -> {}, NExtra -> 0, PeakFinder -> ({}&), + Verbose -> 1, Final -> All, + PseudoRandom -> False, PseudoRandomSeed -> 5489, + Regions -> False, Compiled -> True} + +:Evaluate: Divonne[f_, v:{_, _, _}.., opt___Rule] := + Block[ {ff = HoldForm[f], ndim = Length[{v}], ncomp, + tags, vars, lower, range, jac, tmp, defs, intT, intX, + rel, abs, mineval, maxeval, key1, key2, key3, maxpass, border, + maxchisq, mindeviation, given, nextra, peakfinder, + final, verbose, level, seed, regions, compiled, + $Phase}, + Message[Divonne::optx, #, Divonne]&/@ + Complement[First/@ {opt}, tags = First/@ Options[Divonne]]; + {rel, abs, mineval, maxeval, key1, key2, key3, maxpass, border, + maxchisq, mindeviation, given, nextra, peakfinder, + verbose, final, level, seed, regions, compiled} = + tags /. {opt} /. Options[Divonne]; + {vars, lower, range} = Transpose[{v}]; + jac = Simplify[Times@@ (range -= lower)]; + tmp = Array[tmpvar, ndim]; + defs = Simplify[lower + range tmp]; + Block[{Set}, define[compiled, tmp, vars, Thread[vars = defs], jac]]; + intT = integrandT[f]; + intX = integrandX[f]; + Block[#, + ncomp = Length[intT@@ RandomReal[1, ndim]]; + MLDivonne[ndim, ncomp, 10.^-rel, 10.^-abs, + Min[Max[verbose, 0], 3] + + If[final === Last, 4, 0] + + If[TrueQ[regions], 128, 0] + + If[IntegerQ[level], 256 level, 0], + If[level =!= False && IntegerQ[seed], seed, 0], + mineval, maxeval, + key1, key2, key3, maxpass, + N[border], N[maxchisq], N[mindeviation], + given, sample[given, 0, intX], nextra] + ]& @ vars + ] + +:Evaluate: tmpvar[n_] := ToExpression["Cuba`Divonne`t" <> ToString[n]] + +:Evaluate: Attributes[foo] = {HoldAll} + +:Evaluate: define[True, tmp_, vars_, defs_, jac_] := ( + TtoX := TtoX = Compile[tmp, defs]; + integrandT[f_] := Compile[tmp, eval[defs, Chop[f jac]//N], + {{_eval, _Real, 1}}]; + integrandX[f_] := Compile[vars, eval[vars, Chop[f jac]//N], + {{_eval, _Real, 1}}] ) + +:Evaluate: define[_, tmp_, vars_, defs_, jac_] := ( + TtoX := TtoX = Function[tmp, defs]; + integrandT[f_] := Function[tmp, eval[defs, Chop[f jac]//N]]; + integrandX[f_] := Function[vars, eval[vars, Chop[f jac]//N]] ) + +:Evaluate: eval[_, f_Real] := {f} + +:Evaluate: eval[_, f:{__Real}] := f + +:Evaluate: eval[x_, _] := (Message[Divonne::badsample, ff, x]; {}) + +:Evaluate: sample[x_, p_, i_:intT] := ( + $Phase = p; + Check[Flatten @ MapSample[i@@ # &, Partition[x, ndim]], {}] ) + +:Evaluate: MapSample = Map + +:Evaluate: findpeak[b_, p_] := Check[Join[#, sample[#, p, intX]]& @ + N[Flatten[peakfinder@@ MapThread[TtoX, Partition[b, 2]]]], {}] + +:Evaluate: region[ll_, ur_, r___] := Region[TtoX@@ ll, TtoX@@ ur, r] + +:Evaluate: Divonne::badsample = "`` is not a real-valued function at ``." + +:Evaluate: Divonne::baddim = "Cannot integrate in `` dimensions." + +:Evaluate: Divonne::badcomp = "Cannot integrate `` components." + +:Evaluate: Divonne::accuracy = + "Desired accuracy was not reached within `` integrand evaluations on `` subregions. + Estimate that MaxPoints needs to be increased by `` for this accuracy." + +:Evaluate: Divonne::success = "Needed `` integrand evaluations on `` subregions." + +:Evaluate: End[] + +:Evaluate: EndPackage[] + + +/* + Divonne.tm + Multidimensional integration by partitioning + originally by J.H. Friedman and M.H. Wright + (CERNLIB subroutine D151) + this version by Thomas Hahn + last modified 12 Oct 11 th +*/ + + +#include "mathlink.h" +#include "decl.h" + +#define ExploreParent Explore + +/*********************************************************************/ + +static void Status(MLCONST char *msg, cint n1, cint n2, cint n3) +{ + MLPutFunction(stdlink, "CompoundExpression", 2); + MLPutFunction(stdlink, "Message", 4); + MLPutFunction(stdlink, "MessageName", 2); + MLPutSymbol(stdlink, "Divonne"); + MLPutString(stdlink, msg); + MLPutInteger(stdlink, n1); + MLPutInteger(stdlink, n2); + MLPutInteger(stdlink, n3); +} + +/*********************************************************************/ + +static void Print(MLCONST char *s) +{ + MLPutFunction(stdlink, "EvaluatePacket", 1); + MLPutFunction(stdlink, "Print", 1); + MLPutString(stdlink, s); + MLEndPacket(stdlink); + + MLNextPacket(stdlink); + MLNewPacket(stdlink); +} + +/*********************************************************************/ + +static void DoSample(This *t, cnumber n, real *x, real *f, ccount ldx) +{ + real *mma_f; + long mma_n; + + if( MLAbort ) longjmp(t->abort, -99); + + MLPutFunction(stdlink, "EvaluatePacket", 1); + MLPutFunction(stdlink, "Cuba`Divonne`sample", 2); + MLPutRealList(stdlink, x, n*t->ndim); + MLPutInteger(stdlink, t->phase); + MLEndPacket(stdlink); + + MLNextPacket(stdlink); + if( !MLGetRealList(stdlink, &mma_f, &mma_n) ) { + MLClearError(stdlink); + MLNewPacket(stdlink); + longjmp(t->abort, -99); + } + + if( mma_n != n*t->ncomp ) { + MLDisownRealList(stdlink, mma_f, mma_n); + longjmp(t->abort, -3); + } + + t->neval += n; + + Copy(f, mma_f, n*t->ncomp); + MLDisownRealList(stdlink, mma_f, mma_n); +} + +/*********************************************************************/ + +static count SampleExtra(This *t, cBounds *b) +{ + count n, nget; + real *mma_f; + long mma_n; + + MLPutFunction(stdlink, "EvaluatePacket", 1); + MLPutFunction(stdlink, "Cuba`Divonne`findpeak", 2); + MLPutRealList(stdlink, (real *)b, 2*t->ndim); + MLPutInteger(stdlink, t->phase); + MLEndPacket(stdlink); + + MLNextPacket(stdlink); + if( !MLGetRealList(stdlink, &mma_f, &mma_n) ) { + MLClearError(stdlink); + MLNewPacket(stdlink); + longjmp(t->abort, -99); + } + + t->neval += nget = mma_n/(t->ndim + t->ncomp); + + n = IMin(nget, t->nextra); + if( n ) { + Copy(t->xextra, mma_f, n*t->ndim); + Copy(t->fextra, mma_f + nget*t->ndim, n*t->ncomp); + } + + MLDisownRealList(stdlink, mma_f, mma_n); + + return n; +} + +/*********************************************************************/ + +#include "common.c" + +static inline void DoIntegrate(This *t) +{ + real integral[NCOMP], error[NCOMP], prob[NCOMP]; + cint fail = Integrate(t, integral, error, prob); + + if( fail < 0 ) { + switch( fail ) { + case -99: + MLPutFunction(stdlink, "Abort", 0); + return; + case -1: + Status("baddim", t->ndim, 0, 0); + break; + case -2: + Status("badcomp", t->ncomp, 0, 0); + break; + } + MLPutSymbol(stdlink, "$Failed"); + } + else { + Status(fail ? "accuracy" : "success", t->neval, t->nregions, fail); + MLPutFunction(stdlink, "Thread", 1); + MLPutFunction(stdlink, "List", 3); + MLPutRealList(stdlink, integral, t->ncomp); + MLPutRealList(stdlink, error, t->ncomp); + MLPutRealList(stdlink, prob, t->ncomp); + } +} + +/*********************************************************************/ + +void Divonne(cint ndim, cint ncomp, + creal epsrel, creal epsabs, + cint flags, cint seed, + cnumber mineval, cnumber maxeval, + cint key1, cint key2, cint key3, cint maxpass, + creal border, creal maxchisq, creal mindeviation, + real *xgiven, clong nxgiven, real *fgiven, clong nfgiven, + cnumber nextra) +{ + This t; + t.ldxgiven = t.ndim = ndim; + t.ncomp = ncomp; + t.epsrel = epsrel; + t.epsabs = epsabs; + t.flags = flags; + t.seed = seed; + t.mineval = mineval; + t.maxeval = maxeval; + t.key1 = key1; + t.key2 = key2; + t.key3 = key3; + t.maxpass = maxpass; + t.border.upper = 1 - (t.border.lower = border); + t.maxchisq = maxchisq; + t.mindeviation = mindeviation; + t.xgiven = NULL; + t.nextra = nextra; + t.nregions = 0; + t.neval = t.ngiven = nxgiven/ndim; + + if( t.ngiven | t.nextra ) { + cnumber nx = nxgiven + nextra*t.ndim; + cnumber nf = nfgiven + nextra*t.ncomp; + + Alloc(t.xgiven, nx + nf); + t.xextra = t.xgiven + nxgiven; + t.fgiven = t.xgiven + nx; + t.fextra = t.fgiven + nfgiven; + + Copy(t.xgiven, xgiven, nxgiven); + Copy(t.fgiven, fgiven, nfgiven); + } + + DoIntegrate(&t); + + free(t.xgiven); + MLEndPacket(stdlink); +} + +/*********************************************************************/ + +int main(int argc, char **argv) +{ + return MLMain(argc, argv); +} + diff --git a/src/divonne/Explore.c b/src/divonne/Explore.c new file mode 100644 index 0000000..d6fba19 --- /dev/null +++ b/src/divonne/Explore.c @@ -0,0 +1,160 @@ +/* + Explore.c + sample region, determine min and max, split if necessary + this file is part of Divonne + last modified 15 Nov 11 th +*/ + + +typedef struct { + real fmin, fmax; + creal *xmin, *xmax; +} Extrema; + +/*********************************************************************/ + +static int Explore(This *t, ccount iregion) +{ + TYPEDEFREGION; + Region *region = RegionPtr(iregion); + cBounds *bounds = region->bounds; + Result *result = region->result; + + count n, dim, comp, maxcomp; + Extrema extrema[NCOMP]; + Result *r; + creal *x; + real *f; + real halfvol, maxerr; + cSamples *samples = &t->samples[region->isamples]; + + /* needed as of gcc 3.3 to make gcc correctly address region #@$&! */ + sizeof(*region); + + for( comp = 0; comp < t->ncomp; ++comp ) { + Extrema *e = &extrema[comp]; + e->fmin = INFTY; + e->fmax = -INFTY; + e->xmin = e->xmax = NULL; + } + + if( region->isamples == 0 ) { /* others already sampled */ + real vol = 1; + for( dim = 0; dim < t->ndim; ++dim ) { + cBounds *b = &bounds[dim]; + vol *= b->upper - b->lower; + } + region->vol = vol; + + for( comp = 0; comp < t->ncomp; ++comp ) { + Result *r = &result[comp]; + r->fmin = INFTY; + r->fmax = -INFTY; + } + + x = t->xgiven; + f = t->fgiven; + n = t->ngiven; + if( t->nextra ) n += SampleExtra(t, bounds); + + for( ; n; --n ) { + for( dim = 0; dim < t->ndim; ++dim ) { + cBounds *b = &bounds[dim]; + if( x[dim] < b->lower || x[dim] > b->upper ) goto skip; + } + for( comp = 0; comp < t->ncomp; ++comp ) { + Extrema *e = &extrema[comp]; + creal y = f[comp]; + if( y < e->fmin ) e->fmin = y, e->xmin = x; + if( y > e->fmax ) e->fmax = y, e->xmax = x; + } +skip: + x += t->ldxgiven; + f += t->ncomp; + } + + samples->sampler(t, iregion); + } + + x = samples->x; + f = samples->f; + for( n = samples->n; n; --n ) { + for( comp = 0; comp < t->ncomp; ++comp ) { + Extrema *e = &extrema[comp]; + creal y = *f++; + if( y < e->fmin ) e->fmin = y, e->xmin = x; + if( y > e->fmax ) e->fmax = y, e->xmax = x; + } + x += t->ndim; + } + t->neval_opt -= t->neval; + + halfvol = .5*region->vol; + maxerr = -INFTY; + maxcomp = -1; + + for( comp = 0; comp < t->ncomp; ++comp ) { + Extrema *e = &extrema[comp]; + Result *r = &result[comp]; + real xtmp[NDIM], ftmp, err; + + if( e->xmin ) { /* not all NaNs */ + t->selectedcomp = comp; + VecCopy(xtmp, e->xmin); + ftmp = FindMinimum(t, bounds, xtmp, e->fmin); + if( ftmp < r->fmin ) { + r->fmin = ftmp; + VecCopy(r->xmin, xtmp); + } + + t->selectedcomp = Tag(comp); + VecCopy(xtmp, e->xmax); + ftmp = -FindMinimum(t, bounds, xtmp, -e->fmax); + if( ftmp > r->fmax ) { + r->fmax = ftmp; + VecCopy(r->xmax, xtmp); + } + } + + r->spread = halfvol*(r->fmax - r->fmin); + err = r->spread/Max(fabs(r->avg), NOTZERO); + if( err > maxerr ) { + maxerr = err; + maxcomp = comp; + } + } + + t->neval_opt += t->neval; + + if( maxcomp == -1 ) { /* all NaNs */ + region->depth = 0; + return -1; + } + + region->cutcomp = maxcomp; + r = ®ion->result[maxcomp]; + if( halfvol*(r->fmin + r->fmax) > r->avg ) { + region->fminor = r->fmin; + region->fmajor = r->fmax; + region->xmajor = r->xmax - (real *)region->result; + } + else { + region->fminor = r->fmax; + region->fmajor = r->fmin; + region->xmajor = r->xmin - (real *)region->result; + } + + if( region->isamples == 0 ) { + if( r->spread < samples->neff*r->err || + r->spread < t->totals[maxcomp].secondspread ) region->depth = 0; + if( region->depth == 0 ) + for( comp = 0; comp < t->ncomp; ++comp ) + t->totals[comp].secondspread = + Max(t->totals[comp].secondspread, result[comp].spread); + } + + if( region->depth ) Split(t, iregion); + + return iregion; +} + diff --git a/src/divonne/FindMinimum.c b/src/divonne/FindMinimum.c new file mode 100644 index 0000000..b476520 --- /dev/null +++ b/src/divonne/FindMinimum.c @@ -0,0 +1,689 @@ +/* + FindMinimum.c + find minimum (maximum) of hyperrectangular region + this file is part of Divonne + last modified 8 Jun 10 th +*/ + + +#define EPS 0x1p-52 +#define RTEPS 0x1p-26 +#define QEPS 0x1p-13 + +#define DELTA 0x1p-16 +#define RTDELTA 0x1p-8 +#define QDELTA 0x1p-4 + +/* +#define DELTA 1e-5 +#define RTDELTA 3.1622776601683791e-3 +#define QDELTA 5.6234132519034912e-2 +*/ + +#define SUFTOL 8*QEPS*QDELTA +#define FTOL 5e-2 +#define GTOL 1e-2 + +#define Hessian(i, j) hessian[(i)*t->ndim + j] + +typedef struct { real dx, f; } Point; + +/*********************************************************************/ + +static inline real Dot(ccount n, creal *a, creal *b) +{ + real sum = 0; + count i; + for( i = 0; i < n; ++i ) sum += a[i]*b[i]; + return sum; +} + +/*********************************************************************/ + +static inline real Length(ccount n, creal *vec) +{ + return sqrt(Dot(n, vec, vec)); +} + +/*********************************************************************/ + +static inline void LinearSolve(cThis *t, ccount n, creal *hessian, + creal *grad, real *p) +{ + int i, j; + real dir; + + for( i = 0; i < n; ++i ) { + dir = -grad[i]; + for( j = 0; j < i; ++j ) + dir -= Hessian(i, j)*p[j]; + p[i] = dir; + } + + while( --i >= 0 ) { + if( Hessian(i, i) <= 0 ) return; + dir = p[i]/Hessian(i, i); + for( j = i + 1; j < n; ++j ) + dir -= Hessian(j, i)*p[j]; + p[i] = dir; + } +} + +/*********************************************************************/ + +static void RenormalizeCholesky(cThis *t, ccount n, real *hessian, + real *z, real alpha) +{ + count i, j; + + for( i = 0; i < n; ++i ) { + creal dir = z[i]; + real beta = alpha*dir; + real gamma = Hessian(i, i); + real gammanew = Hessian(i, i) += beta*dir; + + if( i + 1 >= n || gammanew < 0 || + (gammanew < 1 && gamma > DBL_MAX*gammanew) ) return; + + gamma /= gammanew; + beta /= gammanew; + alpha *= gamma; + + if( gamma < .25 ) { + for( j = i + 1; j < n; ++j ) { + real delta = beta*z[j]; + z[j] -= dir*Hessian(j, i); + Hessian(j, i) = Hessian(j, i)*gamma + delta; + } + } + else { + for( j = i + 1; j < n; ++j ) { + z[j] -= dir*Hessian(j, i); + Hessian(j, i) += beta*z[j]; + } + } + } +} + +/*********************************************************************/ + +static void UpdateCholesky(cThis *t, ccount n, real *hessian, + real *z, real *p) +{ + int i, j; + real gamma = 0; + + for( i = 0; i < n; ++i ) { + real dir = z[i]; + for( j = 0; j < i; ++j ) + dir -= Hessian(i, j)*p[j]; + p[i] = dir; + gamma += Sq(dir)/Hessian(i, i); + } + gamma = Max(fabs(1 - gamma), EPS); + + while( --i >= 0 ) { + creal dir = z[i] = p[i]; + real beta = dir/Hessian(i, i); + creal gammanew = gamma + dir*beta; + Hessian(i, i) *= gamma/gammanew; + beta /= gamma; + gamma = gammanew; + for( j = i + 1; j < n; ++j ) { + creal delta = beta*z[j]; + z[j] += dir*Hessian(j, i); + Hessian(j, i) -= delta; + } + } +} + +/*********************************************************************/ + +static inline void BFGS(cThis *t, ccount n, real *hessian, + creal *gnew, creal *g, real *p, creal dx) +{ + real y[NDIM], c; + count i, j; + + for( i = 0; i < n; ++i ) + y[i] = gnew[i] - g[i]; + c = dx*Dot(n, y, p); + if( c < 1e-10 ) return; + RenormalizeCholesky(t, n, hessian, y, 1/c); + + c = Dot(n, g, p); + if( c >= 0 ) return; + c = 1/sqrt(-c); + for( i = 0; i < n; ++i ) + y[i] = c*g[i]; + UpdateCholesky(t, n, hessian, y, p); + + for( i = 0; i < n - 1; ++i ) + for( j = i + 1; j < n; ++j ) + Hessian(i, j) = Hessian(j, i); +} + +/*********************************************************************/ + +static void Gradient(This *t, ccount nfree, ccount *ifree, + cBounds *b, real *x, creal y, real *grad) +{ + count i; + + for( i = 0; i < nfree; ++i ) { + ccount dim = Untag(ifree[i]); + creal xd = x[dim]; + creal delta = (b[dim].upper - xd < DELTA) ? -DELTA : DELTA; + x[dim] += delta; + grad[i] = (Sample(t, x) - y)/delta; + x[dim] = xd; + } +} + +/*********************************************************************/ + +static Point LineSearch(This *t, ccount nfree, ccount *ifree, + creal *p, creal *xini, real fini, real *x, + real step, creal range, creal grad, + creal ftol, creal xtol, creal gtol) +{ + real tol = ftol, tol2 = tol + tol; + Point cur = {0, fini}; + + VecCopy(x, xini); + + /* don't even try if + a) we'd walk backwards, + b) the range to explore is too small, + c) the gradient is positive, i.e. we'd move uphill */ + + if( step > 0 && range > tol2 && grad <= 0 ) { + creal eps = RTEPS*fabs(range) + ftol; + creal mingrad = -1e-4*grad, maxgrad = -gtol*grad; + + real end = range + eps; + real maxstep = range - eps/(1 + RTEPS); + + Point min = cur, v = cur, w = cur; + Point a = cur, b = {end, 0}; + real a1, b1 = end; + + /* distmin: distance along p from xini to the minimum, + u: second-lowest point, + v: third-lowest point, + a, b: interval in which the minimum is sought. */ + + real distmin = 0, dist, mid, q, r, s; + count i; + int shift; + bool first; + + for( first = true; ; first = false ) { + if( step >= maxstep ) { + step = maxstep; + maxstep = maxstep*(1 + .75*RTEPS) + .75*tol; + } + + cur.dx = (fabs(step) >= tol) ? step : (step > 0) ? tol : -tol; + dist = distmin + cur.dx; + for( i = 0; i < nfree; ++i ) { + ccount dim = ifree[i]; + x[dim] = xini[dim] + dist*p[i]; + } + cur.f = Sample(t, x); + + if( cur.f <= min.f ) { + v = w; + w = min; + min.f = cur.f; + distmin = dist; + + /* shift everything to the new minimum position */ + maxstep -= cur.dx; + v.dx -= cur.dx; + w.dx -= cur.dx; + a.dx -= cur.dx; + b.dx -= cur.dx; + if( cur.dx < 0 ) b = w; + else a = w; + + tol = RTEPS*fabs(distmin) + ftol; + tol2 = tol + tol; + } + else { + if( cur.dx < 0 ) a = cur; + else b = cur; + if( cur.f <= w.f || w.dx == 0 ) v = w, w = cur; + else if( cur.f <= v.f || v.dx == 0 || v.dx == w.dx ) v = cur; + } + + if( distmin + b.dx <= xtol ) break; + if( min.f < fini && + a.f - min.f <= fabs(a.dx)*maxgrad && + (fabs(distmin - range) > tol || maxstep < b.dx) ) break; + + mid = .5*(a.dx + b.dx); + if( fabs(mid) <= tol2 - .5*(b.dx - a.dx) ) break; + + r = q = s = 0; + if( fabs(end) > tol ) { + if( first ) { + creal s1 = w.dx*grad; + creal s2 = w.f - min.f; + s = (s1 - ((distmin == 0) ? 0 : 2*s2))*w.dx; + q = 2*(s2 - s1); + } + else { + creal s1 = w.dx*(v.f - min.f); + creal s2 = v.dx*(w.f - min.f); + s = s1*w.dx - s2*v.dx; + q = 2*(s2 - s1); + } + if( q > 0 ) s = -s; + q = fabs(q); + r = end; + if( step != b1 || b.dx <= maxstep ) end = step; + } + + if( distmin == a.dx ) step = mid; + else if( b.dx > maxstep ) step = (step < b.dx) ? -4*a.dx : maxstep; + else { + real num = a.dx, den = b.dx; + if( fabs(b.dx) <= tol || (w.dx > 0 && fabs(a.dx) > tol) ) + num = b.dx, den = a.dx; + num /= -den; + step = (num < 1) ? .5*den*sqrt(num) : 5/11.*den*(.1 + 1/num); + } + + if( step > 0 ) a1 = a.dx, b1 = step; + else a1 = step, b1 = b.dx; + if( fabs(s) < fabs(.5*q*r) && s > q*a1 && s < q*b1 ) { + step = s/q; + if( step - a.dx < tol2 || b.dx - step < tol2 ) + step = (mid > 0) ? tol : -tol; + } + else end = (mid > 0) ? b.dx : a.dx; + } + + first = true; + if( fabs(distmin - range) < tol ) { + distmin = range; + if( maxstep > b.dx ) first = false; + } + + for( cur.dx = distmin, cur.f = min.f, shift = -1; ; + cur.dx = Max(ldexp(distmin, shift), ftol), shift <<= 1 ) { + for( i = 0; i < nfree; ++i ) { + ccount dim = ifree[i]; + x[dim] = xini[dim] + cur.dx*p[i]; + } + if( !first ) cur.f = Sample(t, x); + + if( cur.dx + b.dx <= xtol ) { + cur.dx = 0; + break; + } + if( fini - cur.f > cur.dx*mingrad ) break; + if( cur.dx <= ftol ) { + cur.dx = 0; + break; + } + first = false; + } + } + + return cur; +} + +/*********************************************************************/ + +static real LocalSearch(This *t, ccount nfree, ccount *ifree, + cBounds *b, creal *x, creal fx, real *z) +{ + real delta, smax, sopp, spmax, snmax; + real y[NDIM], fy, fz, ftest; + real p[NDIM]; + int sign; + count i; + + /* Choose a direction p along which to move away from the + present x. We choose the direction which leads farthest + away from all borders. */ + + smax = INFTY; + for( i = 0; i < nfree; ++i ) { + ccount dim = ifree[i]; + creal sp = b[dim].upper - x[dim]; + creal sn = x[dim] - b[dim].lower; + if( sp < sn ) { + smax = Min(smax, sn); + p[i] = -1; + } + else { + smax = Min(smax, sp); + p[i] = 1; + } + } + smax *= .9; + + /* Move along p until the integrand changes appreciably + or we come close to a border. */ + + VecCopy(y, x); + ftest = SUFTOL*(1 + fabs(fx)); + delta = RTDELTA/5; + do { + delta = Min(5*delta, smax); + for( i = 0; i < nfree; ++i ) { + ccount dim = ifree[i]; + y[dim] = x[dim] + delta*p[i]; + } + fy = Sample(t, y); + if( fabs(fy - fx) > ftest ) break; + } while( delta != smax ); + + /* Construct a second direction p' orthogonal to p, i.e. p.p' = 0. + We let pairs of coordinates cancel in the dot product, + i.e. we choose p'[0] = p[0], p'[1] = -p[1], etc. + (It should really be 1/p and -1/p, but p consists of 1's and -1's.) + For odd nfree, we let the last three components cancel by + choosing p'[nfree - 3] = p[nfree - 3], + p'[nfree - 2] = -1/2 p[nfree - 2], and + p'[nfree - 1] = -1/2 p[nfree - 1]. */ + + sign = (nfree <= 1 && fy > fx) ? 1 : -1; + spmax = snmax = INFTY; + for( i = 0; i < nfree; ++i ) { + ccount dim = ifree[i]; + real sp, sn; + p[i] *= (nfree & 1 && nfree - i <= 2) ? -.5*sign : (sign = -sign); + sp = (b[dim].upper - y[dim])/p[i]; + sn = (y[dim] - b[dim].lower)/p[i]; + if( p[i] > 0 ) { + spmax = Min(spmax, sp); + snmax = Min(snmax, sn); + } + else { + spmax = Min(spmax, -sn); + snmax = Min(snmax, -sp); + } + } + smax = .9*spmax; + sopp = .9*snmax; + + if( nfree > 1 && smax < snmax ) { + real tmp = smax; + smax = sopp; + sopp = tmp; + for( i = 0; i < nfree; ++i ) + p[i] = -p[i]; + } + + /* Move along p' until the integrand changes appreciably + or we come close to a border. */ + + VecCopy(z, y); + ftest = SUFTOL*(1 + fabs(fy)); + delta = RTDELTA/5; + do { + delta = Min(5*delta, smax); + for( i = 0; i < nfree; ++i ) { + ccount dim = ifree[i]; + z[dim] = y[dim] + delta*p[i]; + } + fz = Sample(t, z); + if( fabs(fz - fy) > ftest ) break; + } while( delta != smax ); + + if( fy != fz ) { + real pleneps, grad, range, step; + Point low; + + if( fy > fz ) { + grad = (fz - fy)/delta; + range = smax/.9; + step = Min(delta + delta, smax); + } + else { + grad = (fy - fz)/delta; + range = sopp/.9 + delta; + step = Min(delta + delta, sopp); + VecCopy(y, z); + fy = fz; + for( i = 0; i < nfree; ++i ) + p[i] = -p[i]; + } + + pleneps = Length(nfree, p) + RTEPS; + low = LineSearch(t, nfree, ifree, p, y, fy, z, step, range, grad, + RTEPS/pleneps, 0., RTEPS); + fz = low.f; + } + + if( fz != fx ) { + real pleneps, grad, range, step; + Point low; + + spmax = snmax = INFTY; + for( i = 0; i < nfree; ++i ) { + ccount dim = ifree[i]; + p[i] = z[dim] - x[dim]; + if( p[i] != 0 ) { + creal sp = (b[dim].upper - x[dim])/p[i]; + creal sn = (x[dim] - b[dim].lower)/p[i]; + if( p[i] > 0 ) { + spmax = Min(spmax, sp); + snmax = Min(snmax, sn); + } + else { + spmax = Min(spmax, -sn); + snmax = Min(snmax, -sp); + } + } + } + + grad = fz - fx; + range = spmax; + step = Min(.9*spmax, 2.); + pleneps = Length(nfree, p) + RTEPS; + if( fz > fx ) { + delta = Min(.9*snmax, RTDELTA/pleneps); + for( i = 0; i < nfree; ++i ) { + ccount dim = ifree[i]; + z[dim] = x[dim] - delta*p[i]; + } + fz = Sample(t, z); + if( fz < fx ) { + grad = (fz - fx)/delta; + range = snmax; + step = Min(.9*snmax, delta + delta); + for( i = 0; i < nfree; ++i ) + p[i] = -p[i]; + } + else if( delta < 1 ) grad = (fx - fz)/delta; + } + + low = LineSearch(t, nfree, ifree, p, x, fx, z, step, range, grad, + RTEPS/pleneps, 0., RTEPS); + fz = low.f; + } + + return fz; +} + +/*********************************************************************/ + +static real FindMinimum(This *t, cBounds *b, real *xmin, real fmin) +{ + real hessian[NDIM*NDIM]; + real gfree[NDIM], p[NDIM]; + real tmp[NDIM], ftmp, fini = fmin; + ccount maxeval = t->neval + 50*t->ndim; + count nfree, nfix; + count ifree[NDIM], ifix[NDIM]; + count dim, local; + + Zap(hessian); + for( dim = 0; dim < t->ndim; ++dim ) + Hessian(dim, dim) = 1; + + /* Step 1: - classify the variables as "fixed" (sufficiently close + to a border) and "free", + - if the integrand is flat in the direction of the gradient + w.r.t. the free dimensions, perform a local search. */ + + for( local = 0; local < 2; ++local ) { + bool resample = false; + nfree = nfix = 0; + for( dim = 0; dim < t->ndim; ++dim ) { + if( xmin[dim] < b[dim].lower + (1 + fabs(b[dim].lower))*QEPS ) { + xmin[dim] = b[dim].lower; + ifix[nfix++] = dim; + resample = true; + } + else if( xmin[dim] > b[dim].upper - (1 + fabs(b[dim].upper))*QEPS ) { + xmin[dim] = b[dim].upper; + ifix[nfix++] = Tag(dim); + resample = true; + } + else ifree[nfree++] = dim; + } + + if( resample ) fini = fmin = Sample(t, xmin); + + if( nfree == 0 ) goto releasebounds; + + Gradient(t, nfree, ifree, b, xmin, fmin, gfree); + if( local || Length(nfree, gfree) > GTOL ) break; + + ftmp = LocalSearch(t, nfree, ifree, b, xmin, fmin, tmp); + if( ftmp > fmin - (1 + fabs(fmin))*RTEPS ) + goto releasebounds; + fmin = ftmp; + VecCopy(xmin, tmp); + } + + while( t->neval <= maxeval ) { + + /* Step 2a: perform a quasi-Newton iteration on the free + variables only. */ + + if( nfree > 0 ) { + real plen, pleneps; + real minstep; + count i, mini = 0, minfix = 0; + Point low; + + LinearSolve(t, nfree, hessian, gfree, p); + plen = Length(nfree, p); + pleneps = plen + RTEPS; + + minstep = INFTY; + for( i = 0; i < nfree; ++i ) { + count dim = Untag(ifree[i]); + if( fabs(p[i]) > EPS ) { + real step; + count fix; + if( p[i] < 0 ) { + step = (b[dim].lower - xmin[dim])/p[i]; + fix = dim; + } + else { + step = (b[dim].upper - xmin[dim])/p[i]; + fix = Tag(dim); + } + if( step < minstep ) { + minstep = step; + mini = i; + minfix = fix; + } + } + } + + if( minstep*pleneps <= DELTA ) { +fixbound: + ifix[nfix++] = minfix; + + if( mini < --nfree ) { + creal diag = Hessian(mini, mini); + + Clear(tmp, mini); + for( i = mini; i < nfree; ++i ) + tmp[i] = Hessian(i + 1, mini); + + for( i = mini; i < nfree; ++i ) { + Copy(&Hessian(i, 0), &Hessian(i + 1, 0), i); + Hessian(i, i) = Hessian(i + 1, i + 1); + } + RenormalizeCholesky(t, nfree, hessian, tmp, diag); + + Copy(&ifree[mini], &ifree[mini + 1], nfree - mini); + Copy(&gfree[mini], &gfree[mini + 1], nfree - mini); + } + continue; + } + + low = LineSearch(t, nfree, ifree, p, xmin, fmin, tmp, + Min(minstep, 1.), Min(minstep, 100.), Dot(nfree, gfree, p), + RTEPS/pleneps, DELTA/pleneps, .2); + + if( low.dx > 0 ) { + real fdiff; + + fmin = low.f; + VecCopy(xmin, tmp); + + Gradient(t, nfree, ifree, b, xmin, fmin, tmp); + BFGS(t, nfree, hessian, tmp, gfree, p, low.dx); + VecCopy(gfree, tmp); + + if( fabs(low.dx - minstep) < QEPS*minstep ) goto fixbound; + + fdiff = fini - fmin; + fini = fmin; + if( fdiff > (1 + fabs(fmin))*FTOL || + low.dx*plen > (1 + Length(t->ndim, xmin))*FTOL ) continue; + } + } + + /* Step 2b: check whether freeing any fixed variable will lead + to a reduction in f. */ + +releasebounds: + if( nfix > 0 ) { + real mingrad = INFTY; + count i, mini = 0; + bool repeat = false; + + Gradient(t, nfix, ifix, b, xmin, fmin, tmp); + + for( i = 0; i < nfix; ++i ) { + creal grad = Sign(ifix[i])*tmp[i]; + if( grad < -RTEPS ) { + repeat = true; + if( grad < mingrad ) { + mingrad = grad; + mini = i; + } + } + } + + if( repeat ) { + gfree[nfree] = tmp[mini]; + ifree[nfree] = Untag(ifix[mini]); + Clear(&Hessian(nfree, 0), nfree); + Hessian(nfree, nfree) = 1; + ++nfree; + + --nfix; + Copy(&ifix[mini], &ifix[mini + 1], nfix - mini); + continue; + } + } + + break; + } + + return fmin; +} + diff --git a/src/divonne/Integrate.c b/src/divonne/Integrate.c new file mode 100644 index 0000000..4059a55 --- /dev/null +++ b/src/divonne/Integrate.c @@ -0,0 +1,452 @@ +/* + Integrate.c + partition the integration region until each region + has approximately equal spread = 1/2 vol (max - min), + then do a main integration over all regions + this file is part of Divonne + last modified 15 Nov 11 th +*/ + + +#define INIDEPTH 3 +#define DEPTH 5 +#define POSTDEPTH 15 + +/*********************************************************************/ + +static int Integrate(This *t, real *integral, real *error, real *prob) +{ + TYPEDEFREGION; + + Totals totals[NCOMP]; + real nneed; + count dim, comp, iter, pass = 0, err, iregion; + number nwant, nmin = INT_MAX, neff; + int fail; + + if( VERBOSE > 1 ) { + char s[512]; + sprintf(s, "Divonne input parameters:\n" + " ndim " COUNT "\n ncomp " COUNT "\n" + " epsrel " REAL "\n epsabs " REAL "\n" + " flags %d\n seed %d\n" + " mineval " NUMBER "\n maxeval " NUMBER "\n" + " key1 %d\n key2 %d\n key3 %d\n maxpass " COUNT "\n" + " border " REAL "\n maxchisq " REAL "\n mindeviation " REAL "\n" + " ngiven " NUMBER "\n nextra " NUMBER, + t->ndim, t->ncomp, + t->epsrel, t->epsabs, + t->flags, t->seed, + t->mineval, t->maxeval, + t->key1, t->key2, t->key3, t->maxpass, + t->border.lower, t->maxchisq, t->mindeviation, + t->ngiven, t->nextra); + Print(s); + } + + if( BadComponent(t) ) return -2; + if( BadDimension(t, t->key1) || + BadDimension(t, t->key2) || + ((t->key3 & -2) && BadDimension(t, t->key3)) ) return -1; + + t->neval_opt = t->neval_cut = 0; + + AllocRegions(t); + for( dim = 0; dim < t->ndim; ++dim ) { + Bounds *b = &RegionPtr(0)->bounds[dim]; + b->lower = 0; + b->upper = 1; + } + t->nregions = 1; + + RuleIni(&t->rule7); + RuleIni(&t->rule9); + RuleIni(&t->rule11); + RuleIni(&t->rule13); + SamplesIni(&t->samples[0]); + SamplesIni(&t->samples[1]); + SamplesIni(&t->samples[2]); + + if( (fail = setjmp(t->abort)) ) goto abort; + + t->epsabs = Max(t->epsabs, NOTZERO); + + /* Step 1: partition the integration region */ + + if( VERBOSE ) Print("Partitioning phase:"); + + if( IsSobol(t->key1) || IsSobol(t->key2) || IsSobol(t->key3) ) + IniRandom(t); + + SamplesLookup(t, &t->samples[0], t->key1, + (number)47, (number)INT_MAX, (number)0); + SamplesAlloc(t, &t->samples[0]); + + t->totals = totals; + Zap(totals); + t->phase = 1; + + Iterate(t, 0, INIDEPTH, 0, NULL); + + for( iter = 1; ; ++iter ) { + Totals *maxtot; + count valid; + + for( comp = 0; comp < t->ncomp; ++comp ) { + Totals *tot = &totals[comp]; + tot->avg = tot->spreadsq = 0; + tot->spread = tot->secondspread = -INFTY; + } + + for( iregion = 0; iregion < t->nregions; ++iregion ) { + Region *region = RegionPtr(iregion); + for( comp = 0; comp < t->ncomp; ++comp ) { + cResult *r = ®ion->result[comp]; + Totals *tot = &totals[comp]; + tot->avg += r->avg; + tot->spreadsq += Sq(r->spread); + if( r->spread > tot->spread ) { + tot->secondspread = tot->spread; + tot->spread = r->spread; + tot->iregion = iregion; + } + else if( r->spread > tot->secondspread ) + tot->secondspread = r->spread; + } + } + + maxtot = totals; + valid = 0; + for( comp = 0; comp < t->ncomp; ++comp ) { + Totals *tot = &totals[comp]; + integral[comp] = tot->avg; + valid += tot->avg == tot->avg; + if( tot->spreadsq > maxtot->spreadsq ) maxtot = tot; + tot->spread = sqrt(tot->spreadsq); + error[comp] = tot->spread/t->samples[0].neff; + } + + if( VERBOSE ) { + char s[128 + 64*NCOMP], *p = s; + + p += sprintf(p, "\n" + "Iteration " COUNT " (pass " COUNT "): " COUNT " regions\n" + NUMBER7 " integrand evaluations so far,\n" + NUMBER7 " in optimizing regions,\n" + NUMBER7 " in finding cuts", + iter, pass, t->nregions, t->neval, t->neval_opt, t->neval_cut); + + for( comp = 0; comp < t->ncomp; ++comp ) + p += sprintf(p, "\n[" COUNT "] " + REAL " +- " REAL, + comp + 1, integral[comp], error[comp]); + + Print(s); + } + + if( valid == 0 ) goto abort; /* all NaNs */ + + if( t->neval > t->maxeval ) break; + + nneed = maxtot->spread/MaxErr(maxtot->avg); + if( nneed < MAXPRIME ) { + cnumber n = t->neval + t->nregions*(number)ceil(nneed); + if( n < nmin ) { + nmin = n; + pass = 0; + } + else if( ++pass > t->maxpass && n >= t->mineval ) break; + } + + Iterate(t, maxtot->iregion, DEPTH, -1, NULL); + } + + /* Step 2: do a "full" integration on each region */ + +/* nneed = t->samples[0].neff + 1; */ + nneed = 2*t->samples[0].neff; + for( comp = 0; comp < t->ncomp; ++comp ) { + Totals *tot = &totals[comp]; + creal maxerr = MaxErr(tot->avg); + tot->nneed = tot->spread/maxerr; + nneed = Max(nneed, tot->nneed); + tot->maxerrsq = Sq(maxerr); + tot->mindevsq = tot->maxerrsq*Sq(t->mindeviation); + } + nwant = (number)Min(ceil(nneed), MARKMASK/40.); + + err = SamplesLookup(t, &t->samples[1], t->key2, nwant, + (t->maxeval - t->neval)/t->nregions + 1, t->samples[0].n + 1); + + /* the number of points needed to reach the desired accuracy */ + fail = Unmark(err)*t->nregions; + + if( Marked(err) ) { + if( VERBOSE ) Print("\nNot enough samples left for main integration."); + for( comp = 0; comp < t->ncomp; ++comp ) + prob[comp] = -999; + neff = t->samples[0].neff; + } + else { + bool can_adjust = (t->key3 == 1 && t->samples[1].sampler != SampleRule && + (t->key2 < 0 || t->samples[1].neff < MAXPRIME)); + count df, nlimit; + + SamplesAlloc(t, &t->samples[1]); + + if( VERBOSE ) { + char s[128]; + sprintf(s, "\nMain integration on " COUNT + " regions with " NUMBER " samples per region.", + t->nregions, t->samples[1].neff); + Print(s); + } + + ResClear(integral); + ResClear(error); + ResClear(prob); + + nlimit = t->maxeval - t->nregions*t->samples[1].n; + df = 0; + +#define CopyPhaseResults(f) \ + for( comp = 0; comp < t->ncomp; ++comp ) { \ + PhaseResult *p = &totals[comp].phase[f]; \ + cResult *r = ®ion->result[comp]; \ + p->avg = r->avg; \ + p->err = r->err; \ + } + +#define Var2(f, res) Sq((res)->err ? (res)->err : r->spread/t->samples[f].neff) +#define Var(f) Var2(f, &tot->phase[f]) + + for( iregion = 0; iregion < t->nregions; ++iregion ) { + Region *region; + char s[64*NDIM + 256*NCOMP], *p = s; + int todo; + +refine: + region = RegionPtr(iregion); + CopyPhaseResults(0); + t->phase = 2; + region->isamples = 1; + t->samples[1].sampler(t, iregion); + CopyPhaseResults(1); + + if( can_adjust ) + for( comp = 0; comp < t->ncomp; ++comp ) + totals[comp].spreadsq -= Sq(region->result[comp].spread); + + nlimit += t->samples[1].n; + todo = 0; + + for( comp = 0; comp < t->ncomp; ++comp ) { + cResult *r = ®ion->result[comp]; + Totals *tot = &totals[comp]; + + if( t->neval < nlimit ) { + creal avg2 = tot->phase[1].avg; + creal diffsq = Sq(avg2 - tot->phase[0].avg); + + if( r->err*tot->nneed > r->spread || + diffsq > Max(t->maxchisq*(Var(0) + Var(1)), EPS*Sq(avg2)) ) { + if( t->key3 && diffsq > tot->mindevsq ) { + if( t->key3 == 1 ) { + if( VERBOSE > 2 ) Print("\nSplit"); + t->phase = 1; + Iterate(t, iregion, POSTDEPTH, 1, totals); + + if( can_adjust ) { + cnumber nnew = (tot->spreadsq/Sq(MARKMASK) > tot->maxerrsq) ? + MARKMASK : + (number)ceil(sqrt(tot->spreadsq/tot->maxerrsq)); + if( nnew > nwant + nwant/64 ) { + ccount err = SamplesLookup(t, &t->samples[1], t->key2, nnew, + (t->maxeval - t->neval)/t->nregions + 1, t->samples[1].n); + fail += Unmark(err)*t->nregions; + nwant = nnew; + SamplesFree(&t->samples[1]); + SamplesAlloc(t, &t->samples[1]); + + if( t->key2 > 0 && t->samples[1].neff >= MAXPRIME ) + can_adjust = false; + + if( VERBOSE > 2 ) { + char s[128]; + sprintf(s, "Sampling remaining " COUNT + " regions with " NUMBER " points per region.", + t->nregions, t->samples[1].neff); + Print(s); + } + } + } + goto refine; + } + todo |= 3; + } + todo |= 1; + } + } + } + + if( can_adjust ) { + for( comp = 0; comp < t->ncomp; ++comp ) + totals[comp].maxerrsq -= + Sq(region->result[comp].spread/t->samples[1].neff); + } + + switch( todo ) { + case 1: /* get spread right */ + region->isamples = 1; + Explore(t, iregion); + break; + + case 3: /* sample region again with more points */ + if( SamplesIniQ(&t->samples[2]) ) { + SamplesLookup(t, &t->samples[2], t->key3, + nwant, (number)INT_MAX, (number)0); + SamplesAlloc(t, &t->samples[2]); + } + t->phase = 3; + region->isamples = 2; + t->samples[2].sampler(t, iregion); + Explore(t, iregion); + ++region->depth; /* misused for df here */ + ++df; + } + + if( VERBOSE > 2 ) { + for( dim = 0; dim < t->ndim; ++dim ) { + cBounds *b = ®ion->bounds[dim]; + p += sprintf(p, + (dim == 0) ? "\nRegion (" REALF ") - (" REALF ")" : + "\n (" REALF ") - (" REALF ")", + b->lower, b->upper); + } + } + + for( comp = 0; comp < t->ncomp; ++comp ) { + Result *r = ®ion->result[comp]; + Totals *tot = &totals[comp]; + + creal x1 = tot->phase[0].avg; + creal v1 = Var(0); + creal x2 = tot->phase[1].avg; + creal v2 = Var(1); + creal r2 = v1 ? v2/v1 : + Sq(t->samples[1].neff/(real)t->samples[0].neff); + + real norm = 1 + r2; + real avg = x2 + r2*x1; + real sigsq = v2; + real chisq = Sq(x2 - x1); + real chiden = v1 + v2; + + if( todo == 3 ) { + creal x3 = r->avg; + creal v3 = Var2(2, r); + creal r3 = v2 ? v3/v2 : + Sq(t->samples[2].neff/(real)t->samples[1].neff); + + norm = 1 + r3*norm; + avg = x3 + r3*avg; + sigsq = v3; + chisq = v1*Sq(x3 - x2) + v2*Sq(x3 - x1) + v3*chisq; + chiden = v1*v2 + v3*chiden; + } + + avg = LAST ? r->avg : (sigsq *= norm = 1/norm, avg*norm); + if( chisq > EPS ) chisq /= Max(chiden, NOTZERO); + + if( VERBOSE > 2 ) { +#define Out2(f, res) (res)->avg, r->spread/t->samples[f].neff, (res)->err +#define Out(f) Out2(f, &tot->phase[f]) + p += sprintf(p, "\n[" COUNT "] " + REAL " +- " REAL "(" REAL ")\n " + REAL " +- " REAL "(" REAL ")", comp + 1, Out(0), Out(1)); + if( todo == 3 ) p += sprintf(p, "\n " + REAL " +- " REAL "(" REAL ")", Out2(2, r)); + p += sprintf(p, " \tchisq " REAL, chisq); + } + + integral[comp] += avg; + error[comp] += sigsq; + prob[comp] += chisq; + + r->avg = avg; + r->spread = sqrt(sigsq); + r->chisq = chisq; + } + + if( VERBOSE > 2 ) Print(s); + } + + for( comp = 0; comp < t->ncomp; ++comp ) + error[comp] = sqrt(error[comp]); + + df += t->nregions; + + if( VERBOSE > 2 ) { + char s[16 + 128*NCOMP], *p = s; + + p += sprintf(p, "\nTotals:"); + + for( comp = 0; comp < t->ncomp; ++comp ) + p += sprintf(p, "\n[" COUNT "] " + REAL " +- " REAL " \tchisq " REAL " (" COUNT " df)", + comp + 1, integral[comp], error[comp], prob[comp], df); + + Print(s); + } + + for( comp = 0; comp < t->ncomp; ++comp ) + prob[comp] = ChiSquare(prob[comp], df); + + neff = 1; + } + +#ifdef MLVERSION + if( REGIONS ) { + MLPutFunction(stdlink, "List", 2); + MLPutFunction(stdlink, "List", t->nregions); + for( iregion = 0; iregion < t->nregions; ++iregion ) { + Region *region = RegionPtr(iregion); + cBounds *b = region->bounds; + real lower[NDIM], upper[NDIM]; + + for( dim = 0; dim < t->ndim; ++dim ) { + lower[dim] = b[dim].lower; + upper[dim] = b[dim].upper; + } + + MLPutFunction(stdlink, "Cuba`Divonne`region", 4); + + MLPutRealList(stdlink, lower, t->ndim); + MLPutRealList(stdlink, upper, t->ndim); + + MLPutFunction(stdlink, "List", t->ncomp); + for( comp = 0; comp < t->ncomp; ++comp ) { + cResult *r = ®ion->result[comp]; + real res[] = {r->avg, r->spread/neff, r->chisq}; + MLPutRealList(stdlink, res, Elements(res)); + } + + MLPutInteger(stdlink, region->depth + 1); /* misused for df */ + } + } +#endif + +abort: + SamplesFree(&t->samples[2]); + SamplesFree(&t->samples[1]); + SamplesFree(&t->samples[0]); + RuleFree(&t->rule13); + RuleFree(&t->rule11); + RuleFree(&t->rule9); + RuleFree(&t->rule7); + + free(t->voidregion); + + return fail; +} + diff --git a/src/divonne/Iterate.c b/src/divonne/Iterate.c new file mode 100644 index 0000000..82c0e34 --- /dev/null +++ b/src/divonne/Iterate.c @@ -0,0 +1,138 @@ +/* + Iterate.c + recursion over regions + this file is part of Divonne + last modified 15 Nov 11 th +*/ + + +static void Iterate(This *t, count iregion, cint depth, cint isamples, + Totals *totals) +{ + TYPEDEFREGION; + Region *parent, *region; + typedef struct { + real avg, err, spread, spreadsq; + } Corr; + Corr corr[NCOMP]; + count ireg, mreg = iregion; + count comp, maxsplit; + int last, idest, isrc; + + region = RegionPtr(iregion); + region->depth = depth; + region->next = -iregion - 1; + if( isamples < 0 ) Split(t, iregion); + else { + region->isamples = isamples; + Explore(t, iregion); + } + + ireg = iregion + RegionPtr(iregion)->next; + + do { + region = RegionPtr(ireg); + if( region->depth > 0 ) { + --region->depth; +more: + ireg = ExploreParent(t, ireg); + if( ireg == -1 ) return; + region = RegionPtr(ireg); + } + if( region->depth < 0 ) mreg = IMax(mreg, ireg); + ireg += region->next; + } while( ireg > 0 ); + +#ifndef MLVERSION + if( t->running ) goto more; +#endif + + maxsplit = 1; + for( ireg = mreg; ireg >= iregion; --ireg ) { + parent = RegionPtr(ireg); + maxsplit -= NegQ(parent->depth); + if( parent->depth < 0 ) { + count xreg; + struct { + count from, to; + } todo[maxsplit], *tdmax = todo, *td; + count nsplit = 0; + real norm; + + memset(corr, 0, sizeof corr); + + tdmax->from = ireg + parent->next; + tdmax->to = tdmax->from - parent->depth; + ++tdmax; + for( td = todo; td < tdmax; ++td ) { + for( xreg = td->from; xreg < td->to; ++xreg ) { + Region *region = RegionPtr(xreg); + if( region->depth < 0 ) { + tdmax->from = xreg + region->next; + tdmax->to = tdmax->from - region->depth; + ++tdmax; + } + else { + ++nsplit; + for( comp = 0; comp < t->ncomp; ++comp ) { + cResult *r = ®ion->result[comp]; + Corr *c = &corr[comp]; + c->avg += r->avg; + c->err += r->err; + c->spread += Sq(r->spread); + } + } + } + } + + norm = 1./nsplit--; + for( comp = 0; comp < t->ncomp; ++comp ) { + Result *p = &parent->result[comp]; + Corr *c = &corr[comp]; + creal diff = fabs(p->avg - c->avg)*norm; + c->avg = diff*norm*nsplit; + c->err = (c->err == 0) ? 1 : 1 + diff/c->err; + c->spread = (c->spread == 0) ? 1 : 1 + diff/sqrt(c->spread); + } + + for( td = todo; td < tdmax; ++td ) + for( xreg = td->from; xreg < td->to; ++xreg ) { + Region *region = RegionPtr(xreg); + if( region->depth >= 0 ) { + cnumber neff = t->samples[region->isamples].neff; + for( comp = 0; comp < t->ncomp; ++comp ) { + Result *r = ®ion->result[comp]; + Corr *c = &corr[comp]; + if( r->err > 0 ) r->err = r->err*c->err + c->avg; + r->spread = r->spread*c->spread + c->avg*neff; + c->spreadsq += Sq(r->spread); + } + } + } + } + } + + if( totals ) + for( comp = 0; comp < t->ncomp; ++comp ) + totals[comp].spreadsq += corr[comp].spreadsq; + + for( last = -1, idest = isrc = iregion; iregion <= mreg; ++iregion ) { + Region *region = RegionPtr(iregion); + cint cur = NegQ(region->depth); + switch( cur - last ) { + case -1: + memmove(RegionPtr(idest), RegionPtr(isrc), + (iregion - isrc)*sizeof(Region)); + idest += iregion - isrc; + break; + case 1: + isrc = iregion; + } + last = cur; + } + + memmove(RegionPtr(idest), RegionPtr(iregion), + (t->nregions - iregion)*sizeof(Region)); + t->nregions += idest - iregion; +} + diff --git a/src/divonne/KorobovCoeff.c b/src/divonne/KorobovCoeff.c new file mode 100644 index 0000000..e8ace85 --- /dev/null +++ b/src/divonne/KorobovCoeff.c @@ -0,0 +1,881 @@ +#define KOROBOV_MINDIM 2 +#define KOROBOV_MAXDIM 33 +#define MAXPRIME 9689 + +#define Hash(x) ((19945 - x)*(-47 + x))/121634 + +static int prime[] = { + FIRST,47,53,59,67,71,79,83,89,97,103,109,113,127,131,137,139,149,151, + 157,163,173,179,181,191,193,199,211,223,227,229,233,239,241,251,257,263, + 269,277,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383, + 389,397,401,409,419,421,431,433,439,443,449,457,461,467,479,487,491,499, + 503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617, + 619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739, + 743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859, + 863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991, + 997,1009,1013,1019,1021,1031,1033,1039,1049,1051,1061,1063,1069,1087, + 1091,1093,1097,1103,1109,1117,1123,1129,1151,1153,1163,1171,1181,1187, + 1193,1201,1213,1217,1223,1229,1231,1237,1249,1259,1277,1279,1283,1289, + 1291,1297,1301,1303,1307,1319,1321,1327,1361,1367,1373,1381,1399,1409, + 1423,1427,1429,1433,1439,1447,1451,1453,1459,1471,1481,1483,1487,1489, + 1493,1499,1511,1523,1531,1543,1549,1553,1559,1567,1571,1579,1583,1597, + 1601,1607,1609,1613,1619,1621,1627,1637,1657,1663,1667,1669,1693,1697, + 1699,1709,1721,1723,1733,1741,1747,1753,1759,1777,1783,1787,1789,1801, + 1811,1823,1831,1847,1861,1867,1871,1873,1877,1879,1889,1901,1907,1913, + 1931,1933,1949,1951,1973,1979,1987,1993,1997,1999,2003,2011,2017,2027, + 2029,2039,2053,2063,2069,2081,2083,2087,2089,2099,2111,2113,2129,2131, + 2137,2141,2143,2153,2161,2179,2203,2207,2213,2221,2237,2239,2243,2251, + 2267,2269,2273,2281,2287,2293,2297,2309,2311,2333,2339,2341,2347,2351, + 2357,2371,2377,2381,2383,2389,2393,2399,2411,2417,2423,2437,2441,2447, + 2459,2467,2473,2477,2503,2521,2531,2539,2543,2549,2551,2557,2579,2591, + 2593,2609,2617,2621,2633,2647,2657,2659,2663,2671,2677,2683,2687,2689, + 2693,2699,2707,2711,2713,2719,2729,2731,2741,2749,2753,2767,2777,2789, + 2791,2797,2801,2803,2819,2833,2837,2843,2851,2857,2861,2879,2887,2897, + 2903,2909,2917,2927,2939,2953,2957,2963,2969,2971,2999,3001,3011,3019, + 3023,3037,3041,3049,3061,3067,3079,3083,3089,3109,3119,3121,3137,3163, + 3167,3169,3181,3187,3191,3203,3209,3217,3221,3229,3251,3253,3257,3259, + 3271,3299,3301,3307,3313,3319,3323,3329,3331,3343,3347,3359,3361,3371, + 3373,3389,3391,3407,3413,3433,3449,3457,3461,3463,3467,3469,3491,3499, + 3511,3517,3527,3529,3533,3539,3547,3557,3571,3581,3583,3593,3607,3613, + 3623,3631,3643,3659,3671,3673,3677,3691,3701,3709,3719,3733,3739,3761, + 3767,3769,3779,3793,3797,3803,3821,3833,3847,3851,3853,3863,3877,3889, + 3907,3911,3917,3929,3943,3947,3967,3989,4001,4003,4007,4013,4019,4027, + 4049,4051,4057,4073,4079,4091,4099,4111,4127,4133,4139,4153,4159,4177, + 4201,4211,4217,4219,4229,4231,4243,4259,4271,4283,4289,4297,4327,4337, + 4339,4349,4357,4363,4373,4391,4397,4409,4421,4423,4441,4451,4463,4481, + 4483,4493,4507,4517,4523,4547,4549,4561,4567,4583,4597,4603,4621,4637, + 4639,4651,4663,4673,4691,4703,4721,4723,4733,4751,4759,4783,4787,4789, + 4801,4813,4831,4861,4871,4877,4889,4903,4909,4919,4931,4933,4943,4957, + 4969,4987,4993,5003,5021,5023,5039,5051,5059,5077,5087,5101,5119,5147, + 5153,5167,5171,5179,5189,5209,5227,5231,5237,5261,5273,5281,5297,5309, + 5323,5333,5347,5351,5381,5387,5399,5413,5431,5437,5449,5471,5479,5501, + 5507,5519,5531,5557,5563,5573,5591,5623,5639,5641,5647,5657,5669,5683, + 5701,5711,5737,5743,5749,5779,5783,5801,5813,5827,5843,5857,5869,5881, + 5903,5923,5927,5953,5981,5987,6007,6011,6029,6037,6053,6067,6089,6101, + 6113,6131,6151,6163,6173,6197,6211,6229,6247,6257,6277,6287,6311,6323, + 6343,6359,6373,6389,6421,6427,6449,6469,6481,6491,6521,6529,6547,6563, + 6581,6599,6619,6637,6653,6673,6691,6709,6733,6737,6763,6781,6803,6823, + 6841,6863,6883,6899,6917,6947,6961,6983,7001,7019,7043,7057,7079,7103, + 7127,7151,7159,7187,7211,7229,7253,7283,7297,7321,7349,7369,7393,7417, + 7433,7459,7487,7507,7537,7561,7583,7607,7639,7669,7687,7717,7741,7759, + 7793,7823,7853,7883,7907,7937,7963,7993,8039,8059,8093,8123,8161,8191, + 8221,8263,8297,8329,8369,8419,8447,8501,8527,8563,8609,8663,8699,8747, + 8803,8849,8893,8963,9029,9091,9157,9239,9319,9413,9533,MarkLast(9689) +}; + +static short coeff[][32] = { + {13,11,10,3,9,2,2,2,2,9,2,2,7,2,2,2,2,2,2,6,2,2,2,13,11,10,3,9,2,2,2,2}, + {23,17,12,11,14,14,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,12,12,12,14,14,14}, + {18,14,5,14,2,2,19,19,25,25,18,18,18,2,2,2,2,2,2,2,2,2,2,2,25,6,2,2,2,18,14,5}, + {18,13,23,5,2,12,6,12,12,12,10,10,16,2,16,16,2,2,2,2,2,2,2,10,2,2,2,2,10,2,2,2}, + {21,22,7,21,2,20,20,2,2,2,2,22,2,2,2,2,2,2,2,6,6,21,2,2,2,2,2,2,2,2,6,6}, + {29,19,27,32,6,8,2,2,2,2,2,8,8,2,2,2,2,9,9,9,9,2,2,2,2,2,2,2,9,9,2,2}, + {30,19,24,16,22,8,2,2,22,5,9,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {34,28,13,28,27,27,2,4,2,2,2,16,16,4,20,20,36,20,36,5,5,5,36,36,5,5,5,7,5,7,7,2}, + {35,19,33,8,21,30,8,2,4,2,4,4,2,2,2,2,2,2,2,2,2,17,2,2,11,25,11,17,17,17,17,17}, + {37,21,35,29,27,19,19,2,2,2,5,15,2,2,15,15,19,19,19,19,19,2,2,2,2,2,19,2,2,2,2,2}, + {45,44,13,25,17,47,30,2,30,2,2,2,2,2,2,2,2,2,19,19,19,17,17,2,2,2,2,2,2,2,2,2}, + {35,22,37,9,35,12,35,8,2,2,50,50,2,2,32,32,32,31,13,8,8,8,2,22,50,9,9,9,22,22,22,10}, + {29,24,43,36,49,2,2,8,4,25,49,25,2,2,8,10,10,10,5,5,5,40,10,33,40,40,2,27,10,25,25,25}, + {50,18,32,39,21,2,2,2,4,4,36,36,14,14,14,14,2,2,2,17,17,17,16,16,2,14,14,14,14,2,2,2}, + {31,28,45,20,18,43,43,13,28,2,2,2,31,31,31,31,31,2,2,2,43,43,2,2,2,2,2,2,2,2,30,2}, + {39,15,41,7,24,2,2,30,40,2,2,25,25,25,25,2,2,2,2,2,2,6,6,2,25,2,5,2,2,25,2,2}, + {44,20,29,39,7,21,21,21,2,2,45,2,2,2,49,49,49,49,49,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {56,20,22,13,18,35,35,6,2,4,2,4,2,2,2,23,16,16,4,23,2,34,52,2,34,2,4,2,2,2,23,16}, + {46,32,17,18,29,27,31,31,31,2,2,4,15,2,2,2,2,2,2,2,2,2,2,2,2,2,23,32,32,32,15,15}, + {62,42,43,17,23,13,13,2,2,13,2,2,2,2,2,2,2,10,2,2,2,2,9,10,2,2,2,19,9,9,9,9}, + {64,34,16,28,16,51,47,2,2,2,6,18,39,39,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,12,12,2}, + {74,26,44,25,50,24,54,39,58,42,2,42,42,2,2,2,2,2,2,2,2,33,33,2,2,39,11,2,2,58,39,58}, + {70,22,50,22,16,9,25,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {74,21,17,25,35,33,10,2,10,20,20,57,57,57,2,2,57,2,2,2,2,2,2,2,13,2,2,2,2,2,2,2}, + {81,18,10,11,47,38,71,37,2,37,2,2,2,2,2,26,26,26,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {55,30,85,42,16,36,45,67,2,2,68,2,2,2,2,2,2,2,68,10,2,2,2,2,2,2,2,2,2,2,2,2}, + {64,17,24,26,49,12,10,39,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,59,2,2}, + {68,57,23,38,61,38,13,13,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,68,15,2,44,44,44,2,2,2}, + {94,28,58,29,13,5,15,8,66,2,2,2,39,39,15,66,2,2,6,6,2,2,66,66,66,66,2,2,2,2,2,66}, + {94,85,9,41,41,37,29,29,17,2,2,2,7,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,8,8}, + {89,32,75,77,77,13,2,30,30,2,2,2,2,2,2,2,2,2,2,67,67,2,2,2,2,2,2,2,2,8,19,32}, + {70,45,58,63,67,10,72,72,70,6,2,36,2,70,70,6,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {101,33,76,13,45,63,2,2,6,19,2,2,32,32,32,32,32,65,2,63,63,11,11,11,19,19,19,19,9,63,63,63}, + {70,89,44,37,19,45,2,2,2,8,10,8,54,54,80,80,80,80,80,2,116,2,116,2,2,80,40,51,100,100,8,2}, + {71,54,83,51,42,98,2,2,8,8,14,30,93,22,15,15,30,30,30,44,44,44,2,2,22,22,22,117,44,11,11,11}, + {109,37,51,113,17,10,2,2,17,17,55,2,55,55,55,55,55,55,2,2,2,57,48,48,55,55,2,2,55,2,2,55}, + {75,38,68,89,11,52,2,2,81,39,2,38,2,2,2,2,2,2,2,2,2,2,2,19,2,2,2,2,2,2,2,2}, + {81,84,35,34,20,93,2,12,12,12,2,96,2,96,96,2,96,2,2,2,2,2,2,2,2,2,2,2,2,56,56,56}, + {104,32,56,46,77,11,35,35,24,56,19,2,2,2,78,2,2,75,2,2,2,2,78,2,2,2,2,2,2,2,2,2}, + {81,103,25,35,28,15,20,20,20,2,2,2,2,20,20,20,107,107,2,2,2,2,2,2,2,2,2,2,2,2,13,13}, + {119,75,42,29,74,23,54,36,39,2,2,4,4,19,19,2,2,2,2,2,2,2,2,54,2,2,2,2,2,2,2,54}, + {115,73,22,102,75,138,16,73,50,16,2,50,2,2,2,133,2,2,2,2,2,2,2,2,2,2,2,2,2,33,33,33}, + {119,48,66,51,14,22,20,20,2,2,2,2,2,60,2,2,2,2,2,2,2,2,60,2,2,2,2,2,2,60,2,65}, + {121,94,80,29,51,69,42,36,14,14,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,17,2,2}, + {129,123,41,79,43,34,24,11,2,2,4,2,2,2,2,75,16,16,16,75,75,75,16,16,16,25,2,99,2,2,75,16}, + {128,33,35,68,22,8,62,94,2,2,2,62,62,2,98,2,2,4,98,2,2,32,81,32,32,32,98,98,98,98,98,98}, + {101,109,154,15,57,6,27,36,2,2,37,37,2,2,2,2,2,2,2,107,2,2,2,107,107,2,2,2,2,2,2,2}, + {106,40,24,38,61,118,106,106,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {149,111,58,79,127,13,41,33,27,16,30,2,61,2,72,2,2,2,2,2,2,2,2,2,2,2,2,75,75,2,2,2}, + {105,92,43,156,25,53,57,115,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {99,40,62,67,66,29,99,99,99,78,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,79}, + {109,42,96,95,66,41,103,84,13,103,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {111,72,16,89,25,86,117,29,14,14,2,2,2,2,2,60,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {106,72,49,94,140,44,97,157,75,2,2,4,123,123,2,2,123,123,123,123,2,2,2,2,2,2,2,2,2,2,2,2}, + {115,67,74,32,43,50,21,36,135,36,85,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {151,71,157,42,41,37,80,27,18,2,2,2,2,2,2,2,2,2,2,2,2,2,115,128,128,128,128,128,32,2,128,80}, + {119,91,38,30,92,44,32,76,22,2,34,2,2,2,2,2,2,2,2,2,2,2,2,2,2,129,2,2,129,2,2,2}, + {121,126,31,52,120,37,57,10,171,2,2,2,2,35,35,35,2,2,97,97,97,97,97,97,97,35,35,35,97,97,97,2}, + {155,86,49,104,87,94,64,45,61,91,91,91,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {164,121,44,166,47,33,7,15,13,2,2,122,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {128,120,133,17,71,52,25,107,42,21,21,2,2,2,2,4,4,96,2,9,9,2,9,94,94,94,94,94,94,94,94,96}, + {179,82,157,76,61,35,13,90,197,2,69,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,39,39}, + {136,136,148,63,66,10,169,95,95,163,30,28,28,2,41,130,2,2,2,21,2,2,2,2,2,2,2,2,2,2,2,36}, + {131,40,112,63,55,30,53,79,79,79,2,79,2,2,2,2,2,79,2,2,2,2,14,36,2,21,21,21,21,2,2,91}, + {165,81,92,48,9,110,12,40,40,34,2,2,2,107,107,107,2,107,2,2,2,2,2,2,2,2,2,2,2,15,41,41}, + {169,66,170,97,35,56,55,86,32,32,2,2,2,2,14,2,40,2,37,2,2,37,40,40,40,2,2,2,37,37,37,37}, + {135,63,126,156,70,18,49,143,6,117,2,109,109,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {193,59,51,68,68,15,170,170,170,143,143,12,2,2,2,63,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {145,101,56,65,23,76,110,2,4,4,4,146,146,146,2,146,2,2,2,2,2,2,2,2,2,2,2,2,2,2,146,146}, + {144,129,26,98,36,46,47,52,52,52,82,2,2,2,2,2,17,2,2,2,2,2,2,2,2,2,2,2,2,91,2,2}, + {145,78,166,171,56,20,63,2,2,33,33,33,33,2,78,47,47,47,47,47,2,2,2,2,2,78,78,78,2,2,2,2}, + {191,69,176,54,47,75,167,2,2,2,188,188,188,30,30,2,67,67,117,2,117,117,117,2,2,36,2,2,2,2,2,2}, + {186,96,29,122,47,96,170,157,157,157,157,108,159,2,195,195,26,26,26,26,26,2,2,2,2,132,132,132,2,2,2,2}, + {151,118,226,91,54,49,33,2,2,2,2,4,4,4,143,143,2,2,143,25,25,25,2,143,143,143,143,143,143,143,143,143}, + {144,91,237,82,81,75,138,163,163,163,117,117,44,2,44,136,136,136,136,2,2,2,2,2,122,122,122,122,2,2,2,136}, + {189,78,178,64,118,27,189,2,2,67,67,110,110,110,110,2,28,28,2,2,2,2,2,2,2,102,2,2,2,2,2,2}, + {165,202,83,76,125,65,42,2,44,44,23,2,23,23,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {209,204,92,75,85,146,104,2,7,18,8,2,2,2,204,95,95,95,2,2,2,95,95,95,95,95,95,95,2,2,2,95}, + {169,68,89,16,193,82,33,262,262,175,148,148,148,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {171,162,78,43,61,17,112,10,171,182,118,33,2,2,2,2,118,2,2,2,2,2,2,151,2,2,2,2,2,2,2,2}, + {211,121,119,55,90,211,96,89,225,25,178,36,36,36,2,2,108,2,2,2,2,2,2,2,2,2,2,2,2,184,2,2}, + {154,101,83,17,16,210,41,79,70,158,2,27,27,2,2,2,2,2,2,2,2,2,2,2,2,153,2,2,2,2,2,2}, + {169,179,130,79,148,180,136,17,47,119,2,119,119,169,169,2,169,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {241,171,148,31,172,34,66,60,156,140,2,2,2,75,75,2,2,2,2,2,2,2,190,190,2,2,2,30,2,2,2,2}, + {229,189,183,106,118,138,82,149,265,39,2,2,265,2,2,2,2,2,2,130,2,2,2,71,71,2,2,2,71,2,2,71}, + {165,157,127,21,64,15,80,130,130,130,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,74,2}, + {221,130,203,84,83,83,29,121,54,54,2,141,2,2,94,94,94,4,4,4,2,4,2,2,2,54,54,108,16,16,94,52}, + {230,166,20,160,121,102,153,94,16,67,2,2,2,2,2,2,97,97,97,2,2,97,97,2,97,97,97,97,97,97,97,97}, + {181,79,137,119,139,24,77,17,50,25,25,25,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {239,242,192,40,41,62,124,193,193,31,193,2,2,2,2,2,2,2,2,2,2,2,2,148,2,2,2,2,2,2,2,2}, + {239,178,73,122,239,51,95,48,78,88,78,2,2,2,2,2,2,2,2,2,2,2,144,144,2,2,144,144,144,2,144,144}, + {234,117,198,34,143,21,74,6,252,252,98,2,2,2,2,197,38,2,2,2,2,2,47,2,47,47,47,47,2,2,2,47}, + {179,110,38,28,58,39,16,29,42,125,202,8,8,129,4,4,2,2,2,67,67,2,2,2,2,2,2,8,67,67,2,2}, + {246,53,189,50,18,59,179,179,7,137,137,2,2,103,103,103,103,40,40,40,2,2,2,2,73,73,73,2,103,103,103,103}, + {239,133,87,92,193,12,206,238,238,238,31,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {191,244,60,193,18,32,193,104,74,125,125,66,2,2,2,2,2,2,2,2,2,2,125,125,2,125,125,125,2,2,2,2}, + {177,74,90,91,172,219,63,84,32,2,2,196,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {253,143,54,39,122,32,75,107,234,2,6,6,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {282,89,71,88,30,23,81,105,105,2,2,105,105,131,107,2,2,2,2,2,195,195,2,2,29,29,21,21,128,195,195,195}, + {259,115,171,40,156,71,67,24,24,2,2,2,24,4,4,4,2,234,2,2,2,2,2,2,2,2,2,74,74,2,2,2}, + {264,237,49,203,247,108,75,75,75,2,2,32,16,8,16,16,16,164,14,164,2,2,32,16,8,16,16,32,42,42,42,2}, + {264,106,89,51,29,226,23,286,286,151,151,151,151,151,2,2,2,2,2,2,31,31,31,2,2,2,2,2,2,2,2,284}, + {194,215,82,23,213,23,108,127,74,2,201,32,178,2,285,2,2,2,2,285,2,2,2,2,2,2,2,2,2,2,2,2}, + {196,267,251,111,231,14,30,52,95,2,154,53,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {266,67,22,101,102,157,53,95,130,2,42,76,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {281,205,107,178,236,122,122,316,76,215,215,2,60,2,2,2,2,2,2,227,2,2,2,2,2,2,2,2,27,2,2,2}, + {271,89,65,195,132,162,102,45,56,174,104,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {200,169,170,121,155,68,131,167,78,113,113,2,2,64,2,2,2,2,2,2,2,2,2,2,2,2,2,173,2,2,2,2}, + {288,143,265,264,71,19,231,169,27,27,27,2,2,2,2,2,2,2,2,2,2,2,2,2,51,2,2,2,2,2,2,2}, + {311,141,96,173,90,119,134,151,35,252,39,2,39,39,2,2,2,2,2,2,2,2,2,113,113,2,2,2,2,2,2,113}, + {311,230,52,138,225,346,162,216,216,91,160,182,91,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {275,167,128,244,184,184,44,210,237,139,139,139,139,2,2,2,2,2,2,2,2,2,2,73,2,2,2,2,2,2,2,2}, + {176,156,83,135,46,197,108,63,33,33,33,2,133,2,213,213,213,213,133,133,2,133,2,2,133,133,2,2,2,2,2,2}, + {283,125,141,192,89,181,106,208,124,124,2,112,112,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {289,191,171,152,191,173,54,13,21,56,56,56,2,2,2,2,2,2,2,2,2,220,2,2,2,2,2,2,2,2,2,2}, + {334,305,132,132,99,126,54,116,164,105,2,105,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,287,2,2,2,2}, + {240,166,44,193,153,333,15,99,246,99,2,2,99,99,2,2,2,2,195,195,195,2,195,195,2,263,263,2,195,195,195,263}, + {246,194,265,79,225,65,24,62,46,181,2,2,2,314,2,2,2,2,2,2,2,215,2,2,2,2,2,2,2,2,2,2}, + {229,334,285,302,21,26,24,97,64,40,2,2,2,231,231,231,231,65,2,148,2,2,2,2,2,2,2,2,2,2,2,2}, + {251,295,55,249,135,173,164,78,261,261,2,2,2,2,114,2,2,2,2,2,256,142,142,2,2,2,2,2,2,2,2,185}, + {232,153,55,60,181,79,107,70,29,35,2,2,58,58,2,58,2,2,2,2,61,61,2,61,61,2,2,61,61,90,2,90}, + {246,116,45,146,109,90,32,103,133,119,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {246,113,146,232,162,262,204,47,45,331,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {360,150,84,275,13,26,368,49,244,244,63,63,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {239,295,174,87,30,87,85,36,103,36,2,278,2,2,2,2,2,2,163,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {356,300,75,310,123,301,200,107,183,37,218,37,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {358,207,168,150,150,21,156,50,195,275,275,275,2,2,2,2,2,251,2,2,2,251,251,251,251,251,251,251,251,251,2,2}, + {322,194,234,62,236,147,239,400,255,255,80,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {326,276,134,100,143,113,115,221,13,339,194,194,194,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {337,132,27,45,14,81,110,84,238,224,211,2,29,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {192,213,113,174,403,117,342,342,311,35,35,2,2,2,2,2,2,2,2,101,2,2,2,2,2,2,2,2,2,101,101,101}, + {264,273,316,53,40,330,51,285,115,219,147,2,2,2,335,2,2,2,2,2,173,2,173,2,2,173,173,173,173,173,173,83}, + {254,293,407,118,54,296,160,231,4,4,93,2,2,2,2,2,60,61,2,2,120,127,127,127,88,88,88,88,88,88,88,88}, + {341,78,336,263,281,164,99,334,296,114,109,2,163,163,163,163,2,2,2,2,2,2,2,125,125,292,292,292,292,125,125,125}, + {355,87,212,100,89,210,133,344,120,45,45,138,138,138,138,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {274,141,46,219,158,284,38,79,73,185,35,6,81,2,2,2,2,53,2,2,81,81,2,81,2,2,2,53,53,53,53,53}, + {349,303,439,19,95,240,174,191,2,162,162,2,2,2,76,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {360,91,201,205,67,181,59,77,2,44,103,103,103,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,125}, + {283,154,261,91,77,147,227,105,116,311,256,256,2,116,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,32,2}, + {287,288,111,89,249,370,55,16,248,67,67,115,2,2,134,134,2,2,2,2,2,2,2,2,2,2,2,2,2,22,22,22}, + {284,270,282,37,29,181,160,49,285,285,374,250,2,374,374,2,2,2,179,179,35,2,179,179,2,179,179,2,2,285,285,285}, + {359,305,52,36,243,231,7,92,2,68,68,307,62,45,2,2,112,311,311,311,2,2,2,2,2,2,2,2,2,2,2,2}, + {288,119,218,137,364,38,27,380,2,2,211,23,33,2,2,2,2,2,225,225,225,2,2,225,225,225,2,2,2,2,2,2}, + {277,155,232,309,370,365,348,75,214,214,214,4,4,2,2,2,210,210,210,210,210,210,210,2,2,2,2,2,2,2,2,2}, + {292,204,91,41,124,190,107,322,125,125,125,125,125,25,25,62,2,2,146,146,2,2,62,146,2,146,114,146,114,2,2,2}, + {282,195,192,409,68,99,253,106,2,2,2,231,55,55,2,323,323,55,55,285,285,285,285,2,2,2,2,2,2,285,285,323}, + {299,122,174,403,113,77,63,275,2,2,2,138,276,227,38,227,2,237,2,2,2,2,2,2,2,2,2,2,352,352,352,2}, + {282,222,268,86,21,109,353,408,2,2,2,2,135,12,12,216,241,241,241,241,241,241,241,241,241,303,303,303,135,135,135,2}, + {374,94,89,257,137,246,186,196,2,2,2,2,2,454,122,122,122,122,2,2,2,28,28,94,94,94,94,94,122,122,122,122}, + {288,92,62,428,122,153,481,66,2,2,2,250,250,177,177,177,177,279,279,279,279,279,279,279,2,2,279,177,177,177,177,177}, + {288,370,141,284,207,192,450,67,2,2,2,183,217,217,217,183,183,167,202,202,202,202,167,167,2,2,2,164,164,80,167,167}, + {286,293,199,39,158,332,242,103,2,2,2,408,266,315,2,2,365,253,315,315,315,315,315,2,2,315,2,2,2,2,2,2}, + {407,83,435,187,40,16,52,65,2,2,244,39,77,119,119,2,2,2,119,342,342,2,2,2,2,2,342,2,2,58,58,119}, + {398,88,78,57,260,203,203,43,131,131,131,204,204,322,204,2,102,2,325,325,325,325,2,2,2,2,2,2,2,2,2,2}, + {390,174,70,155,163,67,225,49,2,34,34,151,151,2,2,111,2,2,111,111,2,2,2,2,2,2,2,2,2,2,2,2}, + {393,129,393,169,23,192,168,47,2,2,312,150,71,2,150,2,2,2,61,2,2,61,2,2,2,2,2,2,2,2,2,2}, + {408,136,71,63,63,159,222,68,181,181,124,227,14,14,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {294,169,79,242,160,123,178,290,186,186,56,399,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {415,228,69,68,193,122,21,362,33,22,362,57,2,2,2,2,46,46,196,196,196,2,196,196,196,2,196,2,2,2,2,2}, + {415,130,241,185,312,175,309,199,94,281,47,47,2,2,2,2,206,307,221,2,2,2,2,2,239,239,239,239,239,206,206,206}, + {417,238,147,165,346,19,92,164,266,291,291,43,2,2,2,345,2,2,2,345,345,2,2,2,2,2,345,2,2,2,2,2}, + {456,192,86,182,35,174,342,102,210,210,210,393,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,256,256,158}, + {307,255,92,38,325,61,103,246,176,319,80,89,2,241,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {432,168,63,154,166,46,479,145,144,288,288,288,288,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {341,256,113,85,188,233,161,29,110,167,91,91,253,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {311,360,312,158,73,16,106,209,472,48,24,203,203,2,2,2,2,234,234,234,2,234,234,203,2,2,2,234,234,234,234,234}, + {437,196,161,100,132,246,395,187,35,35,35,2,2,35,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {438,174,338,145,155,276,422,374,4,463,463,99,224,70,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {426,225,211,130,325,283,353,96,282,23,299,2,2,2,63,63,2,276,276,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {430,101,288,38,200,332,325,193,123,123,88,2,2,2,2,2,231,231,139,139,139,139,139,139,139,139,139,139,139,139,139,139}, + {434,143,308,389,365,363,174,63,121,125,260,2,2,260,260,2,2,2,2,2,2,2,2,2,2,258,2,2,2,258,2,2}, + {453,123,201,141,229,223,234,494,102,102,102,2,2,102,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,252}, + {438,168,65,264,304,74,168,88,114,132,187,2,127,127,2,2,2,2,2,81,81,56,2,2,2,307,2,2,2,2,81,81}, + {324,181,141,129,33,171,173,291,227,373,52,301,301,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {448,119,431,111,135,50,242,95,148,49,49,49,68,2,2,2,2,2,2,2,2,49,2,2,2,2,2,2,2,2,2,2}, + {335,114,55,47,33,173,287,345,198,198,136,238,238,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {468,377,243,237,332,512,27,167,22,169,14,14,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {456,162,188,223,408,209,28,164,299,299,258,186,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {445,391,115,226,96,456,239,214,556,158,158,282,2,2,2,2,2,2,2,2,2,2,2,2,2,331,2,2,2,2,2,2}, + {360,397,130,172,407,479,295,13,38,199,199,346,2,2,2,2,2,2,145,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {512,136,129,361,180,61,274,128,422,27,292,165,2,2,2,2,2,2,363,117,117,117,117,2,2,2,2,363,2,2,2,2}, + {478,433,483,302,200,227,273,27,171,171,371,102,2,2,2,2,2,20,2,2,2,2,2,2,2,2,403,403,2,2,2,2}, + {485,158,454,86,212,60,93,40,209,188,188,106,2,231,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {390,448,111,145,47,555,367,317,315,52,429,435,429,429,2,2,2,2,2,2,2,2,229,2,2,229,2,2,2,229,2,2}, + {490,331,187,398,407,373,497,219,423,423,378,378,2,419,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {378,406,112,198,539,550,516,59,240,240,23,316,2,122,2,2,2,2,2,2,2,2,2,2,111,111,2,2,2,95,2,2}, + {474,373,248,330,40,113,105,273,103,407,2,165,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {495,406,306,239,172,323,236,50,37,435,2,310,56,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {498,447,112,241,552,119,227,189,140,140,140,140,140,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {505,132,169,418,342,28,319,301,172,530,317,317,335,2,2,2,2,2,2,376,2,2,2,2,2,2,2,2,2,2,2,2}, + {397,393,191,269,462,151,264,134,307,307,2,163,163,2,2,2,2,2,2,2,2,2,2,2,2,2,159,2,2,2,2,2}, + {485,491,325,149,122,145,228,100,311,64,2,62,137,2,137,2,2,2,2,2,2,2,392,2,2,2,2,2,2,2,2,2}, + {364,462,360,383,182,187,123,69,129,146,2,156,149,2,149,2,2,2,2,2,2,2,303,303,303,2,2,2,2,2,149,266}, + {507,195,130,401,363,171,483,20,86,464,2,89,89,2,26,2,2,2,2,2,425,425,2,2,2,2,2,2,2,2,2,2}, + {380,220,87,122,242,78,207,371,95,305,2,2,2,2,440,440,445,358,358,331,331,358,445,445,445,445,445,445,445,445,445,445}, + {507,221,247,137,182,90,28,207,325,438,2,2,2,2,2,187,232,438,2,2,68,37,37,37,37,37,37,37,37,37,161,2}, + {509,265,101,126,203,86,152,416,352,85,2,2,2,284,391,368,2,2,152,2,2,2,325,2,2,2,2,2,2,2,2,2}, + {572,359,332,480,68,535,59,504,365,21,2,2,246,54,246,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {415,178,178,372,415,400,73,82,348,99,2,23,325,44,2,2,2,2,2,2,2,2,325,2,2,2,2,2,2,2,2,2}, + {430,275,236,361,42,552,368,236,653,74,65,458,288,307,307,2,2,2,2,2,2,2,65,65,2,2,2,2,2,2,2,2}, + {434,139,58,437,130,441,188,15,63,145,145,145,300,2,2,2,2,300,2,2,2,2,2,2,2,2,401,401,401,401,401,401}, + {542,138,266,514,552,202,103,197,574,48,2,96,96,2,2,96,96,217,2,2,2,2,2,2,2,2,2,2,2,2,2,217}, + {546,494,72,272,550,219,213,209,169,404,69,464,86,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {602,466,332,458,99,244,255,183,446,670,2,186,323,2,2,2,2,2,2,2,2,2,2,2,2,2,2,292,165,165,165,165}, + {422,413,561,110,242,62,436,478,18,150,606,88,643,2,249,2,2,2,2,456,2,2,2,2,2,2,2,2,2,2,2,456}, + {522,141,154,253,264,53,120,93,274,52,44,203,556,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {600,249,375,555,421,322,317,84,517,517,268,106,353,2,2,2,2,2,2,2,2,2,268,2,2,2,2,2,2,302,2,2}, + {555,516,310,438,290,559,52,265,248,193,285,441,285,285,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {555,300,232,386,470,300,355,177,57,407,450,279,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {544,177,79,306,256,402,205,496,398,115,115,43,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {534,274,194,220,575,81,206,544,341,85,137,429,429,429,429,344,2,2,2,2,2,315,315,315,315,315,315,72,72,72,2,2}, + {400,136,112,136,273,277,205,578,122,122,230,230,2,2,2,2,2,2,2,2,2,2,2,2,2,2,302,2,2,2,2,2}, + {576,421,115,52,253,373,17,657,43,178,178,58,485,485,485,485,485,485,2,2,2,159,159,159,159,2,619,2,2,2,2,2}, + {576,301,142,329,96,41,302,528,126,112,206,206,2,2,2,2,2,2,206,206,2,206,206,2,191,206,206,191,191,191,191,206}, + {548,538,508,250,539,102,73,285,119,433,480,480,2,2,2,480,480,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {622,526,294,56,498,176,237,351,25,26,474,55,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {446,163,469,481,240,278,51,373,491,13,22,419,2,2,2,2,2,2,2,2,2,176,176,2,2,2,2,2,2,2,2,2}, + {445,223,102,108,120,166,68,214,737,504,96,96,206,377,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,39,39,528}, + {453,121,489,84,434,505,78,575,468,372,468,468,83,468,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {425,355,128,58,194,82,438,117,10,34,34,35,112,107,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {432,479,328,443,253,634,271,429,406,543,406,543,543,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {433,294,192,205,152,70,99,68,392,169,309,390,390,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,199,2,2,2}, + {456,383,487,311,57,579,673,264,582,187,184,43,43,2,2,2,2,501,501,501,2,2,2,2,2,2,2,2,2,2,2,2}, + {437,561,384,619,363,420,614,117,217,247,405,142,142,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {434,372,239,508,478,26,375,255,151,151,650,112,251,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {437,133,516,423,305,90,135,25,266,487,6,286,286,2,2,2,2,2,2,2,2,2,2,2,2,510,510,2,2,2,2,2}, + {463,341,170,401,178,79,305,98,162,166,32,392,335,335,335,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {610,477,478,516,318,184,267,423,190,494,494,2,336,336,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {611,211,491,224,47,54,124,268,271,271,223,2,2,2,2,2,2,2,2,2,2,2,2,359,2,2,2,2,2,2,2,2}, + {590,463,461,162,162,622,167,254,29,377,377,75,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {478,388,612,404,491,561,180,80,262,58,94,2,2,275,2,2,2,2,2,151,2,2,2,2,2,312,312,312,2,2,2,275}, + {629,225,67,623,298,588,354,49,41,185,176,63,63,63,2,2,2,2,2,2,2,2,2,2,2,2,8,435,32,32,435,435}, + {671,275,392,298,612,328,337,215,58,58,124,2,2,490,392,2,2,2,125,457,457,2,2,2,2,2,2,2,2,2,2,457}, + {448,126,129,168,209,340,40,96,509,509,509,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {667,246,160,68,737,203,168,628,46,128,358,2,2,2,121,121,2,2,2,2,2,2,560,121,2,2,2,2,2,2,2,121}, + {635,212,284,356,187,591,275,361,194,317,488,2,2,2,2,2,2,97,6,2,6,247,2,2,2,2,2,2,2,2,2,6}, + {612,395,104,86,264,321,521,325,252,53,178,100,100,100,16,343,343,343,343,343,2,2,2,2,2,2,2,2,2,343,343,343}, + {486,428,287,472,292,141,504,178,585,98,282,2,2,2,2,2,2,2,2,2,2,2,2,284,284,284,78,284,2,2,2,2}, + {612,327,212,565,450,385,201,649,423,491,106,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {462,579,236,447,60,162,427,258,73,742,742,2,742,742,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {495,440,89,439,65,207,459,407,139,131,624,2,380,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {469,507,276,227,66,237,260,386,27,666,31,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {646,393,273,238,24,13,253,127,368,316,316,316,150,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {626,196,111,465,386,431,181,414,614,391,349,318,389,2,389,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {667,257,290,122,109,523,95,26,282,49,374,236,236,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,88,2,2}, + {653,169,261,533,488,282,213,443,337,480,503,174,534,2,2,2,2,2,534,2,2,2,2,534,2,2,2,2,534,2,2,2}, + {670,555,160,90,604,604,50,459,376,545,316,180,526,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {639,253,95,380,108,448,223,254,381,30,6,644,6,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {642,160,702,90,157,254,278,521,650,277,74,554,122,2,2,2,2,2,2,517,174,174,174,2,2,2,2,2,2,2,2,2}, + {678,254,190,197,637,49,130,25,374,357,357,411,643,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,537,2,2}, + {512,347,65,546,434,87,18,123,672,412,316,6,699,6,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {657,233,108,38,147,53,136,168,408,477,477,279,268,289,2,2,2,2,2,2,289,2,2,2,2,2,2,2,2,289,289,2}, + {498,431,217,101,78,143,111,113,181,825,458,140,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {660,624,376,472,165,66,158,308,492,779,305,305,2,576,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {521,249,388,155,467,245,134,311,72,312,312,623,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {408,348,216,299,302,668,347,63,172,141,272,168,678,2,2,2,512,2,2,2,2,4,2,2,2,494,64,64,64,128,16,512}, + {669,421,230,70,212,845,237,347,148,76,823,472,2,2,2,132,2,2,2,2,2,2,2,383,132,383,2,2,383,383,383,383}, + {693,530,139,82,780,416,270,278,330,484,484,200,2,2,2,2,137,94,2,2,2,2,2,2,2,2,484,2,2,2,2,2}, + {672,150,164,622,196,75,302,119,42,314,314,132,60,60,60,298,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {705,302,411,705,691,160,809,40,32,867,826,826,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {684,229,138,46,407,399,82,254,267,31,31,45,2,209,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {707,323,409,27,31,157,492,463,886,412,251,251,304,190,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {715,521,636,304,402,459,435,571,611,214,214,43,43,358,2,2,2,2,358,2,2,2,2,2,2,358,358,358,2,2,358,358}, + {768,224,219,425,467,147,151,643,316,263,263,263,263,263,2,2,2,2,2,272,139,2,2,2,2,2,2,2,2,2,272,53}, + {555,543,434,78,850,174,277,194,4,100,471,69,69,424,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {690,206,572,877,600,129,288,52,19,147,222,222,147,147,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {793,279,264,566,252,495,872,492,482,107,294,503,350,350,2,2,2,2,2,2,2,285,285,273,273,273,273,2,2,2,2,2}, + {703,427,225,320,136,47,103,547,239,217,73,68,68,204,204,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {791,275,60,137,352,839,67,476,356,216,216,563,563,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {703,312,472,588,228,512,386,668,477,617,389,389,389,2,296,2,2,2,2,343,343,2,2,343,343,2,2,617,617,617,617,2}, + {709,509,697,145,252,194,304,192,192,623,623,4,423,2,2,2,199,423,2,2,2,222,222,2,2,623,623,623,623,623,2,222}, + {587,453,117,107,672,86,248,568,568,294,294,513,78,2,2,164,82,2,2,2,2,22,2,2,2,2,2,2,2,2,2,2}, + {741,466,378,135,737,131,159,469,59,2,59,59,187,2,204,2,2,2,2,2,2,2,2,2,798,2,2,798,798,798,798,798}, + {539,310,463,103,553,45,609,326,197,2,62,113,272,2,62,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {750,703,182,242,92,335,272,466,594,2,701,569,474,129,140,140,2,507,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {547,210,113,361,584,121,65,307,98,2,2,552,514,514,2,514,207,514,514,514,2,2,2,2,2,2,2,2,2,2,2,2}, + {555,229,328,91,272,815,483,749,468,2,92,92,4,92,2,2,2,258,258,258,2,258,258,2,2,2,2,258,2,2,258,258}, + {580,145,358,434,630,73,604,366,366,2,2,398,398,207,2,207,487,2,2,487,207,2,2,207,207,207,2,2,2,2,207,207}, + {457,520,93,460,275,525,300,184,354,147,147,147,147,179,82,82,82,82,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {872,630,513,218,719,174,197,104,86,281,281,281,541,642,281,94,2,45,94,2,335,335,2,2,2,2,2,2,2,2,2,84}, + {765,421,129,298,867,365,222,476,401,142,90,22,22,88,226,657,2,2,477,2,2,2,2,2,226,226,2,226,2,2,2,226}, + {833,634,228,520,113,329,279,420,581,2,2,385,385,110,450,2,733,2,2,2,561,561,2,561,2,2,2,2,2,2,2,2}, + {587,553,360,539,227,800,312,143,536,2,2,2,64,64,64,2,2,2,179,179,493,2,2,184,184,184,58,2,2,2,493,493}, + {744,466,389,280,229,134,363,177,389,2,2,2,536,273,536,536,536,536,168,45,45,45,45,2,2,2,2,2,2,2,2,2}, + {841,222,158,469,253,91,347,241,766,2,2,2,88,88,88,439,439,439,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {462,653,478,67,269,150,474,711,220,669,669,669,669,669,390,352,325,2,229,545,545,545,545,545,545,545,545,2,545,352,309,352}, + {468,430,849,689,202,427,45,34,105,2,2,2,2,4,4,4,4,4,4,4,2,2,2,4,4,4,4,4,2,2,2,2}, + {610,289,503,744,775,512,605,454,484,2,2,2,444,466,145,631,2,631,631,631,631,631,631,631,631,631,2,2,631,631,631,858}, + {792,169,306,843,246,123,293,229,483,2,2,2,165,163,163,163,163,440,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {563,325,717,766,440,705,290,123,228,2,2,2,32,64,146,2,2,2,116,79,79,2,146,146,79,79,79,2,2,146,146,79}, + {795,185,350,211,82,537,106,680,62,2,2,537,423,423,423,2,2,501,501,2,501,2,501,2,2,2,2,2,2,2,2,2}, + {633,425,295,548,497,163,381,461,89,2,2,831,583,896,38,2,625,2,2,2,276,276,2,2,276,2,2,2,2,2,2,2}, + {767,318,84,97,208,387,423,196,417,2,396,396,396,396,396,128,128,2,2,2,328,328,4,4,4,4,101,2,2,328,82,16}, + {802,533,869,638,67,192,805,223,219,2,2,191,178,178,77,77,2,2,2,2,431,431,2,2,2,431,431,2,2,431,2,2}, + {781,638,410,399,336,465,856,426,28,2,4,4,6,6,2,2,2,449,372,372,449,449,449,2,2,449,449,449,449,449,449,2}, + {807,377,237,443,388,286,158,349,491,32,32,260,260,260,2,2,260,615,615,615,2,2,260,260,260,260,260,615,615,615,615,615}, + {780,359,766,618,41,596,86,636,287,707,707,96,49,373,613,373,2,2,2,2,2,2,2,613,613,613,2,2,2,2,2,2}, + {788,497,334,93,319,169,273,540,904,2,903,569,569,569,272,272,2,2,2,2,571,571,571,571,571,571,571,571,571,571,571,571}, + {622,309,913,550,994,90,257,588,29,526,526,526,496,496,576,2,2,2,2,2,182,182,182,2,2,447,447,447,447,447,447,182}, + {814,652,456,774,624,870,27,739,464,2,108,578,578,561,295,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {818,280,99,873,165,426,341,74,479,342,727,684,684,662,662,2,2,2,2,2,2,662,2,2,2,2,2,2,2,2,2,2}, + {593,411,953,203,89,57,785,354,349,424,424,707,707,707,829,2,2,2,2,2,670,670,670,2,2,424,424,424,2,2,670,424}, + {629,560,621,245,683,633,495,551,472,2,31,74,489,684,555,684,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {901,490,693,410,666,119,703,593,201,61,70,70,774,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,418,418}, + {669,321,391,548,189,157,337,42,796,871,276,622,30,2,2,2,2,2,2,2,580,580,107,2,2,2,2,2,434,434,434,434}, + {610,236,633,300,681,358,72,281,148,466,466,283,275,2,386,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {929,360,102,893,329,136,515,33,170,581,268,35,777,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {859,584,475,745,506,900,40,869,143,612,175,275,209,12,12,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {822,581,76,382,72,347,964,324,137,61,61,28,623,351,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {655,330,324,151,166,431,58,174,142,115,1003,66,724,778,2,2,2,503,503,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {867,820,301,252,61,331,105,309,562,218,365,326,768,672,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {623,330,182,489,212,223,741,490,40,412,801,681,681,801,2,2,71,2,2,2,2,2,2,427,2,2,2,2,2,2,2,2}, + {859,844,510,859,118,190,550,29,159,622,622,382,258,382,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {612,237,272,53,534,682,372,935,494,536,536,599,599,599,2,536,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {843,730,235,233,816,495,598,134,131,604,227,378,378,553,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {667,397,121,526,321,660,848,729,357,137,268,711,521,521,2,2,2,2,2,2,2,2,2,2,2,2,2,194,2,2,2,521}, + {939,783,796,676,259,643,103,289,15,471,80,80,2,239,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,888}, + {670,595,333,257,907,413,548,341,327,350,612,700,700,700,700,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {678,274,695,790,169,701,707,1084,470,123,846,846,217,121,317,2,2,2,83,83,83,83,83,83,83,83,83,2,2,2,2,2}, + {877,181,375,79,199,256,223,295,135,371,395,354,2,307,944,2,813,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {882,417,475,424,311,646,346,207,74,157,590,356,2,2,324,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {708,442,186,698,345,103,687,463,163,416,416,107,2,2,2,375,375,416,6,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {865,675,786,568,112,197,225,348,372,497,215,215,2,2,2,2,159,159,150,224,224,141,2,2,2,2,141,141,141,141,141,141}, + {844,244,672,489,839,263,14,233,422,392,8,392,2,2,2,2,2,2,815,815,815,815,257,257,105,105,2,2,2,815,815,815}, + {693,726,117,167,535,725,224,78,716,100,460,299,2,2,2,2,921,744,2,2,2,2,2,378,2,2,178,178,178,2,178,178}, + {898,559,396,742,51,143,411,221,116,756,756,756,2,2,2,701,701,2,2,2,2,240,225,256,322,322,240,240,240,240,240,322}, + {697,540,358,391,932,309,103,73,35,353,353,503,2,2,353,134,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {982,579,548,413,416,103,71,101,1039,526,684,684,2,2,656,2,2,2,2,2,2,2,2,2,2,2,656,656,656,2,656,656}, + {695,881,335,126,429,476,772,667,974,98,433,49,129,129,2,2,2,2,2,2,2,2,2,2,544,2,544,2,2,2,2,544}, + {859,361,215,569,255,378,543,436,220,34,105,105,816,816,816,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {705,770,134,178,940,944,654,600,46,797,797,591,2,145,616,2,2,2,2,2,2,389,389,2,122,2,2,2,389,389,909,389}, + {642,757,247,513,372,54,546,971,271,61,61,1018,2,143,332,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {988,271,675,163,379,108,48,472,870,485,485,18,2,485,528,528,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {865,827,614,74,725,685,724,190,178,272,835,722,2,35,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {923,397,722,186,203,575,24,144,36,526,206,787,12,100,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {718,359,103,558,684,560,67,35,120,342,680,265,265,265,2,2,265,2,2,2,2,2,2,2,2,2,430,2,2,2,2,2}, + {927,493,988,194,97,1006,377,578,105,248,707,784,98,784,2,2,2,2,2,2,2,2,2,370,370,2,370,2,2,2,2,2}, + {900,455,485,601,353,69,67,965,25,226,314,314,883,923,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {903,259,153,106,289,916,861,41,441,368,131,131,262,671,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {945,358,160,196,82,403,362,195,376,877,521,336,521,77,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {912,516,108,555,306,274,55,197,565,174,659,208,441,441,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {753,242,194,619,345,94,463,485,163,85,412,575,270,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {940,226,320,666,269,54,542,174,109,290,754,524,649,2,202,2,2,2,2,2,2,2,776,202,776,776,776,2,2,202,202,202}, + {915,210,456,377,303,237,225,521,621,175,569,20,124,2,601,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {672,652,792,253,796,404,171,90,406,433,43,159,72,2,2,372,2,540,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {733,439,537,37,149,650,916,443,743,621,921,664,664,2,2,2,2,2,682,523,523,523,2,2,523,523,523,523,523,523,523,523}, + {982,344,812,567,243,52,246,369,439,205,600,739,730,2,2,2,61,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {982,604,126,65,633,657,22,776,161,45,725,44,4,2,2,2,2,2,2,2,2,2,269,269,2,2,2,2,2,2,2,2}, + {745,600,284,1117,459,1135,300,52,845,331,334,334,334,2,334,334,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {936,409,217,57,574,395,481,245,548,268,447,598,375,2,192,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {986,241,233,45,721,325,350,222,35,1065,1065,1065,1065,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {755,796,877,981,259,194,1180,215,90,658,662,662,662,2,36,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {981,626,987,827,466,458,578,346,475,223,223,223,342,1058,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,728}, + {949,422,941,491,66,786,592,429,307,123,40,478,478,478,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {992,723,625,251,431,544,309,466,700,644,484,837,904,320,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1077,496,819,340,974,122,39,1209,819,18,461,648,648,394,2,2,2,2,2,2,61,2,2,2,2,2,394,2,2,2,2,394}, + {999,674,212,673,279,579,462,754,89,866,345,110,110,887,2,2,2,2,2,707,707,2,2,2,2,2,2,2,2,2,2,707}, + {1083,356,367,357,559,213,606,477,71,103,790,103,299,299,2,2,2,2,2,2,406,406,2,2,2,2,2,2,2,2,2,2}, + {1005,260,389,960,501,714,118,73,334,1019,704,204,504,205,822,822,2,2,2,2,2,2,2,2,2,2,684,2,2,2,2,2}, + {738,749,769,610,306,326,328,578,479,840,840,840,68,192,2,150,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1010,937,449,474,154,456,766,318,275,444,709,2,778,778,778,806,779,779,2,2,2,2,2,2,2,2,806,2,2,2,287,287}, + {1011,780,134,945,183,42,741,25,252,164,205,222,222,222,147,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1118,427,294,404,268,217,922,515,19,1045,1045,2,833,291,448,2,2,2,2,2,2,2,2,2,175,2,2,2,2,2,2,2}, + {1094,640,912,223,67,472,623,623,1244,65,1009,1209,1209,812,387,2,2,2,513,2,2,2,2,2,2,2,2,2,2,2,1209,234}, + {722,375,264,390,515,498,1161,391,884,551,238,2,2,825,549,2,2,2,551,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {792,250,299,210,496,682,94,207,220,227,227,2,2,227,73,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1022,409,93,359,983,345,280,280,104,940,940,2,2,382,1039,2,2,2,2,831,2,2,2,2,2,2,2,2,2,2,2,2}, + {1027,925,413,335,327,826,250,122,293,773,564,541,420,420,420,774,763,2,2,2,2,2,2,900,110,110,2,763,2,2,2,2}, + {1028,730,807,119,209,146,230,498,164,309,309,2,2,2,693,912,430,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {997,525,680,120,466,728,288,110,1082,544,572,2,2,663,290,290,2,2,754,2,2,2,2,2,582,582,582,582,582,2,2,2}, + {1055,395,795,561,222,85,294,433,377,89,89,2,2,2,456,821,2,2,821,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {997,614,240,638,755,575,874,321,600,235,665,2,2,2,154,154,767,767,2,767,2,2,2,2,2,2,2,2,2,2,2,2}, + {802,298,672,424,104,623,152,159,476,760,66,2,2,2,215,215,490,490,490,2,2,2,2,2,490,490,490,490,490,490,490,490}, + {1128,788,124,501,561,1015,419,787,48,620,705,2,2,2,2,88,18,2,215,215,215,2,2,215,215,2,2,2,215,2,2,2}, + {807,433,721,434,449,242,170,842,21,4,642,2,2,2,2,2,4,4,4,4,2,856,856,856,885,885,856,856,856,856,856,885}, + {755,612,235,265,369,855,414,362,478,518,518,2,2,64,16,8,32,4,16,8,8,1041,501,1041,2,2,64,16,8,8,16,270}, + {1004,719,1041,460,551,516,135,417,130,698,698,2,2,2,655,655,655,655,655,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1017,568,930,1113,556,1299,114,881,690,475,641,2,2,2,779,779,103,2,528,2,2,2,2,2,2,528,528,2,2,910,910,2}, + {814,473,286,752,476,779,420,569,742,164,490,2,2,2,793,812,812,812,2,812,812,2,2,526,526,812,526,2,2,2,526,526}, + {818,301,273,664,206,971,895,590,912,523,523,2,2,452,384,255,2,130,130,130,130,865,2,2,2,255,2,2,2,2,2,2}, + {820,249,292,1017,1017,143,403,37,433,456,515,2,2,69,640,2,2,2,2,2,2,2,2,2,2,2,2,824,824,824,2,2}, + {1078,527,589,244,170,892,827,606,1165,773,189,2,2,240,22,2,2,2,2,2,2,759,621,621,621,621,621,621,621,621,621,621}, + {865,1132,428,582,254,408,536,376,825,116,116,1266,1266,1266,705,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1062,268,389,1325,598,276,1270,48,572,439,302,2,544,609,544,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1065,517,247,1142,247,674,385,120,592,177,98,2,956,364,275,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {635,503,594,203,456,1246,221,396,1151,178,66,2,781,587,86,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1157,395,446,280,1130,695,668,271,111,882,477,615,615,615,2,2,2,2,2,2,2,2,615,615,615,615,615,615,615,2,305,2}, + {830,397,932,519,818,113,367,694,88,535,535,414,343,175,2,2,2,2,2,2,2,2,2,2,414,864,2,2,864,864,864,864}, + {793,463,329,730,390,551,968,92,511,470,424,563,672,563,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1050,749,809,479,87,757,288,172,597,722,4,418,418,390,2,2,2,2,2,390,390,2,2,2,2,2,2,2,2,2,2,2}, + {1084,402,130,1077,276,154,1068,779,511,853,83,757,757,38,2,2,2,2,2,202,2,2,2,2,2,2,2,2,2,2,757,2}, + {1090,255,271,110,159,235,158,236,271,815,1300,416,416,416,2,2,416,416,2,2,2,399,791,791,2,791,2,2,2,2,791,791}, + {1058,417,271,172,312,363,184,191,28,183,759,214,759,39,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1057,385,263,395,901,274,727,340,1117,263,813,870,858,429,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1102,846,985,1085,764,124,764,51,874,612,478,801,478,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1120,665,311,695,319,1033,511,297,602,1030,1030,714,240,240,2,2,2,2,2,2,2,2,2,2,2,2,2,953,2,2,2,2}, + {814,293,763,661,575,631,524,636,112,691,595,1103,405,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1106,662,258,190,1315,214,530,263,318,904,877,1317,318,2,510,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1206,469,299,1052,655,114,189,213,321,188,64,475,475,2,2,662,662,662,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1120,1159,358,347,838,207,357,167,476,52,672,38,822,2,2,2,2,2,2,213,2,2,2,2,2,2,2,2,2,2,2,2}, + {1076,596,553,545,79,727,881,121,298,169,639,368,695,115,115,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1130,177,84,673,350,543,543,95,128,954,430,884,884,2,884,884,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1222,412,430,707,691,746,131,607,311,607,112,217,912,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {820,461,681,382,273,273,358,274,274,91,887,676,386,2,676,676,2,2,2,2,2,2,2,200,2,2,2,2,200,2,2,2}, + {1096,1166,209,407,1127,400,974,322,428,906,631,134,171,2,2,2,2,664,664,664,2,2,2,2,2,2,2,2,2,2,2,2}, + {1091,946,437,51,527,802,597,639,587,645,510,586,586,2,2,2,2,2,2,2,2,2,2,2,2,2,2,168,168,168,168,168}, + {1148,585,868,1282,666,417,733,1231,515,332,1213,337,337,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1103,276,174,408,233,170,955,108,530,354,585,38,677,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,476}, + {1167,478,1169,1053,563,371,108,772,413,497,1338,991,660,2,2,2,2,2,2,2,2,2,2,2,2,27,2,2,2,2,2,2}, + {1108,437,1160,324,868,686,361,399,786,1161,1161,707,731,731,655,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1116,331,280,422,1109,341,570,243,849,241,566,61,608,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {898,782,478,1208,196,983,608,537,196,1141,141,296,715,715,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1099,1187,300,240,268,413,1366,634,184,768,773,365,783,224,783,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1158,945,300,1115,205,495,435,302,187,774,774,843,843,284,284,2,2,2,2,909,933,933,933,2,2,909,909,2,2,2,2,909}, + {904,660,1283,46,33,124,416,218,152,970,1241,305,307,307,307,260,894,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1127,553,287,58,739,99,514,739,766,42,580,241,598,598,936,936,936,629,629,629,629,2,2,2,2,2,2,2,2,2,2,2}, + {1142,370,287,925,307,1232,129,11,1284,1056,33,33,536,521,2,1286,2,2,2,2,2,2,2,2,2,2,2,2,847,847,847,847}, + {1140,814,528,677,84,1192,305,637,335,451,103,325,77,969,2,651,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1297,600,419,985,846,493,186,109,147,239,197,762,762,327,327,1004,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1181,615,482,653,238,130,313,506,98,1314,730,730,730,730,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {921,613,628,1288,111,150,191,233,633,83,387,602,105,394,2,2,2,2,2,2,2,351,2,2,351,351,351,2,2,2,351,351}, + {1192,555,586,516,1288,733,64,653,364,273,421,215,75,75,2,2,2,2,2,2,953,953,953,953,8,383,383,2,161,383,953,953}, + {1160,617,505,1205,374,906,23,408,194,91,91,91,585,984,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1203,1101,497,352,254,309,464,123,607,1080,265,1145,1145,1145,284,284,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1210,656,1026,782,802,442,1319,734,794,165,165,796,93,796,2,829,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {963,646,721,1161,219,667,1088,485,692,692,663,535,553,662,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,686,686,2}, + {966,590,140,297,189,844,633,12,847,742,742,244,281,34,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {941,231,1038,309,173,770,413,560,855,660,721,1103,721,721,721,2,2,2,2,2,2,2,2,2,2,2,2,174,2,2,2,2}, + {1213,305,656,983,1399,1196,692,986,9,339,754,308,2,308,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {972,768,1109,523,642,546,1452,29,1296,13,813,813,2,1496,2,2,2,2,2,2,2,165,165,165,165,165,165,2,2,2,2,544}, + {1330,671,528,831,1426,735,33,425,364,119,363,978,2,761,483,476,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1188,217,838,237,379,202,785,949,479,169,348,872,2,872,872,2,2,2,2,2,2,1028,2,2,2,2,2,2,2,2,2,2}, + {1190,286,513,881,390,215,387,130,749,554,1110,519,160,160,160,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1247,353,973,217,1044,1318,1115,319,203,390,1244,225,2,2,508,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {893,560,132,1420,721,191,568,799,412,22,322,93,2,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {987,774,678,175,145,264,588,97,1308,6,828,1129,2,2,2,45,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {955,980,753,96,574,259,1327,556,342,1415,1036,1036,478,478,478,478,507,2,2,2,2,151,2,2,317,2,2,2,2,2,595,595}, + {882,1038,211,110,942,337,1305,1225,661,183,381,381,2,2,2,2,347,2,2,2,2,2,2,2,600,431,431,431,431,431,431,431}, + {1208,486,343,725,677,1204,135,139,924,170,1111,317,2,2,2,2,202,706,202,107,107,107,2,2,706,706,107,107,2,2,2,706}, + {1259,1017,456,298,443,838,137,744,551,334,36,951,2,2,2,699,718,2,2,984,2,2,2,2,2,2,984,984,2,2,2,2}, + {1212,1186,641,284,565,636,895,82,690,117,184,184,2,2,2,397,902,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1263,370,132,635,381,47,537,179,1192,301,1282,33,2,2,2,1553,2,2,2,2,2,2,2,2,2,2,2,307,307,2,2,2}, + {1223,433,252,572,424,82,221,107,382,430,203,461,2,915,362,964,2,2,964,2,2,2,2,2,964,964,964,964,964,485,485,485}, + {1015,593,112,1408,51,104,199,221,931,1010,928,928,2,2,878,878,2,2,2,2,731,731,2,731,731,2,731,2,731,731,731,2}, + {1220,410,1193,352,260,434,469,41,1090,961,961,728,2,2,330,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {898,1043,391,1289,29,830,184,321,1136,85,1133,1082,864,864,2,2,2,2,2,2,2,2,789,789,2,789,789,2,2,789,789,2}, + {1223,434,851,152,140,1495,190,397,925,37,1080,430,2,2,204,2,759,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {989,1043,184,232,64,403,284,745,171,171,995,223,380,380,1400,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {939,1070,1288,254,973,901,321,109,568,713,336,988,2,946,262,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1276,636,569,258,325,675,342,85,88,579,833,833,833,833,520,2,2,2,2,520,520,2,2,2,2,2,2,2,2,2,2,2}, + {982,508,815,214,206,602,448,685,446,572,1549,8,1047,1047,1047,2,2,2,2,2,2,2,363,502,2,2,71,363,2,2,363,363}, + {1288,1398,789,514,151,600,1618,1194,1419,441,234,204,1191,438,828,2,857,857,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1002,342,1045,757,1008,979,322,240,1211,171,552,123,2,129,129,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1401,402,525,293,97,223,452,808,61,169,1023,1023,886,886,1023,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1001,644,263,164,136,939,624,95,489,1023,1107,331,331,10,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1011,475,845,532,567,951,663,295,877,1275,227,39,618,683,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1401,741,509,797,47,157,1256,482,1513,899,736,780,780,210,2,2,2,2,783,783,2,2,2,2,2,2,2,2,2,2,2,2}, + {1047,880,369,402,641,446,639,586,277,396,419,275,825,820,2,2,2,238,238,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1273,701,831,1294,1580,137,162,415,563,11,92,116,116,116,2,2,2,2,2,2,1029,1029,1029,504,504,877,877,877,877,877,1029,1029}, + {1335,400,315,412,172,125,568,1024,58,601,398,985,640,577,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1453,947,486,485,453,415,1164,684,504,605,422,998,727,727,2,2,2,1136,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1057,1198,146,529,284,1286,160,135,75,686,648,1425,821,586,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1052,442,936,64,132,1378,1323,161,161,161,230,131,12,12,2,2,2,2,2,2,2,2,2,2,2,998,998,998,998,2,2,2}, + {1422,838,234,554,736,243,344,526,1108,33,1303,699,249,305,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1279,681,423,813,806,269,412,420,985,485,761,1013,649,796,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {938,614,523,557,898,624,178,461,287,985,371,371,260,613,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1335,834,652,528,536,523,497,60,173,777,238,59,4,59,4,8,2,2,2,559,559,559,559,559,559,559,2,2,559,559,559,2}, + {1040,998,324,93,887,497,1326,443,152,1193,595,80,80,80,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1302,1116,283,1006,891,838,768,373,468,968,1178,1178,1269,1269,876,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1027,1128,114,395,357,417,848,22,389,1257,734,838,838,301,900,2,90,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1072,724,717,877,873,369,1031,698,917,1641,1641,1641,53,549,549,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {987,1243,424,240,53,1150,558,292,1107,574,814,1474,1474,1068,1186,2,2,2,2,2,2,2,2,2,2,2,2,2,2,859,2,2}, + {1040,420,960,882,64,661,292,146,976,427,689,248,248,248,638,2,2,2,2,2,2,2,2,2,2,2,2,861,861,861,2,861}, + {1040,522,666,398,78,208,293,818,134,867,147,147,482,2,4,629,629,629,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {987,1280,1245,1300,926,676,56,546,541,690,84,42,1000,1383,1383,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1324,588,1378,592,1445,1029,759,1296,739,931,363,704,312,704,704,704,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1058,454,1557,191,129,297,695,1390,1274,460,923,923,923,2,4,1059,2,2,2,2,2,2,2,2,2,2,2,2,2,1059,2,2}, + {1327,572,282,1022,907,1276,409,643,1050,633,187,187,187,2,228,45,2,2,2,2,2,2,320,2,2,2,2,2,2,2,2,2}, + {1395,958,237,101,559,891,560,47,524,747,197,589,589,917,887,887,887,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1395,529,461,402,194,392,122,781,111,162,780,593,593,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1378,541,848,848,347,856,102,104,183,156,395,130,1377,2,2,2,159,159,159,2,2,2,772,2,2,2,2,2,2,2,2,2}, + {1062,212,784,63,252,873,1302,1108,1380,84,1375,1375,1375,2,2,2,375,374,2,980,2,2,2,980,980,980,2,2,2,2,2,2}, + {1384,549,430,781,946,879,901,924,741,114,14,451,36,2,2,2,2,287,287,287,803,803,803,803,2,2,2,803,803,803,803,803}, + {1413,627,1329,1092,526,197,31,417,1149,981,964,1003,685,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,717,717,2,2}, + {1084,1174,1601,949,910,960,500,461,1290,23,1042,636,212,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1420,531,626,738,376,537,814,206,990,235,847,812,201,201,201,201,726,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1420,624,363,537,1436,278,292,377,263,820,376,382,382,2,654,655,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1091,793,1353,208,506,599,846,503,1011,247,289,61,1050,61,61,61,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1533,978,284,156,914,162,685,1184,252,1375,189,256,640,2,640,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1531,692,414,277,541,1371,1447,682,536,109,432,1240,1240,2,1022,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1128,398,791,1170,76,661,408,259,756,495,79,553,10,10,1532,1532,1532,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1040,704,618,854,374,1470,274,383,941,519,351,351,351,351,351,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1427,988,498,1529,99,678,1323,149,33,426,543,543,335,1507,772,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1102,349,490,266,144,220,599,437,743,764,647,1128,605,265,324,324,324,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1118,496,645,592,354,1133,935,428,72,532,182,182,1370,660,123,2,294,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1102,1042,315,745,1006,771,630,68,587,1187,295,295,295,408,408,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1118,724,1322,405,199,614,1087,885,1313,317,769,660,660,1158,535,2,2,2,373,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1120,772,743,488,346,126,784,584,943,153,311,133,133,969,605,605,2,2,2,2,2,2,2,605,2,2,2,2,2,2,2,2}, + {1404,284,176,590,1128,1371,322,543,1136,546,1315,174,174,777,777,891,2,2,2,2,2,2,2,579,579,579,579,2,2,2,2,2}, + {1441,791,233,141,141,316,89,296,462,1263,758,482,599,599,578,341,2,2,2,2,2,2,2,2,2,2,2,525,525,525,2,2}, + {1413,406,700,547,1166,250,518,543,104,331,205,205,691,691,2,2,118,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1485,400,1497,168,82,680,1103,554,249,702,493,101,296,236,2,236,236,944,944,2,2,394,2,2,2,2,2,2,2,2,2,2}, + {1127,869,558,533,1215,194,1762,784,593,777,1153,1079,1079,1079,2,2,2,330,1045,2,1045,1045,2,2,2,2,2,2,2,2,2,787}, + {1459,1243,467,533,266,1364,1031,890,1402,486,1678,1678,93,978,2,2,2,978,947,947,2,978,2,2,2,2,2,2,2,2,2,2}, + {1139,809,117,522,955,1096,1120,1470,116,184,1565,1565,557,557,2,2,2,2,2,829,1326,2,2,2,2,2,2,2,2,2,2,2}, + {1142,984,1044,590,340,241,662,357,366,1305,2,125,631,474,2,2,2,980,2,2,2,2,2,2,2,2,2,2,2,2,2,1273}, + {1469,1247,1277,616,209,486,106,552,219,217,471,272,272,1201,2,2,503,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1148,542,1478,496,950,464,1011,235,136,180,2,416,758,453,2,909,2,2,2,2,2,2,2,2,2,2,1019,1019,2,2,2,2}, + {1495,1178,874,415,1100,368,1057,1228,562,215,31,31,680,680,680,1208,2,2,2,2,2,2,2,2,1208,2,2,2,2,1208,1208,2}, + {1497,1166,1613,1403,107,803,993,539,1436,1289,2,240,334,634,532,1147,2,2,2,2,2,2,2,117,2,2,2,2,2,2,2,117}, + {1617,289,1033,169,355,260,30,45,721,906,88,44,44,418,417,218,2,2,846,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1628,721,400,239,728,1336,984,425,65,120,1232,463,463,640,349,616,616,2,2,2,2,2,2,2,2,147,147,2,2,2,2,2}, + {1628,286,541,530,1610,201,1220,1592,272,181,2,38,263,1586,1157,1157,1157,2,2,2,1157,1157,2,2,2,1157,2,2,2,2,1157,1157}, + {1531,621,210,755,482,82,1308,317,427,168,2,232,116,190,701,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,701}, + {1532,575,1245,360,249,630,133,1406,920,1539,63,63,76,82,82,2,2,2,770,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1102,785,118,93,1491,988,275,53,1328,26,2,2,240,647,240,761,761,761,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1478,722,113,1534,1751,115,1728,1234,777,282,508,508,1184,63,1184,855,855,2,2,2,738,738,578,578,2,2,2,2,2,2,2,2}, + {1480,536,1421,164,429,84,970,1673,548,497,2,2,530,156,156,128,245,2,2,2,2,260,2,2,2,2,2,2,2,2,2,2}, + {1533,1302,1286,538,619,526,1669,145,1034,125,2,1038,1038,388,388,387,729,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1482,961,1093,556,1746,628,427,689,510,751,684,37,37,1229,1256,882,1507,1507,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1472,852,533,433,924,57,53,1036,410,675,1212,1212,1212,600,600,1212,1259,1245,1245,1245,1245,2,2,2,2,2,2,2,2,2,2,2}, + {1228,425,1030,699,407,171,568,925,1104,97,2,2,1286,1286,1286,502,2,1219,1219,1219,1290,2,1219,1219,1219,1219,2,2,2,59,2,2}, + {1547,657,777,695,1254,224,933,367,212,385,2,2,2,1422,749,245,885,710,2,2,710,710,710,45,710,710,710,710,2,336,710,2}, + {1678,466,549,145,351,816,1041,334,192,192,2,2,348,1017,130,4,4,180,180,180,180,512,2,2,2,512,512,512,512,512,128,8}, + {1550,569,481,1041,1680,1114,1265,160,386,194,2,2,2,533,929,531,422,531,1355,1355,1355,1355,531,216,216,2,2,2,2,2,2,2}, + {1559,462,850,289,1570,71,512,858,810,835,2,2,2,2,1028,1205,1205,546,546,546,1205,1205,1205,1205,1205,2,1205,1205,1205,1205,1205,1205}, + {1192,888,701,164,131,613,282,237,525,366,2,2,2,2,1737,845,845,750,2,1062,1062,1062,1062,1062,1062,1062,1062,1062,1062,2,1261,1261}, + {1208,426,412,1072,274,248,1544,627,9,458,2,2,2,2,2,2,270,270,270,150,715,282,150,150,150,150,150,150,150,150,150,150}, + {1128,393,1522,96,160,581,540,120,441,176,2,2,2,2,2,2,1427,551,1102,1102,328,328,592,592,592,592,592,592,592,592,592,592}, + {1202,538,171,1177,1090,690,1566,746,1012,1012,2,2,2,2,313,781,808,313,1125,1117,930,1117,1117,1117,1117,1117,1117,1117,1117,2,2,2}, + {1567,1265,372,1633,613,484,243,1523,21,275,2,2,2,431,431,431,431,2,2,978,489,889,889,889,889,889,889,889,2,2,2,2}, + {1566,982,815,133,891,412,1179,831,651,268,2,2,2,367,366,367,367,63,63,767,2,2,2,2,2,2,2,2,2,2,2,2}, + {1522,1422,1017,124,499,451,731,1112,1355,1355,2,2,2,854,854,336,854,336,1297,2,2,2,193,193,193,193,193,2,2,2,2,2}, + {1160,1331,917,1696,401,547,122,592,863,863,2,2,703,703,703,703,495,495,495,2,2,495,495,495,495,495,269,2,2,2,269,269}, + {1538,814,1027,677,524,226,756,202,242,102,2,2,912,564,1289,682,2,1125,1125,1125,1125,2,1289,1289,1289,1125,1125,1125,2,1289,1289,1289}, + {1598,397,1471,1471,1162,866,236,948,1557,737,2,2,153,737,1408,765,765,608,2,2,2,171,608,608,608,608,2,608,608,2,2,2}, + {1598,434,107,270,148,1317,835,123,642,1236,2,2,67,633,771,878,771,878,878,2,2,2,771,2,2,2,2,2,2,2,2,2}, + {1628,1502,1042,822,80,403,1335,684,464,426,671,671,336,336,336,2,425,896,2,2,2,2,1337,1337,1337,1337,1337,1337,2,2,2,2}, + {1630,715,1368,1273,993,293,385,545,1267,896,1038,1038,270,1325,1325,2,2,961,961,961,961,961,961,2,2,961,961,2,2,961,2,961}, + {1612,723,409,641,796,1087,1228,1398,623,262,740,740,870,870,397,2,2,893,893,2,2,1367,328,2,328,2,2,2,2,2,2,2}, + {1614,588,652,105,441,844,734,912,532,878,1073,1073,62,1415,693,1431,1431,1431,1431,925,925,925,925,925,925,925,2,2,2,2,2,2}, + {1607,1503,1072,471,221,277,854,1236,263,752,2,694,1657,934,553,2,2,2,498,498,2,802,2,46,2,2,2,2,2,2,2,2}, + {1172,987,140,1964,584,600,852,1725,456,1199,718,718,791,981,791,2,2,2,2,2,1260,2,2,2,2,2,718,2,2,718,2,718}, + {1746,771,620,415,1057,437,613,1034,1662,837,2,1149,1466,1149,1149,1149,1466,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1263,835,1533,789,1259,174,1497,557,644,203,2,289,604,434,434,434,2,844,844,2,2,2,1111,1111,1111,2,2,2,2,2,2,2}, + {1272,884,388,1889,956,159,1172,595,219,645,2,629,107,107,1279,75,2,2,2,211,2,2,2,2,2,2,2,2,2,2,2,2}, + {1797,904,172,659,349,177,692,448,1141,990,640,99,1073,806,640,640,2,640,640,911,911,911,640,640,640,640,2,2,2,2,2,2}, + {1276,442,1008,1352,243,162,711,301,552,1002,668,668,384,71,384,384,2,2,2,2,2,727,727,727,777,777,777,777,777,777,2,777}, + {1600,1130,171,1113,813,722,117,990,37,24,969,94,825,1398,1398,1398,1398,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1198,496,714,609,644,1159,873,249,186,1539,136,239,379,1994,2,68,68,68,68,68,2,2,192,2,969,2,2,969,2,2,969,969}, + {1678,1316,460,1133,1003,150,1236,1316,1417,218,1763,1763,77,77,2,1491,771,771,771,771,771,2,771,2,2,2,2,2,2,2,2,2}, + {1682,449,1067,393,136,854,36,492,637,1053,247,1111,1111,1111,2,247,247,247,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1288,1690,702,760,420,333,1213,1911,805,351,67,67,1568,1568,2,2,604,142,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1288,1858,152,894,346,104,997,203,249,1006,1278,1489,1489,555,2,2,2,1074,1074,518,2,2,518,2,2,518,2,2,2,2,2,2}, + {1601,697,532,408,697,1140,1568,47,1499,780,1171,318,318,318,2,2,2,2,318,318,2,2,2,2,2,2,2,2,2,2,2,2}, + {1283,1078,791,873,655,412,389,835,292,958,1245,678,1611,1519,2,2,185,2,2,2,2,2,2,1245,1245,2,2,2,2,2,2,1245}, + {1685,1610,1447,1093,1255,937,703,431,522,1384,988,988,253,988,2,1892,1892,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1822,589,236,205,797,39,241,1048,181,386,102,102,102,111,1361,1361,1361,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1233,843,813,157,396,669,1531,439,640,733,996,996,996,1566,951,608,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1342,705,302,595,1200,52,83,647,519,139,103,103,103,513,2,513,2,2,2,2,2,513,2,2,2,2,2,2,2,2,2,2}, + {1630,1244,142,767,1299,719,629,1716,419,837,1145,1136,1148,1405,1405,1405,2,2,2,2,2,309,309,309,309,309,2,2,2,2,2,2}, + {1636,974,279,419,893,1608,1491,156,1486,115,730,730,863,509,924,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1318,1234,213,1089,1567,602,1330,404,467,718,249,215,354,177,59,332,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1732,1771,584,533,297,1056,669,293,146,311,1176,311,590,590,277,2,2,2,2,2,2,2,2,2,539,539,2,2,2,2,2,2}, + {1026,512,1196,394,1259,1313,762,549,311,1576,1576,465,465,140,465,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1360,383,1470,502,1010,153,1588,619,1246,396,1107,1107,112,423,423,2,2,2,2,2,202,2,2,2,2,2,2,2,2,2,2,2}, + {1320,1636,858,1210,509,194,1575,154,1424,455,1860,832,1075,581,262,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1670,1350,689,1074,437,956,587,642,1154,439,196,1108,1108,1108,990,2,2,2,2,2,1112,2,2,2,2,2,2,2,2,2,2,2}, + {1873,890,920,874,591,651,768,478,331,76,760,760,760,760,67,2,2,2,2,1241,1241,1241,1241,2,2,2,2,2,2,2,1241,1241}, + {1682,867,333,102,628,891,654,506,995,684,961,563,1313,1313,1313,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1672,1248,429,813,262,92,809,1248,560,1365,1392,753,753,1259,1261,2,2,2,2,2,2,2,2,177,177,2,2,2,2,2,2,2}, + {1391,1598,1112,590,797,584,1354,47,1473,1291,1874,48,491,463,990,463,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1875,1576,924,677,461,134,1525,1619,44,701,299,743,728,791,791,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,791,791}, + {1267,904,1187,1595,765,1451,494,1573,950,909,87,1265,757,1371,1005,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1360,1091,1478,1237,97,578,1616,494,1422,223,865,1092,359,2,1080,4,2,2,2,688,1965,2,1965,2,2,2,2,2,2,2,2,2}, + {1750,386,393,840,723,791,1707,1319,1525,83,1302,571,280,2,280,73,2,2,2,1207,2,2,2,2,2,2,2,2,2,2,2,2}, + {1763,1018,1859,432,717,723,874,1294,1050,1800,1237,619,1074,2,10,1237,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1376,652,461,225,361,936,1073,1279,149,619,983,511,1994,2,2,1076,1076,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1947,393,495,946,1375,391,2128,582,1143,695,1872,760,760,2,2,1456,974,974,435,974,974,435,974,2,974,974,2,2,2,2,2,2}, + {1768,1463,531,1008,95,1677,362,1105,985,177,1682,1682,244,2,2,1234,1041,1041,1041,2,2,2,1041,1041,2,2,2,2,2,2,1894,2}, + {1780,1739,1357,1684,1586,736,208,966,1691,339,339,128,128,2,2,128,128,128,2,2,128,2,2,2,2,1929,2,2,338,2,2,338}, + {1387,1459,358,1409,1919,917,777,223,313,1847,1012,1024,1024,2,2,2,2,1420,1420,1428,1420,2,1420,1420,2,2,2,1420,1117,1117,1117,1117}, + {1289,907,228,665,1695,1735,489,214,762,1777,321,1674,932,2,2,2,2,1358,709,2,1959,1959,372,2,2,372,372,2,2,372,372,372}, + {1378,680,1117,1367,759,62,319,563,505,1138,1093,345,693,2,2,2,780,780,2,2,2,729,729,729,2,2,2,2,2,2,729,729}, + {1802,1645,453,1079,604,618,334,855,541,167,37,88,849,2,2,518,518,2,2,530,2,2,2,2,2,2,2,119,119,2,2,2}, + {1275,1612,143,1586,502,987,555,436,2236,1826,494,494,358,2,2,213,2,2,2,2,2,2,1585,1585,1585,1585,1585,1585,1585,1585,1585,1585}, + {1322,512,560,432,365,87,1835,1137,515,1271,1739,309,309,1229,1229,1229,2,2,2,2,2,2,2,2,416,416,416,416,2,2,2,2}, + {1758,835,287,888,391,875,1834,516,1432,1171,98,408,302,976,976,1963,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1444,394,1613,796,645,1406,186,158,402,1364,314,588,606,2,577,117,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1337,1391,137,371,165,87,1026,20,419,99,572,572,918,854,918,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1323,589,526,1555,1636,1172,86,42,1545,57,627,1769,1769,2,867,343,2,2,2,2,2,2,2,724,2,2,2,2,724,724,2,2}, + {1323,1647,384,301,270,549,1098,1144,1066,55,88,1805,683,2,945,120,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1327,1075,539,1017,926,350,1102,236,494,1268,286,286,1293,267,227,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1472,661,1538,487,94,2209,563,138,881,1735,718,203,1382,1473,1473,1473,1473,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1413,766,349,1471,45,625,733,1082,170,58,1268,207,1081,1081,1081,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1861,1487,419,97,799,1791,458,1029,370,627,57,414,414,1540,247,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1881,716,268,387,2138,1212,999,408,1363,434,1429,1429,1648,1648,1007,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1480,1131,1089,1688,340,962,505,1816,139,44,1350,403,1385,1996,173,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1868,650,1146,1690,948,43,497,692,1628,1302,1302,108,462,731,731,2,2,2,2,2,2,2,185,185,185,2,2,2,2,2,2,2}, + {2023,1204,531,733,1054,618,668,363,783,218,1302,2055,559,2055,2055,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1328,601,601,617,554,467,391,1545,162,1361,807,1565,1565,243,1344,2,725,510,510,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1808,1525,1129,652,1195,329,1410,558,1322,911,161,536,737,94,306,2,2,2,2,2,2,2,2,2,541,541,541,2,2,2,2,2}, + {1911,1338,639,1106,854,128,19,1353,847,253,618,517,2054,2054,93,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1825,850,180,1483,864,953,50,81,106,432,1372,1372,1212,10,10,10,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1892,441,977,228,1252,604,735,136,889,878,1319,1319,2127,2127,1963,367,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1820,1553,536,1351,425,1268,227,1742,429,348,1397,552,1151,1151,2,180,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1453,1044,556,833,305,1493,989,1158,726,1790,532,1229,1229,1229,2,2,2,2,2,2,2,2,2,2,259,2,2,2,2,2,420,2}, + {2059,592,492,973,137,1331,392,334,635,1480,2254,1796,1796,284,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1460,986,709,268,755,824,83,893,115,656,2071,1323,1001,144,2,2,2,2,2,2,2,2,1527,1527,1527,1527,1527,1527,1527,2,801,801}, + {1850,1476,792,840,2037,229,1578,526,431,1485,1450,1001,1001,1001,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1922,1383,813,346,1247,666,1931,1111,2042,79,682,501,1349,1930,2,2,681,681,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1922,542,1739,625,88,1376,259,49,338,318,505,788,1314,657,2,2,2,1314,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1948,1530,576,582,1069,119,2131,41,1178,1677,1677,1677,325,346,2,2,2,2,2,2,1401,2,33,2,2,2,2,2,2,71,71,71}, + {1928,1111,168,1252,1467,1083,1927,603,1278,714,1027,50,751,1970,2,2,2,2,621,2,100,2,2,10,10,2,2,2,2,793,793,793}, + {1394,896,674,2350,1375,1599,1858,135,762,722,628,685,705,28,2,2,2,2,2,2,2,2,2,2,2,855,2,2,2,2,2,2}, + {1540,791,518,419,1130,1068,299,1386,1378,134,859,859,71,162,2,71,71,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2107,709,828,154,542,184,1094,1665,307,1549,177,2007,85,773,2,2,2,2,2,2,2,2,2,2,2,697,2,2,2,2,697,2}, + {1977,1218,244,365,576,666,761,238,629,913,1907,986,1351,986,704,1257,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1496,1912,1291,1053,510,2322,1048,1530,2223,673,894,594,628,332,2,2,2,2,2,295,295,295,2,2,2,2,2,2,2,2,2,2}, + {1520,1107,1082,687,484,1732,676,1595,467,653,1091,428,2113,332,332,332,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1905,612,920,848,562,2032,230,1305,1073,851,731,798,798,357,516,2,2,2,2,2,2,2,2,1465,1465,373,2,2,2,2,2,2}, + {1428,1062,1016,75,297,1130,533,768,464,753,48,1510,1510,418,375,1626,2,221,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1396,729,1710,337,371,489,1341,2117,132,1870,853,853,408,1079,328,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1978,1051,977,588,1423,1001,508,409,825,497,659,1063,384,463,463,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1534,854,2007,1207,947,1773,1571,1505,909,1471,1655,1655,2334,1327,409,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2157,2106,679,238,378,49,1101,588,811,1313,1556,2301,475,812,812,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2187,1515,549,1416,1073,1613,47,1046,390,252,1214,1404,1404,933,1013,2,2,2,1025,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2145,1069,662,709,737,1141,1737,827,1384,1628,107,107,1032,277,277,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2173,1379,155,393,1578,610,1911,899,697,58,185,597,597,1249,1369,2,2,2,2,1369,2,2,2,2,2,2,2,2,2,2,2,2}, + {1413,1589,1603,2268,520,333,1416,859,1619,867,1154,512,1291,413,413,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1600,1823,1698,1268,623,583,1932,1674,522,529,1862,1281,246,989,246,2,246,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1559,992,174,1313,612,1487,1487,461,702,37,1660,839,2,95,1628,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2066,1719,710,1294,2041,377,1005,690,132,756,1618,187,187,726,187,615,615,2,2,2,2,851,2,2,2,2,2,2,2,2,2,744}, + {2192,1029,310,1609,592,1542,265,117,2006,82,162,205,2,2009,2009,1201,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1570,1504,1414,1143,1999,1932,1015,1015,556,514,626,79,2,79,1795,1461,1461,2,2,2,2,2,2,2,1461,1461,1461,1461,1461,2,2,2}, + {1562,937,1964,934,1349,378,459,109,1676,1655,1339,1809,2,768,768,188,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1965,949,1057,1043,2256,1571,970,348,69,1324,1174,485,105,105,105,2172,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2044,1869,838,1424,1097,155,1142,230,1335,420,235,1510,2,431,425,622,2,2,2,2,2,625,2,2,2,625,625,2,2,2,2,2}, + {1976,1433,820,504,421,1007,388,1083,635,82,1524,750,2,2,870,106,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1990,1948,1138,1787,253,115,312,1912,341,1624,260,1783,1315,1315,790,790,790,790,790,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1993,585,327,1393,1013,1671,1758,1436,1989,1217,1109,1476,2,2,1042,756,1042,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2056,1062,1605,1943,680,445,113,857,650,1388,2016,1231,2,2,1292,1292,1292,2,1039,1039,1039,1039,1039,2,2,2,2,2,2,2,2,2}, + {2008,1773,416,1954,1314,742,1694,505,202,1747,785,375,2,2,2,477,1538,477,2,2,2,2,2,1309,1309,1309,1309,2,2,2,1309,2}, + {1658,1008,258,749,427,1071,2052,263,1047,2152,1602,1602,2,2,2,1311,669,669,2,1897,1897,1897,669,669,669,669,669,669,669,669,669,669}, + {2258,1887,1875,1021,863,604,543,1115,509,1243,312,213,2,2,2,2,335,770,770,2,1143,567,2,2,567,567,567,411,2,2,2,411}, + {2266,1872,991,1468,1168,939,907,833,624,701,386,1713,2,2,2,2,2,931,861,381,1299,2,861,2,2,2,861,861,861,861,861,2}, + {2273,1510,803,2278,842,1245,1389,230,822,1564,113,1276,2,2,2,2,1350,273,273,2,2,2,2,2,1281,1281,1281,2,2,1281,1281,1281}, + {2278,1028,548,373,190,1443,614,2386,1940,930,557,2069,2,2,2,558,112,103,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2108,776,1568,342,2215,1882,681,1292,1601,586,1481,618,1930,1930,1930,1930,2146,89,89,2,2,2,2,2,2,2,1171,2,2,2,2,2}, + {2139,2177,1652,392,715,605,778,632,472,1619,64,64,2,2,2,1747,859,2,2,2,2,2,216,216,216,216,1747,1747,1747,1747,1747,1747}, + {1492,448,271,135,1288,417,130,83,235,2313,482,746,2,2,746,609,611,611,611,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1628,846,1504,138,464,401,501,506,967,1027,1540,1035,2,1921,1539,1539,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1630,1677,1624,301,1038,909,887,374,411,143,1021,174,2,1393,19,634,2,2,2,2,2,2,2,873,2,2,873,873,2,2,2,2}, + {1654,1131,2054,994,2170,548,801,252,87,219,488,2239,2,1232,1839,1822,2,2,2,968,2,2,2,2,2,2,2,2,2,2,2,2}, + {2065,1520,1423,1797,899,1425,1801,776,2365,58,646,695,2,998,998,1342,2,2,2,2,2,2,2,2,2,2,2,2,1150,1150,2,2}, + {2304,1948,316,1063,237,607,1143,2575,1388,1022,127,251,2,438,1570,1570,1570,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2177,710,1912,617,809,1078,199,905,673,519,457,52,2,1348,1348,410,2,2,2,2,2,340,2,2,2,2,2,2,2,2,2,2}, + {2073,1543,1586,1296,2466,753,455,46,119,1694,2035,1592,206,206,206,2,2,2,2,2,2,2,2,1172,2,2,2,2,2,2,2,2}, + {2075,1056,874,2101,566,1790,1333,386,538,1560,2254,331,717,717,717,454,454,2,2,2,2,2,2,2,2,2,2,2,454,454,2,2}, + {1670,977,1540,553,855,1729,239,757,191,62,732,549,1092,1092,199,199,199,199,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2096,1155,2257,125,1986,245,1208,2146,2287,680,1413,73,467,1410,1410,2,2,2,2,2,133,133,133,2,2,2,2,2,2,2,2,2}, + {1538,1026,2157,1457,1784,2559,184,29,614,273,697,697,1922,697,697,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2106,856,1025,382,389,272,425,672,1021,216,601,292,510,510,876,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1662,608,2478,266,1330,505,40,2058,964,724,596,1221,1221,310,42,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1600,1338,196,1510,1371,1138,957,169,545,1176,1131,2460,1708,541,541,2,363,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1682,1008,737,444,822,999,2066,283,646,1860,1008,778,1178,1178,458,1743,2,2,2,2,2,2,2,2,2,2,2,2,2,1743,1743,1743}, + {2132,756,1097,166,202,411,640,717,514,1389,633,633,633,633,633,633,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2386,748,620,478,647,898,320,53,1115,190,60,1860,1860,802,802,2,2,2,2,1264,1346,1346,2,2,2,2,2,2,2,2,2,2}, + {2125,996,1081,124,1140,628,1668,1913,151,2495,523,430,260,708,2190,2190,2190,2,2,2,2,2,1660,2,2,497,497,497,497,497,497,2}, + {1602,1489,895,383,56,698,2081,1728,794,789,16,16,797,302,52,2,2,2,2,2,2,2,2,2,2,797,797,797,797,797,797,1808}, + {2210,606,901,547,131,1924,1852,1271,194,766,390,390,520,795,1429,1429,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1731,599,817,724,718,1038,1082,2503,1341,936,421,1802,1304,1304,1491,186,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1614,1058,847,689,749,1028,1047,1474,117,1369,1442,1442,1540,700,104,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1733,679,2041,2420,326,934,1172,1431,193,370,1073,1073,1073,260,2,2,2,2,2,2,2,2,2,2,2,2,1193,2,2,2,2,2}, + {2168,1532,769,2570,1303,357,1793,1633,1226,1025,205,1218,1984,764,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2234,1706,356,581,532,933,1704,387,1345,1345,34,135,350,307,614,614,307,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1656,2093,354,310,306,1553,106,459,175,55,1482,958,254,254,2,356,356,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1654,1035,330,533,1446,953,499,142,1527,1748,265,1437,265,510,2,2,2,2,2,2,2,1835,1835,1835,1835,2,2,2,2,2,2,2}, + {1600,479,1457,246,2025,618,1612,2139,169,1492,1097,1327,2007,2007,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1744,447,845,2145,748,1555,1193,1312,916,1770,1294,546,794,323,2,2,2,2,2,1733,1733,2,2,1730,2,1733,1733,2,2,1733,551,551}, + {1766,1558,1901,1393,987,1859,815,1165,50,2065,88,88,1453,1453,2,2,2,995,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1615,1267,1242,1494,399,663,68,1209,1573,528,640,1200,248,640,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1678,592,1351,509,312,721,163,1597,1262,199,2643,1330,1661,992,2,2,719,2,2,2,2,2,2,2,2,2,2,2,2,2,1704,2}, + {2207,970,838,2043,1016,561,267,329,584,608,679,303,832,1613,959,959,959,1409,1409,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2217,352,447,914,1200,561,614,1616,509,2292,1114,1114,1229,52,1053,1053,1053,2,2,2,2,2,2,2,2,2,2,2,2,2,795,795}, + {2313,595,1593,1951,133,282,372,2396,1117,226,2104,267,374,267,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2312,1231,1604,997,652,1096,1070,320,481,662,911,1610,342,2527,606,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2245,1541,1828,783,615,428,1282,1892,848,1219,2465,314,314,314,2,2,2,2,2,2,2,2,2,2,2,2,1323,2,2,2,2,1323}, + {2522,1030,324,1264,628,1339,480,234,2351,1085,1979,2333,1339,1356,1356,2286,2,2,2,2,2,2,2,2,2,2,2,2,2530,2,2,2}, + {2519,1136,612,209,994,1179,1060,2621,130,485,661,1444,2122,124,258,1114,2,2,806,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2524,1894,253,2072,1242,355,888,1362,28,480,452,1216,595,545,354,1145,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2569,1356,1053,410,437,58,1508,831,2272,383,1725,615,1191,1191,1191,2493,186,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2386,1106,709,251,784,929,1551,2481,304,2148,1546,955,2453,866,866,2,2,2264,2264,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2228,1163,1995,649,1000,680,325,1591,774,767,711,711,1418,524,711,401,976,2,2,2,2,2005,2005,2,2,2,2,2,2,1390,1390,2}, + {2362,1706,564,1088,1296,1267,70,1015,496,1298,758,154,240,240,154,154,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1715,2260,357,557,783,1195,2288,1997,1120,144,247,175,1277,203,203,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2294,2360,1353,748,1439,226,940,2316,1112,1527,214,1406,1429,712,1124,2,595,595,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2303,1018,316,280,1616,909,97,1126,1295,736,216,54,2045,726,1673,2,2,2,2,2,779,779,2,2,2,2,2,2,2,2,2,2}, + {2390,491,1217,1148,2314,2250,2180,308,613,662,1346,1346,1346,1280,778,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1732,527,1303,664,71,294,404,917,1074,180,2618,2412,441,1987,1750,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1695,1287,1346,1181,1412,1653,830,2025,957,1720,1614,887,964,964,964,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1756,2308,1986,101,957,633,1940,1002,390,1237,95,1441,95,95,705,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2461,1412,540,1183,229,300,47,585,518,402,1863,1863,560,1326,1326,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1707,717,366,287,1883,50,599,1371,474,1551,947,2142,1885,947,2008,1004,1004,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2632,567,1149,1227,1156,2052,643,1585,1197,581,63,718,699,149,149,1940,2,2,2,2,2,2,2,2,2,2,2,2146,2,2,2,2}, + {1773,2024,377,340,1938,103,1180,600,199,848,2449,2449,506,506,762,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2435,1920,394,1482,266,1637,911,1697,1689,1249,1085,1085,397,2292,1355,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2345,662,270,324,1061,1080,1952,593,1480,2111,2667,2093,2059,2120,955,1447,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1777,455,1487,1190,455,1542,977,2308,437,1129,410,856,1420,412,412,766,2,2034,2034,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2662,2224,1142,656,59,598,730,458,226,1151,741,1286,1015,2,688,2017,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2666,768,529,990,2329,130,1678,2466,318,1083,387,1524,511,2,731,731,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2501,1216,246,1278,718,704,2019,88,273,1203,67,1488,1828,2,2,1489,1489,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2474,2292,1818,2061,2833,751,2172,1708,1210,1675,370,131,163,2,2,163,163,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1751,1575,889,828,82,1956,712,499,1420,1686,339,2326,2035,2,2,558,558,2,1234,2,2,2,2,2,2,2,2,2,2,2,1239,1239}, + {2522,1148,1943,168,218,252,543,1535,2004,130,353,353,42,2,2,2,1173,1173,2,1547,2,2,2,2,2,2,2,1547,1173,1547,1547,2}, + {2695,432,1213,579,865,1637,1857,84,447,155,2492,347,1980,2,2,2,1155,1155,1155,2,1933,1933,1933,2,2,2,2,2,2,2,1901,1901}, + {1808,1683,474,1761,106,602,1416,217,1351,1602,366,393,1966,2,2,2,2,2,378,378,606,606,606,2,2,2,2,2,919,919,919,919}, + {2428,1576,1692,449,2012,240,1167,418,272,1557,2197,645,645,2,2,2,2,2,2150,2150,2,2,562,715,2,2,2,81,81,2,2,2}, + {2727,781,1689,1709,997,2563,1032,468,44,992,1214,725,75,2,2,2,2,360,360,380,2,2,2,2,2,2,2,2,2,2,2,2}, + {1948,1085,1344,2090,1435,2389,3193,1007,1003,244,667,1838,2062,2,2,2,1802,299,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2433,932,689,818,2014,1498,749,1645,867,1627,47,1766,2193,2,2,2030,2030,2,430,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2463,712,1525,2092,2942,352,761,242,2178,2339,483,1905,1347,2,2,65,529,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2547,920,386,925,74,579,323,2319,520,2332,1535,751,1591,2,770,770,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2452,2588,2055,665,818,2622,413,1260,965,211,989,1219,166,2,1251,1251,2,1256,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1957,2311,993,276,293,2826,1087,880,927,1811,1122,2974,2974,2,2,590,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2552,998,533,827,1619,831,1861,918,750,1955,241,1899,448,2151,2151,449,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1860,579,1000,1575,898,170,185,1032,293,2754,438,459,459,2,1199,1199,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2602,2417,1888,2528,1410,669,1543,233,814,2478,225,1449,1449,224,1671,1671,2,2,931,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1889,2527,1366,1371,387,925,1751,162,250,1064,292,467,467,546,1244,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2492,1186,1350,1616,2749,1962,33,708,279,813,1390,489,1203,268,173,2410,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2500,1575,423,541,561,380,262,1564,1923,1242,2084,1758,1283,2213,924,924,2,2,2,2,2,2,2,2,2,2,2,1827,1827,2,2,2}, + {1842,1736,489,743,1539,1681,683,1412,1418,312,2778,2778,1975,1975,803,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2824,1183,2201,278,241,2230,1591,1648,1036,818,1321,1312,754,813,813,813,813,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1900,2506,952,1059,163,870,681,1235,1271,1188,2071,1705,1183,648,404,2,2,2,2,2,2,2,2,2236,2236,2,2,2,2,2,2,2}, + {2662,1443,2327,132,490,1149,1572,744,429,621,1763,2383,1903,1246,964,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2673,2182,1307,1776,1233,1828,1828,340,249,216,503,160,160,582,926,2129,2129,2129,2129,2129,2129,2129,2129,2129,2129,2129,2129,2,1018,1018,1103,1103}, + {2042,620,1074,2057,2758,859,815,1127,766,1693,252,808,981,416,416,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2102,881,2170,1673,705,101,58,1712,1568,214,758,488,1007,269,243,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2692,2665,961,1478,324,429,1311,376,1648,130,2083,1047,409,343,343,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2122,1087,563,1669,647,2996,151,2458,250,310,71,1348,355,965,2815,1333,1333,2,2,2,2,2218,2,2,2,2,2,2,2,2,2,2}, + {1952,1968,2260,2945,2464,1055,2626,570,1316,1828,1828,970,970,221,220,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2072,1947,1779,254,2822,1552,855,804,3452,202,695,82,684,208,1270,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1947,1699,1341,486,1765,1960,264,899,1082,1674,987,1878,930,1008,930,930,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1953,1527,1643,591,1517,2427,1232,1555,2542,495,675,2534,2534,3106,83,3106,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2744,1728,2213,792,761,1667,1908,31,447,442,815,2865,762,762,762,762,2,2,2,2,2,2,2,2,2,2,2,2,649,649,649,2}, + {2722,1406,1257,807,2191,3017,1330,1023,602,2124,794,530,733,733,1083,2528,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {1963,1525,437,398,609,393,2420,3059,435,1251,1977,1672,450,1960,1954,1960,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2626,2468,2838,845,2060,218,1080,912,911,1973,1365,920,1316,1316,2,1316,1316,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2734,1727,1743,1026,809,1154,779,244,1238,1616,812,784,825,1810,1810,1810,1810,1559,1559,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2180,2262,1651,204,3193,2121,2725,1016,629,1834,603,2848,26,26,728,728,728,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2648,1328,2578,133,1377,105,2485,2139,323,1045,145,761,1201,1848,2,814,814,814,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2999,358,250,1379,102,2349,1491,2074,42,376,2811,1220,296,296,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2810,1274,499,742,1724,425,190,1561,1302,2603,2255,917,661,661,2,2,2,495,2,2,2,2,2,2,2,2,2,2575,2,2,2,2}, + {2150,589,876,1616,2655,432,902,1028,433,1375,574,1400,1400,1400,2,2,2,2,2,1529,1529,1529,1529,1529,1529,1529,1529,1529,1529,1529,1529,1529}, + {1665,1856,201,824,796,249,1217,590,1375,1175,1599,824,824,3319,2,2,2,601,1961,1961,2,2,2,1961,2,2,2,2,2,2,1961,2}, + {2704,2239,1260,140,2161,2781,1840,574,2353,343,3218,61,2108,2038,1873,2,1833,1408,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2173,876,802,2197,3338,176,1783,224,1763,1160,1264,1264,2864,554,2,552,552,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2708,1663,2279,824,836,1598,2101,1620,1202,1606,1368,1079,1167,1999,2848,2848,2848,1101,1101,1101,2,2,2,662,2,2,2,2272,2,2,2,2}, + {1987,1463,2328,1890,1443,2086,283,2895,522,1577,1514,1657,2605,891,2,1181,1181,2,2,2121,2,2,2,2,2,2,2,2,2,2,2,2}, + {2173,1637,1139,905,1802,1378,296,439,1507,1017,1427,209,708,462,1508,1508,1508,2,2,2,2,2,2,2,2,2,2,2240,2240,1459,1459,1459}, + {2206,1526,628,2877,802,2587,1253,1258,1044,2195,3246,40,2898,2898,1704,598,2,2145,2,2,2,2145,2,2,2,2,2,2,2,2,2,2}, + {2182,618,1022,1433,1138,1580,2590,149,796,2090,743,294,294,1117,720,3003,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2025,1805,1466,1213,2006,1903,568,1700,1355,865,1783,1006,1006,1070,1070,268,2,2,2,2,2388,2388,845,845,845,2,2,2,2,2,2,2}, + {2185,1038,3050,1461,2270,2159,958,1637,233,2483,525,987,437,437,437,3065,2,2,2160,2160,2,2,2,2,2,2,2,2,2,2,2160,2160}, + {2083,1465,847,1450,502,447,2168,794,1761,1324,162,188,2853,2853,636,973,2,563,2,2,2,2,2,2,2,2089,2089,2089,2089,2089,2,2}, + {2923,2303,203,508,472,648,3169,269,515,3147,2415,1700,1700,1700,1461,1461,1461,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2300,1116,1555,2794,1095,998,1999,894,963,753,324,2130,2675,2675,554,2045,2,2,2,2,2,2,2,2130,2130,2130,2,2,2,2,2,2}, + {2103,768,702,1548,1486,2228,2846,861,665,1497,1046,1046,2252,394,394,1901,1155,2,2,2,2,2,2,2,2,2,2,2,192,192,192,192}, + {2923,640,661,2179,1207,182,872,171,738,269,1372,222,908,2069,2069,2,1550,516,2,2,2,2,2,2,2,2,2,2,1109,2,2,2}, + {2833,2005,387,733,562,468,317,224,94,478,1606,2522,1606,2001,1087,2,2,1087,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2125,2479,1749,1226,1169,1681,459,652,1087,2211,1613,686,2213,1689,2446,2,2,2925,2925,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2953,1059,205,3093,138,132,2148,1345,1499,216,151,1296,2446,1610,1632,2,2,2,2,4,4,2,2,2,987,987,2,2,2,2,2,2}, + {3199,1431,593,2050,2785,507,1540,1103,1740,459,62,1766,1781,1121,1600,2,1600,1600,125,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2258,1714,415,373,1919,2605,693,827,1918,496,1479,1903,86,1083,415,2,2,38,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {3289,2032,329,2169,2323,1599,517,1704,1847,804,632,40,40,40,40,40,40,40,40,2,2,1600,2,2,1600,2,2,2,2,2,2,2}, + {2165,2725,2293,368,705,3063,494,103,12,1332,175,2331,3144,2165,1709,1709,2090,2,2,2,2,1363,1363,2,566,2,2,2,2,2,2,2}, + {2300,1070,2169,2540,734,1002,912,1386,2215,224,1285,880,2052,2052,1301,959,563,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {3267,1852,1037,648,611,1250,432,853,1467,179,715,2,2033,841,2607,2607,2607,2607,2,2,2,2,1874,1874,2,1874,899,2,2,2,2,2}, + {2348,2565,794,859,1740,1596,532,462,457,1014,1227,2,2761,954,249,249,2,458,458,2,2,2,2,2,909,909,2,2,2,2,2,2}, + {3038,2399,1450,1276,1222,727,552,646,1055,2351,686,63,252,504,3166,1802,2,2,1165,1165,1165,2,2,2,2,1165,1165,1165,2,2,1165,2}, + {3038,2519,1494,107,2597,802,535,1669,1695,1928,1940,1580,1580,85,2274,1551,2,2,2431,560,560,560,2,2,1098,2,2,2,2,2,2,2}, + {3040,1044,1927,1952,1479,3124,1373,1990,588,2550,1277,2,629,2671,1842,2712,840,1702,2,1669,2,1347,2,2,2,2,1669,1669,1669,1669,2,1669}, + {3056,1567,691,1243,653,751,248,842,1954,480,458,2,2,2451,934,3172,3556,2259,2312,2,2562,2562,2,2,2562,2562,2562,2562,2562,2,2,2}, + {2959,2553,1333,877,2492,3169,2498,686,2030,2820,3233,1313,1313,1471,1471,1471,1471,2,2,1471,1471,2,2,1481,2,1887,2,2,2,2,2,2}, + {3398,964,862,301,1705,2002,310,644,144,1091,1507,2,2,2460,496,496,2517,2517,1842,2,2,1964,2,2,2,2,2,1676,2,2,2,2}, + {2379,3034,166,302,2108,1078,2976,68,158,134,1567,2,2,1514,1514,1514,1883,1883,2,2,1883,1883,1883,1883,1883,1883,1883,1883,1883,2,2,2}, + {2386,1270,1204,1032,1474,224,496,2296,1536,1219,311,2,2,2,2,1238,2108,2108,2108,2108,2108,2108,2108,2108,1444,1444,1444,1444,1444,1444,1444,2}, + {2431,739,2488,1386,1632,2107,2602,2139,1751,349,3147,2,2,64,16,8,32,4,4,32,728,728,728,728,2,2,64,16,8,180,180,180}, + {3405,2142,1621,110,2112,2097,807,740,747,282,372,2,2,2,2,2493,2493,2493,1299,2,132,1872,2,1843,2,2,2,2,2,2,2,2}, + {3157,1230,685,1513,663,1335,2100,1441,1826,1670,1539,2,2,2,2899,2899,1378,54,2,46,46,2,2,1362,1362,2,2,2,2,2,2,2}, + {2415,822,3658,449,1980,891,129,823,1787,621,514,2668,2668,2668,2668,2668,666,269,2830,2,2,2,2,241,370,370,370,370,2,2,2,2}, + {2463,2664,2825,1208,882,629,428,428,356,343,1730,2,769,769,769,1714,769,2,2,955,769,2,2,955,955,955,2,2,2,955,955,955}, + {2447,1588,1077,831,1413,2362,1499,1812,1112,815,129,1034,1034,1867,194,518,1454,723,723,1251,2,160,2,2,1251,1251,2,2,2,2,2,2}, + {3094,1638,1514,843,1503,1884,1481,727,723,1319,226,2,676,2401,1699,562,639,639,1176,2,2,2,2,824,2,2,2,2,2,2,2,2}, + {3125,2004,547,2986,2919,471,948,1747,201,1862,802,2,1238,1277,1277,1277,2,2,1245,1245,1245,2,2,2743,1245,1245,2,2,2,2,2,2}, + {2582,2469,533,1726,1575,1505,2448,2031,1257,427,588,1633,202,3553,1938,672,195,195,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2378,636,1958,1628,1255,2285,2208,1626,719,2944,1086,1436,1436,1719,2111,655,2637,2637,2,2,2,2637,2637,2,2637,2637,2637,2637,2637,2,2637,2637}, + {2372,3079,2161,515,368,847,955,1257,1937,315,2666,1938,1723,1252,1252,362,362,2,2205,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2518,2060,1055,362,1455,1899,1105,1560,2237,2451,2080,181,2346,181,1829,1829,1829,2,2,1509,1509,1509,2,1509,2,2,2,2,2,2,2,2}, + {3580,1671,674,1838,814,1409,323,3021,1047,2579,2579,2968,2968,102,2656,2638,2638,4006,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {3194,1576,1084,859,2879,1600,953,1429,471,867,1105,1490,293,293,293,2,2,198,2619,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {3215,2004,3333,2271,3283,1660,2135,1696,1413,1362,834,253,253,253,3802,2,2,2,1881,690,690,2,2,2,1881,1881,1881,1881,1881,2,1881,1881}, + {3719,2441,2094,1665,1707,1827,1310,230,1635,143,386,1029,1070,1062,1062,2,1062,1062,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {3249,1309,1232,472,711,2557,1479,1027,145,489,1377,2928,2928,3522,3522,3522,968,415,415,2,2,2,2,1332,1332,1332,2,1332,2891,2,1332,2891}, + {2462,1962,257,2244,1966,1905,204,262,799,319,752,1696,971,971,3781,1426,1426,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {3434,3131,1399,3413,1533,281,3288,1242,810,135,2506,2506,1742,946,1015,1044,1044,1044,2,2,2,2,1044,1837,1837,1837,1837,1837,2,2,2,2}, + {2518,1200,631,596,1946,365,2960,413,592,3878,242,2714,2364,1402,1402,2322,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {3362,2012,1759,2002,1365,150,3120,471,1590,3246,1296,196,196,196,2984,2323,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {3382,899,3140,2860,1155,1840,2822,355,1753,1856,1018,822,52,52,52,1102,1102,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2728,1334,274,1330,2674,2614,931,2250,883,1506,2193,1345,1089,500,2,219,390,2,2,2,2,2,2,2,390,2,2,2,2,2,2,2}, + {3911,3343,202,675,1733,71,166,176,1323,2864,899,2155,1108,2172,2,2,1829,2172,1107,2,2,2,2,1107,1107,1107,2,2,2,1107,2,2}, + {2757,3466,1411,1168,340,2760,1053,524,53,2090,1227,26,260,830,2,2,2,1139,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, + {2662,902,2371,1920,1097,1476,1008,1012,3556,468,3374,2560,591,1446,2,298,298,149,149,149,149,149,3135,3135,3135,3135,3135,2,2,2,2,2}, + {2861,1407,1848,245,2186,1209,164,2577,625,132,657,2333,2333,2213,2213,2213,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2} +}; diff --git a/src/divonne/Rule.c b/src/divonne/Rule.c new file mode 100644 index 0000000..f5d9337 --- /dev/null +++ b/src/divonne/Rule.c @@ -0,0 +1,685 @@ +/* + Rule.c + integration with cubature rules + code lifted with minor modifications from DCUHRE + by J. Berntsen, T. Espelid, and A. Genz + this file is part of Divonne + last modified 6 Nov 11 th +*/ + + +enum { nrules = 5 }; + +#define TYPEDEFSET \ + typedef struct { \ + count n; \ + real weight[nrules], scale[nrules], norm[nrules]; \ + real gen[NDIM]; \ + } Set + +/*********************************************************************/ + +static void Rule13Alloc(This *t) +{ + static creal w[][nrules] = { + { .00844923090033615, .3213775489050763, .3372900883288987, + -.8264123822525677, .6539094339575232 }, + { .023771474018994404, -.1767341636743844, -.1644903060344491, + .306583861409436, -.2041614154424632}, + { .02940016170142405, .07347600537466073, .07707849911634623, + .002389292538329435, -.174698151579499 }, + { .006644436465817374, -.03638022004364754, -.03804478358506311, + -.1343024157997222, .03937939671417803 }, + { .0042536044255016, .021252979220987123, .02223559940380806, + .08833366840533902, .006974520545933992 }, + { 0, .1460984204026913, .1480693879765931, + 0, 0 }, + { .0040664827465935255, .017476132861520992, 4.467143702185815e-6, + .0009786283074168292, .0066677021717782585 }, + { .03362231646315497, .1444954045641582, .150894476707413, + -.1319227889147519, .05512960621544304 }, + { .033200804136503725, .0001307687976001325, 3.6472001075162155e-5, + .00799001220015063, .05443846381278608 }, + { .014093686924979677, .0005380992313941161, .000577719899901388, + .0033917470797606257, .02310903863953934 }, + { .000977069770327625, .0001042259576889814, .0001041757313688177, + .0022949157182832643, .01506937747477189 }, + { .007531996943580376, -.001401152865045733, -.001452822267047819, + -.01358584986119197, -.060570216489018905 }, + { .02577183086722915, .008041788181514763, .008338339968783704, + .04025866859057809, .04225737654686337}, + { .015625, -.1420416552759383, -.147279632923196, + .003760268580063992, .02561989142123099 } + }; + + static creal g[] = { + .12585646717265545, .3506966822267133, + .4795480315809981, .4978005239276064, + .25, .07972723291487795, + .1904495567970094, .3291384627633596, + .43807365825146577, .499121592026599, + .4895111329084231, .32461421628226944, + .43637106005656195, .1791307322940614, + .2833333333333333, .1038888888888889 }; + + enum { nsets = 14, ndim = 2 }; + + TYPEDEFSET; + + count n, r; + Set *first, *last, *s, *x; + + Alloc(first, nsets); + Clear(first, nsets); + + last = first; + n = last->n = 1; + Copy(last->weight, w[0], nrules); + + ++last; + n += last->n = 2*ndim; + Copy(last->weight, w[1], nrules); + last->gen[0] = g[0]; + + ++last; + n += last->n = 2*ndim; + Copy(last->weight, w[2], nrules); + last->gen[0] = g[1]; + + ++last; + n += last->n = 2*ndim; + Copy(last->weight, w[3], nrules); + last->gen[0] = g[2]; + + ++last; + n += last->n = 2*ndim; + Copy(last->weight, w[4], nrules); + last->gen[0] = g[3]; + + ++last; + n += last->n = 2*ndim; + Copy(last->weight, w[5], nrules); + last->gen[0] = g[4]; + + ++last; + n += last->n = 2*ndim*(ndim - 1); + Copy(last->weight, w[6], nrules); + last->gen[0] = g[5]; + last->gen[1] = g[5]; + + ++last; + n += last->n = 2*ndim*(ndim - 1); + Copy(last->weight, w[7], nrules); + last->gen[0] = g[6]; + last->gen[1] = g[6]; + + ++last; + n += last->n = 2*ndim*(ndim - 1); + Copy(last->weight, w[8], nrules); + last->gen[0] = g[7]; + last->gen[1] = g[7]; + + ++last; + n += last->n = 2*ndim*(ndim - 1); + Copy(last->weight, w[9], nrules); + last->gen[0] = g[8]; + last->gen[1] = g[8]; + + ++last; + n += last->n = 2*ndim*(ndim - 1); + Copy(last->weight, w[10], nrules); + last->gen[0] = g[9]; + last->gen[1] = g[9]; + + ++last; + n += last->n = 4*ndim*(ndim - 1); + Copy(last->weight, w[11], nrules); + last->gen[0] = g[10]; + last->gen[1] = g[11]; + + ++last; + n += last->n = 4*ndim*(ndim - 1); + Copy(last->weight, w[12], nrules); + last->gen[0] = g[12]; + last->gen[1] = g[13]; + + ++last; + n += last->n = 4*ndim*(ndim - 1); + Copy(last->weight, w[13], nrules); + last->gen[0] = g[14]; + last->gen[1] = g[15]; + + t->rule13.first = first; + t->rule13.last = last; + t->rule13.errcoeff[0] = 10; + t->rule13.errcoeff[1] = 1; + t->rule13.errcoeff[2] = 5; + t->rule13.n = n; + + for( s = first; s <= last; ++s ) + for( r = 1; r < nrules - 1; ++r ) { + creal scale = (s->weight[r] == 0) ? 100 : + -s->weight[r + 1]/s->weight[r]; + real sum = 0; + for( x = first; x <= last; ++x ) + sum += x->n*fabs(x->weight[r + 1] + scale*x->weight[r]); + s->scale[r] = scale; + s->norm[r] = 1/sum; + } +} + +/*********************************************************************/ + +static void Rule11Alloc(This *t) +{ + static creal w[][nrules] = { + { .0009903847688882167, 1.715006248224684, 1.936014978949526, + .517082819560576, 2.05440450381852 }, + { .0084964717409851, -.3755893815889209, -.3673449403754268, + .01445269144914044, .013777599884901202 }, + { .00013587331735072814, .1488632145140549, .02929778657898176, + -.3601489663995932, -.576806291790441 }, + { .022982920777660364, -.2497046640620823, -.1151883520260315, + .3628307003418485, .03726835047700328 }, + { .004202649722286289, .1792501419135204, .05086658220872218, + .007148802650872729, .0068148789397772195 }, + { .0012671889041675774, .0034461267589738897, .04453911087786469, + -.09222852896022966, .057231697338518496 }, + { .0002109560854981544, -.005140483185555825, -.022878282571259, + .01719339732471725, -.044930187438112855 }, + { .016830857056410086, .006536017839876424, .02908926216345833, + -.102141653746035, .027292365738663484 }, + { .00021876823557504823, -.00065134549392297, -.002898884350669207, + -.007504397861080493, .000354747395055699 }, + { .009690420479796819, -.006304672433547204, -.028059634133074954, + .01648362537726711, .01571366799739551 }, + { .030773311284628138, .01266959399788263, .05638741361145884, + .05234610158469334, .049900992192785674 }, + { .0084974310856038, -.005454241018647931, -.02427469611942451, + .014454323316130661, .0137791555266677 }, + { .0017749535291258914, .004826995274768427, .021483070341828822, + .003019236275367777, .0028782064230998723 } + }; + + static creal g[] = { + .095, .25, + .375, .4, + .4975, .49936724991757, + .38968518428362114, .49998494965443835, + .3951318612385894, .22016983438253684, + .4774686911397297, .2189239229503431, + .4830546566815374, .2288552938881567 }; + + enum { nsets = 13, ndim = 3 }; + + TYPEDEFSET; + + count n, r; + Set *first, *last, *s, *x; + + Alloc(first, nsets); + Clear(first, nsets); + + last = first; + n = last->n = 1; + Copy(last->weight, w[0], nrules); + + ++last; + n += last->n = 2*ndim; + Copy(last->weight, w[1], nrules); + last->gen[0] = g[0]; + + ++last; + n += last->n = 2*ndim; + Copy(last->weight, w[2], nrules); + last->gen[0] = g[1]; + + ++last; + n += last->n = 2*ndim; + Copy(last->weight, w[3], nrules); + last->gen[0] = g[2]; + + ++last; + n += last->n = 2*ndim; + Copy(last->weight, w[4], nrules); + last->gen[0] = g[3]; + + ++last; + n += last->n = 2*ndim; + Copy(last->weight, w[5], nrules); + last->gen[0] = g[4]; + + ++last; + n += last->n = 2*ndim*(ndim - 1); + Copy(last->weight, w[6], nrules); + last->gen[0] = g[5]; + last->gen[1] = g[5]; + + ++last; + n += last->n = 2*ndim*(ndim - 1); + Copy(last->weight, w[7], nrules); + last->gen[0] = g[6]; + last->gen[1] = g[6]; + + ++last; + n += last->n = 4*ndim*(ndim - 1)*(ndim - 2)/3; + Copy(last->weight, w[8], nrules); + last->gen[0] = g[7]; + last->gen[1] = g[7]; + last->gen[2] = g[7]; + + ++last; + n += last->n = 4*ndim*(ndim - 1)*(ndim - 2)/3; + Copy(last->weight, w[9], nrules); + last->gen[0] = g[8]; + last->gen[1] = g[8]; + last->gen[2] = g[8]; + + ++last; + n += last->n = 4*ndim*(ndim - 1)*(ndim - 2)/3; + Copy(last->weight, w[10], nrules); + last->gen[0] = g[9]; + last->gen[1] = g[9]; + last->gen[2] = g[9]; + + ++last; + n += last->n = 4*ndim*(ndim - 1)*(ndim - 2); + Copy(last->weight, w[11], nrules); + last->gen[0] = g[10]; + last->gen[1] = g[11]; + last->gen[2] = g[11]; + + ++last; + n += last->n = 4*ndim*(ndim - 1)*(ndim - 2); + Copy(last->weight, w[12], nrules); + last->gen[0] = g[12]; + last->gen[1] = g[12]; + last->gen[2] = g[13]; + + t->rule11.first = first; + t->rule11.last = last; + t->rule11.errcoeff[0] = 4; + t->rule11.errcoeff[1] = .5; + t->rule11.errcoeff[2] = 3; + t->rule11.n = n; + + for( s = first; s <= last; ++s ) + for( r = 1; r < nrules - 1; ++r ) { + creal scale = (s->weight[r] == 0) ? 100 : + -s->weight[r + 1]/s->weight[r]; + real sum = 0; + for( x = first; x <= last; ++x ) + sum += x->n*fabs(x->weight[r + 1] + scale*x->weight[r]); + s->scale[r] = scale; + s->norm[r] = 1/sum; + } +} + +/*********************************************************************/ + +static void Rule9Alloc(This *t) +{ + static creal w[] = { + -.0023611709677855117884, .11415390023857325268, + -.63833920076702389094, .74849988504685208004, + -.0014324017033399125142, .057471507864489725949, + -.14225104571434243234, -.062875028738286979989, + .254591133248959089, -1.207328566678236261, + .89567365764160676508, -.36479356986049146661, + .0035417564516782676826, -.072609367395893679605, + .10557491625218991012, .0021486025550098687713, + -.032268563892953949998, .010636783990231217481, + .014689102496143490175, .51134708346467591431, + .45976448120806344646, .18239678493024573331, + -.04508628929435784076, .21415883524352793401, + -.027351546526545644722, .054941067048711234101, + .11937596202570775297, .65089519391920250593, + .14744939829434460168, .057693384490973483573, + .034999626602143583822, -1.3868627719278281436, + -.2386668732575008879, .015532417276607053264, + .0035328099607090870236, .09231719987444221619, + .02254314464717892038, .013675773263272822361, + -.32544759695960125297, .0017708782258391338413, + .0010743012775049343856, .25150011495314791996 }; + + static creal g[] = { + .47795365790226950619, .20302858736911986780, + .44762735462617812882, .125, + .34303789878087814570 }; + + enum { nsets = 9 }; + + TYPEDEFSET; + + ccount ndim = t->ndim; + ccount twondim = 1 << ndim; + count dim, n, r; + Set *first, *last, *s, *x; + + Alloc(first, nsets); + Clear(first, nsets); + + last = first; + n = last->n = 1; + last->weight[0] = ndim*(ndim*(ndim*w[0] + w[1]) + w[2]) + w[3]; + last->weight[1] = ndim*(ndim*(ndim*w[4] + w[5]) + w[6]) - w[7]; + last->weight[2] = ndim*w[8] - last->weight[1]; + last->weight[3] = ndim*(ndim*w[9] + w[10]) - 1 + last->weight[0]; + last->weight[4] = ndim*w[11] + 1 - last->weight[0]; + + ++last; + n += last->n = 2*ndim; + last->weight[0] = ndim*(ndim*w[12] + w[13]) + w[14]; + last->weight[1] = ndim*(ndim*w[15] + w[16]) + w[17]; + last->weight[2] = w[18] - last->weight[1]; + last->weight[3] = ndim*w[19] + w[20] + last->weight[0]; + last->weight[4] = w[21] - last->weight[0]; + last->gen[0] = g[0]; + + ++last; + n += last->n = 2*ndim; + last->weight[0] = ndim*w[22] + w[23]; + last->weight[1] = ndim*w[24] + w[25]; + last->weight[2] = w[26] - last->weight[1]; + last->weight[3] = ndim*w[27] + w[28]; + last->weight[4] = -last->weight[0]; + last->gen[0] = g[1]; + + ++last; + n += last->n = 2*ndim; + last->weight[0] = w[29]; + last->weight[1] = w[30]; + last->weight[2] = -w[29]; + last->weight[3] = w[31]; + last->weight[4] = -w[29]; + last->gen[0] = g[2]; + + ++last; + n += last->n = 2*ndim; + last->weight[2] = w[32]; + last->gen[0] = g[3]; + + ++last; + n += last->n = 2*ndim*(ndim - 1); + last->weight[0] = w[33] - ndim*w[12]; + last->weight[1] = w[34] - ndim*w[15]; + last->weight[2] = -last->weight[1]; + last->weight[3] = w[35] + last->weight[0]; + last->weight[4] = -last->weight[0]; + last->gen[0] = g[0]; + last->gen[1] = g[0]; + + ++last; + n += last->n = 4*ndim*(ndim - 1); + last->weight[0] = w[36]; + last->weight[1] = w[37]; + last->weight[2] = -w[37]; + last->weight[3] = w[38]; + last->weight[4] = -w[36]; + last->gen[0] = g[0]; + last->gen[1] = g[1]; + + ++last; + n += last->n = 4*ndim*(ndim - 1)*(ndim - 2)/3; + last->weight[0] = w[39]; + last->weight[1] = w[40]; + last->weight[2] = -w[40]; + last->weight[3] = w[39]; + last->weight[4] = -w[39]; + last->gen[0] = g[0]; + last->gen[1] = g[0]; + last->gen[2] = g[0]; + + ++last; + n += last->n = twondim; + last->weight[0] = w[41]/twondim; + last->weight[1] = w[7]/twondim; + last->weight[2] = -last->weight[1]; + last->weight[3] = last->weight[0]; + last->weight[4] = -last->weight[0]; + for( dim = 0; dim < ndim; ++dim ) + last->gen[dim] = g[4]; + + t->rule9.first = first; + t->rule9.last = last; + t->rule9.errcoeff[0] = 5; + t->rule9.errcoeff[1] = 1; + t->rule9.errcoeff[2] = 5; + t->rule9.n = n; + + for( s = first; s <= last; ++s ) + for( r = 1; r < nrules - 1; ++r ) { + creal scale = (s->weight[r] == 0) ? 100 : + -s->weight[r + 1]/s->weight[r]; + real sum = 0; + for( x = first; x <= last; ++x ) + sum += x->n*fabs(x->weight[r + 1] + scale*x->weight[r]); + s->scale[r] = scale; + s->norm[r] = 1/sum; + } +} + +/*********************************************************************/ + +static void Rule7Alloc(This *t) +{ + static creal w[] = { + .019417866674748388428, -.40385257701150182546, + .64485668767465982223, .01177982690775806141, + -.18041318740733609012, -.088785828081335044443, + .056328645808285941374, -.0097089333373741942142, + -.99129176779582358138, -.17757165616267008889, + .12359398032043233572, .074978148702033690681, + .55489147051423559776, .088041241522692771226, + .021118358455513385083, -.0099302203239653333087, + -.064100053285010904179, .030381729038221007659, + .0058899134538790307051, -.0048544666686870971071, + .35514331232534017777 }; + + static creal g[] = { + .47795365790226950619, .20302858736911986780, + .375, .34303789878087814570 }; + + enum { nsets = 6 }; + + TYPEDEFSET; + + ccount ndim = t->ndim; + ccount twondim = 1 << ndim; + count dim, n, r; + Set *first, *last, *s, *x; + + Alloc(first, nsets); + Clear(first, nsets); + + last = first; + n = last->n = 1; + last->weight[0] = ndim*(ndim*w[0] + w[1]) + w[2]; + last->weight[1] = ndim*(ndim*w[3] + w[4]) - w[5]; + last->weight[2] = ndim*w[6] - last->weight[1]; + last->weight[3] = ndim*(ndim*w[7] + w[8]) - w[9]; + last->weight[4] = 1 - last->weight[0]; + + ++last; + n += last->n = 2*ndim; + last->weight[0] = w[10]; + last->weight[1] = w[11]; + last->weight[2] = -w[10]; + last->weight[3] = w[12]; + last->weight[4] = -w[10]; + last->gen[0] = g[1]; + + ++last; + n += last->n = 2*ndim; + last->weight[0] = w[13] - ndim*w[0]; + last->weight[1] = w[14] - ndim*w[3]; + last->weight[2] = w[15] - last->weight[1]; + last->weight[3] = w[16] - ndim*w[7]; + last->weight[4] = -last->weight[0]; + last->gen[0] = g[0]; + + ++last; + n += last->n = 2*ndim; + last->weight[2] = w[17]; + last->gen[0] = g[2]; + + ++last; + n += last->n = 2*ndim*(ndim - 1); + last->weight[0] = -w[7]; + last->weight[1] = w[18]; + last->weight[2] = -w[18]; + last->weight[3] = w[19]; + last->weight[4] = w[7]; + last->gen[0] = g[0]; + last->gen[1] = g[0]; + + ++last; + n += last->n = twondim; + last->weight[0] = w[20]/twondim; + last->weight[1] = w[5]/twondim; + last->weight[2] = -last->weight[1]; + last->weight[3] = w[9]/twondim; + last->weight[4] = -last->weight[0]; + for( dim = 0; dim < ndim; ++dim ) + last->gen[dim] = g[3]; + + t->rule7.first = first; + t->rule7.last = last; + t->rule7.errcoeff[0] = 5; + t->rule7.errcoeff[1] = 1; + t->rule7.errcoeff[2] = 5; + t->rule7.n = n; + + for( s = first; s <= last; ++s ) + for( r = 1; r < nrules - 1; ++r ) { + creal scale = (s->weight[r] == 0) ? 100 : + -s->weight[r + 1]/s->weight[r]; + real sum = 0; + for( x = first; x <= last; ++x ) + sum += x->n*fabs(x->weight[r + 1] + scale*x->weight[r]); + s->scale[r] = scale; + s->norm[r] = 1/sum; + } +} + +/*********************************************************************/ + +static inline void RuleIni(Rule *rule) +{ + rule->first = NULL; +} + +/*********************************************************************/ + +static inline bool RuleIniQ(Rule *rule) +{ + return rule->first == NULL; +} + +/*********************************************************************/ + +static inline void RuleFree(Rule *rule) +{ + free(rule->first); +} + +/*********************************************************************/ + +static real *ExpandFS(cThis *t, cBounds *b, real *g, real *x) +{ + count dim, ndim = t->ndim; + +next: + /* Compute centrally symmetric sum for permutation of G */ + + for( dim = 0; dim < ndim; ++dim ) + *x++ = (.5 + g[dim])*b[dim].lower + (.5 - g[dim])*b[dim].upper; + + for( dim = 0; dim < ndim; ) { + g[dim] = -g[dim]; + if( g[dim++] < 0 ) goto next; + } + + /* Find next distinct permutation of G and loop back for next sum. + Permutations are generated in reverse lexicographic order. */ + + for( dim = 1; dim < ndim; ++dim ) { + creal gd = g[dim]; + if( g[dim - 1] > gd ) { + count i, j = dim, ix = dim, dx = dim - 1; + for( i = 0; i < --j; ++i ) { + creal tmp = g[i]; + g[i] = g[j]; + g[j] = tmp; + if( tmp <= gd ) --dx; + if( g[i] > gd ) ix = i; + } + if( g[dx] <= gd ) dx = ix; + g[dim] = g[dx]; + g[dx] = gd; + goto next; + } + } + + /* Restore original order to generators */ + + for( dim = 0; dim < --ndim; ++dim ) { + creal tmp = g[dim]; + g[dim] = g[ndim]; + g[ndim] = tmp; + } + + return x; +} + +/*********************************************************************/ + +static void SampleRule(This *t, ccount iregion) +{ + SAMPLERDEFS; + TYPEDEFSET; + Set *first = (Set *)samples->rule->first; + Set *last = (Set *)samples->rule->last; + Set *s; + creal *errcoeff = samples->rule->errcoeff; + count comp, rul, sn; + + for( s = first; s <= last; ++s ) + if( s->n ) x = ExpandFS(t, b, s->gen, x); + + DoSample(t, n, samples->x, f, t->ndim); + + for( comp = 0; comp < t->ncomp; ++comp ) { + real sum[nrules]; + creal *f1 = f++; + + Zap(sum); + for( s = first; s <= last; ++s ) + for( sn = s->n; sn; --sn ) { + creal fun = *f1; + f1 += t->ncomp; + for( rul = 0; rul < nrules; ++rul ) + sum[rul] += fun*s->weight[rul]; + } + + /* Search for the null rule, in the linear space spanned by two + successive null rules in our sequence, which gives the greatest + error estimate among all normalized (1-norm) null rules in this + space. */ + + for( rul = 1; rul < nrules - 1; ++rul ) { + real maxerr = 0; + for( s = first; s <= last; ++s ) + maxerr = Max(maxerr, + fabs(sum[rul + 1] + s->scale[rul]*sum[rul])*s->norm[rul]); + sum[rul] = maxerr; + } + + r[comp].avg = region->vol*sum[0]; + r[comp].err = region->vol*( + (errcoeff[0]*sum[1] <= sum[2] && errcoeff[0]*sum[2] <= sum[3]) ? + errcoeff[1]*sum[1] : + errcoeff[2]*Max(Max(sum[1], sum[2]), sum[3]) ); + } +} + diff --git a/src/divonne/Sample.c b/src/divonne/Sample.c new file mode 100644 index 0000000..2d0123a --- /dev/null +++ b/src/divonne/Sample.c @@ -0,0 +1,261 @@ +/* + Sample.c + most of what is related to sampling + this file is part of Divonne + last modified 7 Nov 11 th +*/ + + +#define MARKMASK 0xfffffff +#define Marked(x) ((x) & ~MARKMASK) +#define Unmark(x) ((x) & MARKMASK) + +#define EXTRAPOLATE_EPS (.25*t->border.lower) +/*#define EXTRAPOLATE_EPS 0x1p-26*/ + +/*********************************************************************/ + +static inline void SamplesIni(Samples *samples) +{ + samples->x = NULL; +} + +/*********************************************************************/ + +static inline bool SamplesIniQ(cSamples *samples) +{ + return samples->x == NULL; +} + +/*********************************************************************/ + +static inline void SamplesFree(cSamples *samples) +{ + free(samples->x); +} + +/*********************************************************************/ + +static void SampleSobol(This *t, ccount iregion) +{ + SAMPLERDEFS; + real avg[NCOMP], norm; + number i; + count dim, comp; + + for( i = 0; i < n; ++i ) { + t->rng.getrandom(t, x); + for( dim = 0; dim < t->ndim; ++x, ++dim ) + *x = b[dim].lower + *x*(b[dim].upper - b[dim].lower); + } + + DoSample(t, n, samples->x, f, t->ndim); + + ResCopy(avg, f); + f += t->ncomp; + for( i = 2; i < n; ++i ) + for( comp = 0; comp < t->ncomp; ++comp ) + avg[comp] += *f++; + + norm = region->vol/samples->neff; + for( comp = 0; comp < t->ncomp; ++comp ) { + r[comp].avg = norm*avg[comp]; + r[comp].err = 0; + } +} + +/*********************************************************************/ + +static void SampleKorobov(This *t, ccount iregion) +{ + SAMPLERDEFS; + real *xlast = x + t->ndim, *flast = f + t->ncomp; + real avg[NCOMP], norm; + cnumber neff = samples->neff; + number nextra = 0, i; + real dist = 0; + count dim, comp; + + for( i = 1; i < n; ++i ) { + number c = i; + for( dim = 0; dim < t->ndim; ++dim ) { + creal dx = abs(2*c - neff)/(real)neff; + *xlast++ = b[dim].lower + dx*(b[dim].upper - b[dim].lower); + c = c*samples->coeff % neff; + } + } + + for( dim = 0; dim < t->ndim; ++dim ) { + creal dx = (x[dim] = b[dim].upper) - t->border.upper; + if( dx > 0 ) dist += Sq(dx); + } + + if( dist > 0 ) { + dist = sqrt(dist)/EXTRAPOLATE_EPS; + for( dim = 0; dim < t->ndim; ++dim ) { + real x2 = x[dim], dx = x2 - t->border.upper; + if( dx > 0 ) { + x[dim] = t->border.upper; + x2 = t->border.upper - dx/dist; + } + xlast[dim] = x2; + } + nextra = 1; + } + + DoSample(t, n + nextra, x, f, t->ndim); + + ResCopy(avg, flast); + flast += t->ncomp; + for( i = 2; i < n; ++i ) + for( comp = 0; comp < t->ncomp; ++comp ) + avg[comp] += *flast++; + + if( nextra ) { + for( comp = 0; comp < t->ncomp; ++comp ) + f[comp] += dist*(f[comp] - flast[comp]); + for( dim = 0; dim < t->ndim; ++dim ) + x[dim] = b[dim].upper; + } + + norm = region->vol/samples->neff; + for( comp = 0; comp < t->ncomp; ++comp ) { + r[comp].avg = norm*(avg[comp] + avg[comp] + f[comp]); + r[comp].err = 0; + } +} + +/*********************************************************************/ + +#define IsSobol(k) NegQ(k) +#define IsRule(k, d) (k == 9 || k == 7 || (k == 11 && d == 3) || (k == 13 && d == 2)) + +/* The following coding is used for key1, key2, key3: + 0 = for key1, key2: use default, + for key3: do nothing, + 1 = for key3: split region again, + 7 = degree-7 cubature rule, + 9 = degree-9 cubature rule, + 11 = degree-11 cubature rule (only in 3 dims), + 13 = degree-13 cubature rule (only in 2 dims), + -inf..-40 = absolute # of points, Sobol numbers, + -39..-1 = multiplicator, Sobol numbers, + 1..39 = multiplicator, Korobov numbers, + 40..inf = absolute # of points, Korobov numbers. */ + +static count SamplesLookup(This *t, Samples *samples, cint key, + cnumber nwant, cnumber nmax, number nmin) +{ + number n; + + if( key == 13 && t->ndim == 2 ) { + if( RuleIniQ(&t->rule13) ) Rule13Alloc(t); + samples->rule = &t->rule13; + samples->n = n = nmin = t->rule13.n; + samples->sampler = SampleRule; + } + else if( key == 11 && t->ndim == 3 ) { + if( RuleIniQ(&t->rule11) ) Rule11Alloc(t); + samples->rule = &t->rule11; + samples->n = n = nmin = t->rule11.n; + samples->sampler = SampleRule; + } + else if( key == 9 ) { + if( RuleIniQ(&t->rule9) ) Rule9Alloc(t); + samples->rule = &t->rule9; + samples->n = n = nmin = t->rule9.n; + samples->sampler = SampleRule; + } + else if( key == 7 ) { + if( RuleIniQ(&t->rule7) ) Rule7Alloc(t); + samples->rule = &t->rule7; + samples->n = n = nmin = t->rule7.n; + samples->sampler = SampleRule; + } + else { + n = Abs1(key); + if( n < 40 ) n *= nwant; + samples->sampler = (key < 0) ? SampleSobol : + (n = n/2 + 1, SampleKorobov); + samples->n = IMin(n, nmax); + } + + samples->neff = samples->n; + + return IDim(n - nmax) | Marked(nmax - nmin); +} + +/*********************************************************************/ + +static void SamplesAlloc(cThis *t, Samples *samples) +{ +#define FIRST -INT_MAX +#define MarkLast(x) (x | Marked(INT_MAX)) + +#include "KorobovCoeff.c" + + number nx, nf; + + if( samples->sampler == SampleKorobov ) { + enum { max = Elements(prime) - 2 }; + cint n = IMin(2*samples->n - 1, MAXPRIME); + int i = Hash(n), p; + count shift = 2 + NegQ(n - 1000); + + while( i = IMin(IDim(i), max), + n > (p = prime[i + 1]) || n <= prime[i] ) { + cint d = (n - Unmark(p)) >> ++shift; + i += Min1(d); + } + + samples->coeff = coeff[i][t->ndim - KOROBOV_MINDIM]; + samples->neff = p = Unmark(p); + samples->n = p/2 + 1; + } + + nx = t->ndim*(samples->n + 1); /* need 1 for extrapolation */ + nf = t->ncomp*(samples->n + 1); + + Alloc(samples->x, nx + nf + t->ncomp + t->ncomp); + samples->f = samples->x + nx; +} + +/*********************************************************************/ + +static real Sample(This *t, creal *x0) +{ + real xtmp[2*NDIM], ftmp[2*NCOMP], *xlast = xtmp, f; + real dist = 0; + count dim, comp; + number n = 1; + + for( dim = 0; dim < t->ndim; ++dim ) { + creal x1 = *xlast++ = Min(Max(*x0++, 0.), 1.); + real dx; + if( (dx = x1 - t->border.lower) < 0 || + (dx = x1 - t->border.upper) > 0 ) dist += Sq(dx); + } + + if( dist > 0 ) { + dist = sqrt(dist)/EXTRAPOLATE_EPS; + for( dim = 0; dim < t->ndim; ++dim ) { + real x2 = xtmp[dim], dx, b; + if( (dx = x2 - (b = t->border.lower)) < 0 || + (dx = x2 - (b = t->border.upper)) > 0 ) { + xtmp[dim] = b; + x2 = b - dx/dist; + } + *xlast++ = x2; + } + n = 2; + } + + DoSample(t, n, xtmp, ftmp, t->ndim); + + comp = Untag(t->selectedcomp); + f = ftmp[comp]; + if( n > 1 ) f += dist*(f - ftmp[comp + t->ncomp]); + + return Sign(t->selectedcomp)*f; +} + diff --git a/src/divonne/Split.c b/src/divonne/Split.c new file mode 100644 index 0000000..e5883e6 --- /dev/null +++ b/src/divonne/Split.c @@ -0,0 +1,311 @@ +/* + Split.c + determine optimal cuts for splitting a region + this file is part of Divonne + last modified 15 Nov 11 th +*/ + + +#define BNDTOL .05 +#define FRACT .5 +#define BIG 1e10 +#define SINGTOL 1e-4 + +#define LHSTOL .1 +#define GAMMATOL .1 + +/* the next four macros must be in sync with the typedef of Bounds! */ +#define Lower(d) (2*d) +#define Upper(d) (2*d + 1) +#define Dim(i) ((i) >> 1) +#define SignedDelta(i) (2*(i & 1) - 1)*delta[i] + +typedef struct { + count i; + real save, delta; + real f, df, fold; + real lhs, row, sol; +} Cut; + +/*********************************************************************/ + +static inline real Div(creal a, creal b) +{ + return (b != 0 && fabs(b) < BIG*fabs(a)) ? a/b : a; +} + +/*********************************************************************/ + +static void SomeCut(This *t, Cut *cut, Bounds *b) +{ + count dim, maxdim; + static count nextdim = 0; + real xmid[NDIM], ymid, maxdev; + + for( dim = 0; dim < t->ndim; ++dim ) + xmid[dim] = .5*(b[dim].upper + b[dim].lower); + ymid = Sample(t, xmid); + + maxdev = 0; + maxdim = 0; + for( dim = 0; dim < t->ndim; ++dim ) { + real ylower, yupper, dev; + creal x = xmid[dim]; + xmid[dim] = b[dim].lower; + ylower = Sample(t, xmid); + xmid[dim] = b[dim].upper; + yupper = Sample(t, xmid); + xmid[dim] = x; + + dev = fabs(ymid - .5*(ylower + yupper)); + if( dev >= maxdev ) { + maxdev = dev; + maxdim = dim; + } + } + + if( maxdev > 0 ) nextdim = 0; + else maxdim = nextdim++ % t->ndim; + + cut->i = Upper(maxdim); + cut->save = b[maxdim].upper; + b[maxdim].upper = xmid[maxdim]; +} + +/*********************************************************************/ + +static inline real Volume(cThis *t, creal *delta) +{ + real vol = 1; + count dim; + for( dim = 0; dim < t->ndim; ++dim ) + vol *= delta[Lower(dim)] + delta[Upper(dim)]; + return vol; +} + +/*********************************************************************/ + +static inline real SetupEqs(Cut *cut, ccount ncuts, real f) +{ + real sqsum = 0; + Cut *c = &cut[ncuts]; + while( --c >= cut ) { + sqsum += Sq(c->lhs = f - c->f); + f = c->f; + } + return sqsum; +} + +/*********************************************************************/ + +static inline void SolveEqs(Cut *cut, count ncuts, + creal *delta, creal diff) +{ + real last = 0; + real r = 1; + Cut *c; + + for( c = cut; ; ++c ) { + ccount dim = Dim(c->i); + c->row = r -= + Div(diff, (delta[Lower(dim)] + delta[Upper(dim)])*c->df); + if( --ncuts == 0 ) break; + last += r*c->lhs; + } + + last = Div(c->lhs - last, r); + + for( ; c >= cut; last += (--c)->lhs ) { + creal delmin = -(c->delta = delta[c->i]); + creal delmax = FRACT*(delmin + c->save); + c->sol = Div(last, c->df); + if( c->sol > delmax ) c->sol = .75*delmax; + if( c->sol < delmin ) c->sol = .75*delmin; + } +} + +/*********************************************************************/ + +static count FindCuts(This *t, Cut *cut, Bounds *bounds, creal vol, + real *xmajor, creal fmajor, creal fdiff) +{ + cint sign = (fdiff < 0) ? -1 : 1; + + count ncuts = 0, icut; + real delta[2*NDIM]; + real gamma, fgamma, lhssq; + count dim, div; + + for( dim = 0; dim < t->ndim; ++dim ) { + cBounds *b = &bounds[dim]; + creal xsave = xmajor[dim]; + real dist = b->upper - xsave; + if( dist >= BNDTOL*(b->upper - b->lower) ) { + Cut *c = &cut[ncuts++]; + c->i = Upper(dim); + c->save = dist; + xmajor[dim] += dist *= FRACT; + c->f = Sample(t, xmajor); + xmajor[dim] = xsave; + } + delta[Upper(dim)] = dist; + } + + for( dim = 0; dim < t->ndim; ++dim ) { + cBounds *b = &bounds[dim]; + creal xsave = xmajor[dim]; + real dist = xsave - b->lower; + if( dist >= BNDTOL*(b->upper - b->lower) ) { + Cut *c = &cut[ncuts++]; + c->i = Lower(dim); + c->save = dist; + xmajor[dim] -= dist *= FRACT; + c->f = Sample(t, xmajor); + xmajor[dim] = xsave; + } + delta[Lower(dim)] = dist; + } + + if( ncuts == 0 ) { + SomeCut(t, cut, bounds); + return 1; + } + + for( ; ; ) { + real mindiff = INFTY; + Cut *mincut = cut; + + for( icut = 0; icut < ncuts; ++icut ) { + Cut *c = &cut[icut]; + creal diff = fabs(fmajor - c->f); + if( diff <= mindiff ) { + mindiff = diff; + mincut = c; + } + } + + gamma = Volume(t, delta)/vol; + fgamma = fmajor + (gamma - 1)*fdiff; + + if( sign*(mincut->f - fgamma) < 0 ) break; + + if( --ncuts == 0 ) { + SomeCut(t, cut, bounds); + return 1; + } + + delta[mincut->i] = mincut->save; + memcpy(mincut, mincut + 1, (char *)&cut[ncuts] - (char *)mincut); + } + + for( icut = 0; icut < ncuts; ++icut ) { + Cut *c = &cut[icut]; + c->fold = c->f; + c->df = (c->f - fmajor)/delta[c->i]; + } + + lhssq = SetupEqs(cut, ncuts, fgamma); + +repeat: + SolveEqs(cut, ncuts, delta, gamma*fdiff); + + for( div = 1; div <= 16; div *= 4 ) { + real gammanew, lhssqnew; + + for( icut = 0; icut < ncuts; ++icut ) { + Cut *c = &cut[icut]; + real *x = &xmajor[Dim(c->i)]; + creal xsave = *x; + delta[c->i] = c->delta + c->sol/div; + *x += SignedDelta(c->i); + c->f = Sample(t, xmajor); + *x = xsave; + } + + gammanew = Volume(t, delta)/vol; + fgamma = fmajor + (gammanew - 1)*fdiff; + lhssqnew = SetupEqs(cut, ncuts, fgamma); + + if( lhssqnew <= lhssq ) { + real fmax; + + if( fabs(gammanew - gamma) < GAMMATOL*gamma ) break; + gamma = gammanew; + + fmax = fabs(fgamma); + for( icut = 0; icut < ncuts; ++icut ) { + Cut *c = &cut[icut]; + creal dfmin = SINGTOL*c->df; + creal sol = c->sol/div; + real df = c->f - c->fold; + df = (fabs(sol) < BIG*fabs(df)) ? df/sol : 1; + c->df = (fabs(df) < fabs(dfmin)) ? dfmin : df; + fmax = Max(fmax, fabs(c->f)); + c->fold = c->f; + } + + if( lhssqnew < Sq((1 + fmax)*LHSTOL) ) break; + lhssq = lhssqnew; + goto repeat; + } + } + + for( icut = 0; icut < ncuts; ++icut ) { + Cut *c = &cut[icut]; + real *b = (real *)bounds + c->i; + c->save = *b; + *b = xmajor[Dim(c->i)] + SignedDelta(c->i); + } + + return ncuts; +} + +/*********************************************************************/ + +static void Split(This *t, ccount iregion) +{ + TYPEDEFREGION; + Region *region = RegionPtr(iregion); + Cut cut[2*NDIM], *c; + Errors errors[NCOMP]; + count ncuts, succ; + int depth; + real *b, tmp; + + t->selectedcomp = region->cutcomp; + t->neval_cut -= t->neval; + ncuts = FindCuts(t, cut, region->bounds, region->vol, + (real *)region->result + region->xmajor, region->fmajor, + region->fmajor - region->fminor); + t->neval_cut += t->neval; + + depth = region->depth - ncuts; + + EnlargeRegions(t, ++ncuts); + region = RegionPtr(iregion); + region->depth = -ncuts; + succ = iregion + region->next; + region->next = t->nregions - iregion; + b = (real *)region->bounds; + + region = RegionPtr(t->nregions); + VecCopy(region->bounds, b); + region->depth = IDim(depth) + 1; + region->next = 1; + region->isamples = 0; + for( c = cut; --ncuts; ++c ) { + ccount ci = c->i; + creal tmp = b[ci ^ 1]; + b[ci ^ 1] = b[ci]; + b[ci] = c->save; + region = RegionPtr(++t->nregions); + VecCopy(region->bounds, b); + region->depth = IDim(depth) + 1; + region->next = 1; + region->isamples = 0; + ++depth; + b[ci ^ 1] = tmp; + } + region->next = succ - t->nregions++; +} + diff --git a/src/divonne/common.c b/src/divonne/common.c new file mode 100644 index 0000000..8da4d00 --- /dev/null +++ b/src/divonne/common.c @@ -0,0 +1,34 @@ +/* + common.c + includes most of the modules + this file is part of Divonne + last modified 7 Nov 11 th +*/ + + +#include "Random.c" +#include "ChiSquare.c" +#include "Rule.c" +#include "Sample.c" +#include "FindMinimum.c" +#include "Split.c" +#include "Explore.c" +#include "Iterate.c" + +static inline bool BadDimension(cThis *t, ccount key) +{ + if( t->ndim > NDIM ) return true; + if( IsSobol(key) ) return + t->ndim < SOBOL_MINDIM || (t->seed == 0 && t->ndim > SOBOL_MAXDIM); + if( IsRule(key, t->ndim) ) return t->ndim < 1; + return t->ndim < KOROBOV_MINDIM || t->ndim > KOROBOV_MAXDIM; +} + +static inline bool BadComponent(cThis *t) +{ + if( t->ncomp > NCOMP ) return true; + return t->ncomp < 1; +} + +#include "Integrate.c" + diff --git a/src/divonne/decl.h b/src/divonne/decl.h new file mode 100644 index 0000000..99fac6d --- /dev/null +++ b/src/divonne/decl.h @@ -0,0 +1,127 @@ +/* + decl.h + Type declarations + this file is part of Divonne + last modified 14 Nov 11 th +*/ + + +#include "stddecl.h" + +#define Tag(x) ((x) | INT_MIN) +#define Untag(x) ((x) & INT_MAX) + +typedef struct { + real lower, upper; +} Bounds; + +typedef const Bounds cBounds; + +typedef struct { + real avg, err; +} PhaseResult; + +typedef struct { + real avg, spreadsq; + real spread, secondspread; + real nneed, maxerrsq, mindevsq; + PhaseResult phase[2]; + int iregion; +} Totals; + +typedef struct { + void *first, *last; + real errcoeff[3]; + count n; +} Rule; + +typedef const Rule cRule; + +typedef struct samples { + real *x, *f; + void (*sampler)(struct _this *t, ccount); + cRule *rule; + number n, neff; + count coeff; +} Samples; + +typedef const Samples cSamples; + +typedef struct { + real diff, err, spread; +} Errors; + +typedef const Errors cErrors; + +typedef int (*Integrand)(ccount *, creal *, ccount *, real *, void *, cint *); + +typedef void (*PeakFinder)(ccount *, cBounds *, number *, real *); + +typedef struct _this { + count ndim, ncomp; +#ifndef MLVERSION + Integrand integrand; + void *userdata; + PeakFinder peakfinder; + int ncores, *child; + int running, nchildren; + fd_set children; +#endif + real epsrel, epsabs; + int flags, seed; + number mineval, maxeval; + int key1, key2, key3; + count maxpass; + Bounds border; + real maxchisq, mindeviation; + number ngiven, nextra; + real *xgiven, *xextra, *fgiven, *fextra; + count ldxgiven; + count nregions; + number neval, neval_opt, neval_cut; + count phase; + count selectedcomp, size; + Samples samples[3]; + Totals *totals; + Rule rule7, rule9, rule11, rule13; + RNGState rng; + void *voidregion; + jmp_buf abort; +} This; + +typedef const This cThis; + +#define TYPEDEFREGION \ + typedef struct { \ + real avg, err, spread, chisq; \ + real fmin, fmax; \ + real xmin[NDIM], xmax[NDIM]; \ + } Result; \ + typedef const Result cResult; \ + typedef struct region { \ + int depth, next; \ + count isamples, cutcomp, xmajor; \ + real fmajor, fminor, vol; \ + Bounds bounds[NDIM]; \ + Result result[NCOMP]; \ + } Region + +#define RegionPtr(n) (&((Region *)t->voidregion)[n]) + +#define CHUNKSIZE 4096 + +#define AllocRegions(t) \ + MemAlloc((t)->voidregion, ((t)->size = CHUNKSIZE)*sizeof(Region)) + +#define EnlargeRegions(t, n) if( (t)->nregions + n > (t)->size ) \ + ReAlloc((t)->voidregion, ((t)->size += CHUNKSIZE)*sizeof(Region)) + +#define SAMPLERDEFS \ + TYPEDEFREGION; \ + Region *region = RegionPtr(iregion); \ + cBounds *b = region->bounds; \ + Result *r = region->result; \ + cSamples *samples = &t->samples[region->isamples]; \ + real *x = samples->x, *f = samples->f; \ + cnumber n = samples->n + |